feat(federation): escape LIKE special characters in originDomain to prevent wildcard injection feat(oauth): redirect with token in hash fragment to avoid exposure in logs feat(OAuthCallback): retrieve token from hash fragment for improved security
🔴 Redlight
A modern, self-hosted BigBlueButton frontend with beautiful themes, federation, and powerful features.
✨ Features
Core Features
- 🎥 Video Conferencing - Integrated BigBlueButton support for professional video meetings
- 🎨 15+ Themes - Dracula, Nord, Catppuccin, Rosé Pine, Gruvbox, and more
- 📝 Room Management - Create unlimited rooms with custom settings, access codes, and moderator codes
- 🔐 User Management - Registration, login, role-based access control (Admin/User)
- 📹 Recording Management - View, publish, and delete meeting recordings per room
- 🌍 Multi-Language Support - German (Deutsch) and English built-in, easily extensible
- ✉️ Email Verification - Optional SMTP-based email verification for user registration
- 👤 User Profiles - Customizable avatars, themes, and language preferences
- 📱 Responsive Design - Works seamlessly on mobile, tablet, and desktop
- 🌐 Federation - Invite users from remote Redlight instances via Ed25519-signed messages
- 🐉 DragonflyDB / Redis - JWT blacklisting for secure token revocation on logout
Admin Features
- 👥 User Administration - Manage users and roles
- 🏢 Branding Customization - Custom app name, logos, and default theme
- 📊 Dashboard - Overview of system statistics
- 🔧 Settings Management - System-wide configuration
Room Features
- 🔑 Access Codes - Restrict room access with optional passwords
- 🔐 Moderator Codes - Separate code to grant moderator privileges
- 🚪 Guest Access - Allow unauthenticated users to join meetings (rate-limited)
- ⏱️ Max Participants - Set limits on concurrent participants
- 🎤 Mute on Join - Automatically mute new participants
- ✅ Approval Mode - Require moderator approval for participants
- 🎙️ Anyone Can Start - Allow participants to start the meeting
- 📹 Recording Settings - Control whether meetings are recorded
- 📊 Presentation Upload - Upload PDF, PPTX, ODP, or image files as default slides
- 🤝 Room Sharing - Share rooms with other registered users
Security
- 🛡️ Comprehensive Rate Limiting - Login, register, profile, avatar, guest-join, and federation endpoints
- 🔒 Input Validation - Email format, field length limits, ID format checks, color format validation
- 🕐 Timing-Safe Comparisons - Access codes and moderator codes compared with
crypto.timingSafeEqual - 📏 Streaming Upload Limits - Avatar (5 MB) and presentation (50 MB) uploads reject early without buffering
- 🧹 XSS Prevention - HTML-escaped emails, XML-escaped BBB parameters, SVG sanitization
- 🔐 JWT Blacklist - Token revocation via DragonflyDB/Redis on logout
- 🌐 CORS Restriction - Locked to
APP_URLin production - ⚙️ Configurable Trust Proxy -
TRUST_PROXYenv var for reverse proxy setups
Developer Features
- 🐳 Docker Support - Easy deployment with Docker Compose (includes PostgreSQL + DragonflyDB)
- 🗄️ Database Flexibility - SQLite (default) or PostgreSQL support
- 🔌 REST API - Comprehensive API for custom integrations
- 📦 Open Source - Full source code transparency
- 🛠️ Self-Hosted - Complete data privacy and control
📊 Comparison: Redlight vs Greenlight
| Feature | Redlight | Greenlight |
|---|---|---|
| Theme System | 15+ customizable themes | Limited theming |
| Federation | ✅ Cross-instance invites | ❌ Not supported |
| Language Support | Multi-language ready | Multi-language ready |
| UI Framework | React + Tailwind (Modern) | Rails-based (Traditional) |
| User Preferences | Theme, language, avatar | Limited customization |
| Database Options | SQLite / PostgreSQL | PostgreSQL only |
| Docker | ✅ Supported | ✅ Supported |
| Admin Dashboard | Modern React UI | Legacy Rails interface |
| Room Sharing | ✅ Share rooms with users | ✅ Supported |
| Recording Management | Full control per room | Standard management |
| API | RESTful JSON API | RESTful API |
| Setup Complexity | Simple (5 min) | Moderate (10-15 min) |
| Customization | Easy (Tailwind CSS) | Requires Ruby/Rails |
| Community | doesn't exist lol | Established |
🚀 Quick Start
Prerequisites
- Docker & Docker Compose
- BigBlueButton server (with API access)
- SMTP server (optional, for email verification)
Installation
-
Clone the repository
git clone https://git.scrunkly.cat/Michelle/redlight cd redlight -
Configure environment
cp .env.example .envEdit
.envwith your settings:BBB_URL=https://your-bbb-server.com/bigbluebutton/api/ BBB_SECRET=your-bbb-shared-secret JWT_SECRET=your-secret-key # REQUIRED - app won't start without this APP_URL=https://your-domain.com # Used for CORS and email links DATABASE_URL=postgres://user:password@postgres:5432/redlight POSTGRES_USER=redlight POSTGRES_PASSWORD=redlight POSTGRES_DB=redlight # DragonflyDB / Redis (JWT blacklist for logout) REDIS_URL=redis://dragonfly:6379 # Reverse proxy trust (default: loopback) # TRUST_PROXY=loopback # Optional: Email verification SMTP_HOST=smtp.gmail.com SMTP_PORT=587 SMTP_USER=your-email@gmail.com SMTP_PASS=your-app-password # Optional: Federation (cross-instance room invites) # FEDERATION_DOMAIN=your-domain.com -
Start the application
docker-compose up -d -
Access the application
- Open
http://localhost:3001in your browser - Default admin:
admin@example.com/admin123 - Change password immediately!
- Open
🛠️ Development
Local Setup
-
Install dependencies
npm install -
Start development server
npm run dev- Frontend: http://localhost:5173
- Backend: http://localhost:3001
-
Build for production
npm run build npm run preview
Tech Stack
- Frontend: React 18, Tailwind CSS, React Router, Lucide Icons
- Backend: Node.js 20, Express, JWT, Bcrypt
- Database: SQLite / PostgreSQL with better-sqlite3 / pg
- Cache: DragonflyDB / Redis (ioredis) - JWT blacklisting
- Email: Nodemailer
- Build: Vite
📁 Project Structure
redlight/
├── server/ # Node.js/Express backend
│ ├── config/ # Database, Redis, mailer, BBB & federation config
│ ├── middleware/ # JWT authentication & token blacklisting
│ ├── routes/ # API endpoints (auth, rooms, recordings, admin, branding, federation)
│ └── index.js # Server entry point
├── src/ # React frontend
│ ├── components/ # Reusable components
│ ├── contexts/ # React context (Auth, Language, Theme, Branding)
│ ├── i18n/ # Translations (DE, EN)
│ ├── pages/ # Page components
│ ├── services/ # API client
│ ├── themes/ # Tailwind theme config
│ └── main.jsx # Frontend entry point
├── public/ # Static assets
├── uploads/ # User avatars, branding & presentations (runtime)
├── compose.yml # Docker Compose (Redlight + PostgreSQL + DragonflyDB)
├── Dockerfile # Multi-stage container image
└── package.json # Dependencies
🔐 Security
- JWT Authentication - Secure token-based auth with 7-day expiration and
jti-based blacklisting via DragonflyDB/Redis - Mandatory JWT Secret - Server refuses to start without a
JWT_SECRETenv var - HTTPS Ready - Configure behind reverse proxy (nginx, Caddy); trust proxy via
TRUST_PROXYenv - Password Hashing - bcryptjs with salt rounds 12, minimum 8-character passwords
- Email Verification - Optional SMTP-based email verification with resend support
- CORS Protection - Restricted to
APP_URLin production, open in development - Rate Limiting - Login, register, profile, password, avatar, guest-join, and federation endpoints
- Input Validation - Email regex, field length limits, ID format checks, hex-color format checks
- Timing-Safe Comparisons - Access codes and moderator codes compared via
crypto.timingSafeEqual - Upload Safety - Streaming body size limits (avatar 5 MB, presentation 50 MB) abort early without buffering
- XSS / Injection Prevention - HTML-escaped emails, XML-escaped BBB API parameters, SVG logos served as
attachment - Admin Isolation - Role-based access control with strict admin checks
📦 API Endpoints
Authentication
POST /api/auth/register- Register new userPOST /api/auth/login- Login userPOST /api/auth/logout- Logout (blacklists JWT)GET /api/auth/verify-email?token=...- Verify email with tokenPOST /api/auth/resend-verification- Resend verification emailGET /api/auth/me- Get current user infoPUT /api/auth/profile- Update profile (theme, language, display name)PUT /api/auth/password- Change passwordPOST /api/auth/avatar- Upload avatar imageDELETE /api/auth/avatar- Remove avatar image
Rooms
GET /api/rooms- List user's rooms (owned + shared)POST /api/rooms- Create new roomGET /api/rooms/:uid- Get room detailsPUT /api/rooms/:uid- Update roomDELETE /api/rooms/:uid- Delete roomPOST /api/rooms/:uid/start- Start meetingPOST /api/rooms/:uid/join- Join meeting as authenticated userPOST /api/rooms/:uid/guest-join- Join meeting as guest (rate-limited)POST /api/rooms/:uid/end- End meetingGET /api/rooms/:uid/running- Check if meeting is runningGET /api/rooms/:uid/shares- List shared usersPOST /api/rooms/:uid/shares- Share room with userDELETE /api/rooms/:uid/shares/:userId- Remove sharePOST /api/rooms/:uid/presentation- Upload default presentation (PDF, PPTX, ODP, images)DELETE /api/rooms/:uid/presentation- Remove presentation
Recordings
GET /api/recordings/:roomUid- List room recordingsPUT /api/recordings/:recordingId- Publish/unpublish recordingDELETE /api/recordings/:recordingId- Delete recording
Admin
GET /api/admin/users- List all usersGET /api/admin/stats- System statisticsPOST /api/admin/users- Create user (admin)PUT /api/admin/users/:id- Update userDELETE /api/admin/users/:id- Delete user
Branding
GET /api/branding- Get branding settingsPUT /api/branding- Update branding (admin only)POST /api/branding/logo- Upload custom logoDELETE /api/branding/logo- Remove custom logo
Federation
GET /.well-known/redlight- Instance discovery (domain, public key)POST /api/federation/invite- Send invitation to remote userPOST /api/federation/receive- Receive invitation from remote instance (rate-limited)GET /api/federation/invitations- List received invitationsPUT /api/federation/invitations/:id- Accept / decline invitationDELETE /api/federation/invitations/:id- Delete invitation
🌍 Internationalization (i18n)
Redlight comes with built-in support for multiple languages. Currently supported:
- 🇩🇪 Deutsch (German)
- 🇬🇧 English
Adding a new language
- Create
src/i18n/xx.json(e.g.,fr.jsonfor French) - Copy structure from
de.jsonoren.json - Translate all strings
- Update
src/i18n/index.jsto include the new language
🎨 Themes
Redlight includes the following themes:
- 🌙 Dracula
- ❄️ Nord
- 🐱 Catppuccin
- 🌹 Rosé Pine
- 🍂 Gruvbox (Dark, Light)
- 💜 One Dark
- 🌊 Tokyo Night
- And more...
Themes are fully customizable by editing src/themes/index.js.
🐳 Docker Deployment
Using Docker Compose (Recommended)
docker-compose up -d
Services:
- redlight - Node.js application
- postgres - PostgreSQL database
- dragonfly - DragonflyDB (Redis-compatible) for JWT blacklisting
Environment Variables
| Variable | Required | Default | Description |
|---|---|---|---|
BBB_URL |
Yes | - | BigBlueButton API URL |
BBB_SECRET |
Yes | - | BigBlueButton shared secret |
JWT_SECRET |
Yes | - | Secret for signing JWTs (server won't start without it) |
APP_URL |
Recommended | - | Public URL of the app (used for CORS + email links) |
DATABASE_URL |
No | SQLite | PostgreSQL connection string |
REDIS_URL |
No | redis://localhost:6379 |
DragonflyDB / Redis URL |
TRUST_PROXY |
No | loopback |
Express trust proxy setting (number or string) |
SMTP_HOST |
No | - | SMTP server for email verification |
SMTP_PORT |
No | 587 |
SMTP port |
SMTP_USER |
No | - | SMTP username |
SMTP_PASS |
No | - | SMTP password |
FEDERATION_DOMAIN |
No | - | Domain for federation (enables cross-instance invites) |
Production Deployment
Behind a reverse proxy (nginx example):
upstream redlight {
server localhost:3001;
}
server {
listen 443 ssl http2;
server_name your-domain.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
client_max_body_size 5M;
location / {
proxy_pass http://redlight;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Note: When running behind a reverse proxy, set
TRUST_PROXY=1(or the appropriate value) in.envso Express reads the correct client IP for rate limiting.
🌐 Federation
Federation allows users on different Redlight instances to invite each other into rooms.
Setup
- Set
FEDERATION_DOMAIN=your-domain.comin.env. - On first start, an Ed25519 key pair is generated automatically and stored in
server/config/federation_key.pem. - Other instances discover your public key via
GET /.well-known/redlight.
How it works
- User A on
instance-a.comsends an invite touserB@instance-b.com. - Redlight looks up
instance-b.com/.well-known/redlightto discover the federation API. - The invite payload is signed with instance A's private key and POSTed to instance B's
/api/federation/receive. - Instance B verifies the Ed25519 signature against instance A's public key.
- User B sees the invitation and can accept or decline. Accepting provides a join link to the remote room.
🐛 Troubleshooting
Issue: "ERR_ERL_PERMISSIVE_TRUST_PROXY"
Solution: Set TRUST_PROXY in .env. Use loopback (default) or 1 when behind a single reverse proxy.
Issue: "JWT_SECRET is not set"
Solution: The server requires a JWT_SECRET environment variable and will refuse to start without one. Add it to your .env file.
Issue: "Email verification not working"
Solution: Ensure SMTP is configured in .env. If SMTP_HOST is not set, email verification is disabled.
Issue: "BigBlueButton API error"
Solution: Verify BBB_URL and BBB_SECRET are correct. Test the connection with:
curl "https://your-bbb-server/bigbluebutton/api/getMeetings?checksum=..."
Issue: "Database connection failed"
Solution: Check DATABASE_URL format. For PostgreSQL: postgres://user:password@host:5432/redlight
Issue: "Theme not applying"
Solution: Clear browser cache (Ctrl+Shift+Del) or restart dev server with npm run dev.
Issue: "DragonflyDB connection error"
Solution: Ensure DragonflyDB (or Redis) is running and REDIS_URL is correct. If unavailable, the app still works — JWT blacklisting degrades gracefully (logout won't revoke tokens immediately).
📝 License
This project is licensed under the MIT License - see LICENSE file for details.
🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit changes (
git commit -m 'Add amazing feature') - Push to branch (
git push origin feature/amazing-feature) - Open a Pull Request