Bedrud verwendet YAML-Konfigurationsdateien für den Hauptserver und den eingebetteten LiveKit-Medienserver.
Siehe auch: Schnellstart | Installation | Deployment-Leitfaden | Docker-Anleitung
Minimale Produktionskonfiguration
Die Standardkonfiguration funktioniert für die Entwicklung. Für den produktiven Einsatz ändern Sie diese Werte in /etc/bedrud/config.yaml:
auth:
jwtSecret: "change-to-random-string-32-chars"
sessionSecret: "change-to-another-random-string"Nach Änderungen neu starten:
sudo systemctl restart bedrud livekitVollständige Referenz unten.
Serverkonfiguration
Speicherort: server/config.yaml (Entwicklung) oder /etc/bedrud/config.yaml (Produktion)
Vollständige Referenz
server:
port: 8090 # HTTP port
host: "localhost" # Bind address
maxParticipantsLimit: 1000 # Hard ceiling for room capacity (0 = unlimited). Env: SERVER_MAX_PARTICIPANTS_LIMIT
maxRoomsPerUser: 100 # Max active rooms per user (0 = unlimited). Env: SERVER_MAX_ROOMS_PER_USER
database:
type: "sqlite" # Database type: sqlite or postgres
path: "data.db" # SQLite database file path
logger:
level: "debug" # Log level: debug, info, warn, error. Steuert App- und SQL-Abfrageprotokolle.
outputPath: "" # Log file path (empty = stdout)
livekit:
host: "http://localhost:8090/livekit" # External LiveKit URL
internalHost: "http://127.0.0.1:7880" # Internal LiveKit URL
apiKey: "devkey" # LiveKit API key (auto-generated if empty)
apiSecret: "devsecret" # LiveKit API secret
auth:
jwtSecret: "your-jwt-secret" # Secret for signing JWT tokens
tokenDuration: 24 # Token expiration in hours
sessionSecret: "your-session-secret" # Secret for session cookies
frontendURL: "http://localhost:8090" # Frontend URL (for OAuth redirects)
passkeyChallengeTTL: 5 # Gültigkeitsdauer der Passkey-Herausforderung in Minuten
# OAuth providers (optional)
google:
clientId: ""
clientSecret: ""
github:
clientId: ""
clientSecret: ""
twitter:
clientKey: ""
clientSecret: ""
cors:
allowedOrigins: "http://localhost:8090,http://localhost:3000" # Comma-separated
allowedHeaders: "Origin, Content-Type, Accept, Authorization"
allowedMethods: "GET, POST, PUT, DELETE, OPTIONS"
allowCredentials: true
rateLimit:
authMaxRequests: 10 # Max auth requests per window (login, register, refresh, passkey). 0 = disable
authWindowSecs: 60 # Auth rate limit window in seconds
guestMaxRequests: 5 # Max guest join requests per window. 0 = disable
guestWindowSecs: 60 # Guest rate limit window in seconds
chat:
maxUploadBytesPerUser: 524288000 # Per-user upload quota (500 MB). 0 = unlimited. Env: CHAT_MAX_UPLOAD_BYTES_PER_USER
globalDiskThresholdBytes: 0 # Global storage ceiling across all users. 0 = unlimited. Env: CHAT_GLOBAL_DISK_THRESHOLD_BYTES
maxMessageCount: 10000 # Max chat messages kept per room (0 = unlimited). Env: CHAT_MAX_MESSAGE_COUNT
messageTTLHours: 2160 # Purge messages older than this in hours (0 = forever). 2160 = 90 days. Env: CHAT_MESSAGE_TTL_HOURS
recording:
maxFileSizeMB: 2048 # Max recording file size in MB (0 = unlimited). Env: RECORDING_MAX_FILE_SIZE_MB
storageDir: "./data/recordings" # Local storage path for disk-backed recordings. Env: RECORDING_STORAGE_DIR
maxRecordingsPerRoom: 100 # Max total recordings per room (0 = unlimited). Env: RECORDING_MAX_PER_ROOM
queue:
pollInterval: 500 # ms between job polls. Env: QUEUE_POLL_INTERVAL
maxAttempts: 3 # retries before marking failed. Env: QUEUE_MAX_ATTEMPTS
concurrency: 1 # worker goroutines. Env: QUEUE_CONCURRENCY
email:
smtpHost: "" # SMTP server hostname. Env: EMAIL_SMTP_HOST
smtpPort: 587 # SMTP server port. Env: EMAIL_SMTP_PORT
username: "" # SMTP username. Env: EMAIL_USERNAME
password: "" # SMTP password. Env: EMAIL_PASSWORD
fromAddress: "" # From address. Env: EMAIL_FROM_ADDRESS
fromName: "Bedrud" # From display name. Env: EMAIL_FROM_NAME
tlsSkipVerify: false # Skip TLS certificate validation. Env: EMAIL_TLS_SKIP_VERIFY
smtpsMode: false # Direct TLS (SMTPS, port 465). Env: EMAIL_SMTPS_MODEWichtige Einstellungen
Datenbank
Standardmäßig verwendet Bedrud SQLite mit einer Datei unter dem konfigurierten path. Für Produktivumgebungen mit höherer Parallelität wechseln Sie zu PostgreSQL, indem Sie stattdessen einen Connection String angeben. Bei Verwendung von PostgreSQL enthält das Feld path einen Connection String, keinen Dateipfad:
database:
type: "postgres"
path: "postgres://user:password@localhost:5432/bedrud?sslmode=disable"Authentifizierung
Das jwtSecret wird zum Signieren von Access- und Refresh-Tokens verwendet. Ändern Sie diesen in der Produktion vom Standardwert.
OAuth-Anbieter sind optional. Wenn Sie diese nicht konfigurieren, werden die Social-Login-Schaltflächen nicht in der Benutzeroberfläche angezeigt. Jeder Anbieter erfordert die Registrierung einer OAuth-App beim jeweiligen Dienst sowie die Angabe der Client-ID und des Client-Secrets.
CORS
Der String allowedOrigins (kommagetrennt) muss die URL enthalten, unter der Ihr Frontend ausgeliefert wird. In der Entwicklung ist dies http://localhost:3000. In der Produktion setzen Sie ihn auf Ihre Domain (z. B. https://meet.example.com).
Ratenbegrenzung
Die Ratenbegrenzung schützt Authentifizierungsendpunkte vor Brute-Force- und DoS-Angriffen. Zwei Kategorien:
- Auth-Endpunkte (Login, Registrierung, Refresh, Passkey-Login/-Signup) — Standard: 10 Anfragen pro 60 Sekunden pro IP
- Gastbeitritt — Standard: 5 Anfragen pro 60 Sekunden pro IP
Lassen Sie den Abschnitt rateLimit weg, um die Standardwerte zu verwenden. Setzen Sie authMaxRequests: 0 oder guestMaxRequests: 0 zum Deaktivieren.
Chat History
Bedrud applies advisory retention limits to in-room chat messages. Since LiveKit — the real-time media layer — does not persist data channel messages server-side, these limits are enforced on the client:
maxMessageCount— caps the number of chat messages held in memory and sessionStorage per room. When exceeded, the oldest messages are trimmed. Default: 10000. Set to0for unlimited.messageTTLHours— messages older than this threshold are purged from the local cache. Default: 2160 (90 days). Set to0to keep messages indefinitely.
Chat messages in Bedrud are transmitted exclusively through LiveKit data channels and are not stored on the server. The retention limits above control how many messages the frontend keeps in memory and sessionStorage. A dedicated chat history service (with server-side persistence) would be needed for true history across sessions — this is tracked as a future enhancement.
Recordings
Room recording is controlled by the RecordingsEnabled system setting (toggle in admin Settings → General). When enabled:
- Moderators can start/stop composite MP4 recordings from the meeting controls bar
- Recordings are stored alongside chat uploads using the configured storage backend (disk/S3)
- Each room has a per-room
recordingsAllowedtoggle that must also be enabled - Failed/pending recordings over 7 days old are automatically cleaned up daily
- Non-persistent rooms have a configurable per-room recording cap (
maxRecordingsPerRoom) to prevent abuse - After a room is deleted, the recording creator can still access their recordings from the same room URL
YAML Reference:
maxFileSizeMB— maximum file size for a single recording in MB. 0 = unlimited. Default: 2048. Env:RECORDING_MAX_FILE_SIZE_MBstorageDir— directory for disk-backed recordings. Only used when S3 is not configured. Default:./data/recordings. Env:RECORDING_STORAGE_DIRmaxRecordingsPerRoom— caps total recordings per room (all statuses: completed, failed, etc.). 0 = unlimited. Only enforced for non-persistent rooms. Default: 100. Env:RECORDING_MAX_PER_ROOM
See the Recordings Guide for full details.
Warteschlange (Job-System)
Die interne Job-Warteschlange verarbeitet asynchrone Hintergrundaufgaben wie die Benutzer-/Raumlöschung, Aussetzung und Chat-Uploads.
pollInterval— wie oft der Worker nach neuen Jobs sucht (in ms). Niedrigere Werte reduzieren die Latenz auf Kosten häufigerer Datenbankabfragen.maxAttempts— maximale Wiederholungsversuche, bevor ein Job als fehlgeschlagen markiert wird. Wiederholungen verwenden exponentielle Backoff (2^attempt * 5s, gedeckelt bei 1h).concurrency— Anzahl der Worker-Goroutinen. Erhöhen für höheren Durchsatz mit PostgreSQL. SQLite ist auf einen einzelnen Worker beschränkt (eine Verbindung).
E-Mail-Benachrichtigungen
Bedrud kann transaktionale E-Mails (Willkommen, Passwort-Reset, Raumeinladung) über SMTP senden.
smtpHost/smtpPort— SMTP-Serveradresse. Port 587 (STARTTLS) ist die Voreinstellung.username/password— SMTP-Authentifizierungsdaten.fromAddress/fromName— Absenderidentität für ausgehende E-Mails.tlsSkipVerify— TLS-Zertifikatsprüfung überspringen (für selbstsignierte Zertifikate).smtpsMode— Direktes TLS (SMTPS, Port 465).
LiveKit-Konfiguration
Speicherort: server/config/livekit.yaml (Entwicklung) oder /etc/bedrud/livekit.yaml (Produktion)
port: 7880 # LiveKit HTTP/WebSocket port
rtc:
port_range_start: 50000 # UDP port range start
port_range_end: 60000 # UDP port range end
use_external_ip: true # Use external IP for RTC
turn:
enabled: true
domain: "localhost"
tls_port: 5349
udp_port: 3478
keys:
devkey: "devsecret" # Must match server config
logging:
level: info
room:
auto_create: true # Auto-create rooms when participants join
empty_timeout: 60 # Seconds before deleting empty room
departure_timeout: 60 # Seconds to keep room after all participants leave
max_participants: 20 # Max participants per room (0 = unlimited)
enable_remote_unmute: true # Allow server-side unmute of participantsDie keys in livekit.yaml müssen mit livekit.apiKey und livekit.apiSecret in der Server-Datei config.yaml übereinstimmen.
RTC-Portbereich
LiveKit verwendet UDP-Ports für Medienströme. Der Standardbereich 50000-60000 funktioniert für die meisten Setups. Wenn Sie hinter einer Firewall arbeiten, stellen Sie sicher, dass diese Ports geöffnet sind.
Siehe WebRTC-Konnektivität für Architektur und Fehlerbehebung.
TURN-Server
Der eingebettete TURN-Server leitet Medien für Clients hinter restriktiven NATs oder Unternehmensfirewalls weiter. Er ist standardmäßig auf den Ports 3478 (UDP) und 5349 (TLS) aktiviert.
TURN ist ein Rückfalloptions-Relay - die meisten Clients (~80%) verbinden sich direkt über UDP und nutzen es nie. Wenn TURN aktiv wird, trägt der Server die gesamte Bandbreite der weitergeleiteten Medien.
TLS-Voraussetzung: TURN/TLS (Port 5349) benötigt ein gültiges TLS-Zertifikat. Für den produktiven Einsatz setzen Sie turn.tls_port: 443 und verweisen Sie cert_file/key_file auf Ihr Zertifikat, oder platzieren Sie einen Layer-4-Load-Balancer davor mit external_tls: true.
Siehe den TURN-Server-Leitfaden für Architektur, Konfigurationsdetails, Bandbreitenberechnungen und Fehlerbehebung.
Webhook (Verbindungserkennung)
Bedrud receives webhook events from LiveKit to detect when participants disconnect unexpectedly (e.g., browser crash, network drop) and mark them as inactive in the database.
Endpoint: POST /api/livekit/webhook
Authentication: Uses LiveKit JWT signing with the same apiKey/apiSecret. No separate secret needed.
Embedded LiveKit: When Bedrud manages its own LiveKit server (default), the webhook URL is auto-configured in the generated LiveKit YAML. No user action needed.
External LiveKit (Cloud or self-hosted with external: true): Manually configure the webhook URL in your LiveKit dashboard:
https://<your-domain>/api/livekit/webhook
Events handled:
| Event | Action |
|---|---|
participant_disconnected | Marks participant as inactive in room_participants |
room_finished | Marks all participants + room as inactive |
If apiKey is left empty in config, a random keypair is generated at startup. The embedded LiveKit server and webhook handler both use the same generated key — no manual configuration needed.
Raumeinstellungen
Der Abschnitt room: steuert das Verhalten von Meetingräumen:
auto_create- Räume automatisch erstellen, wenn Teilnehmer beitreten (Standard:true)empty_timeout- Sekunden bis zum Löschen eines Raums, dem nie beigetreten wurde (Standard:60)departure_timeout- Sekunden, die ein Raum nach dem Verlassen aller Teilnehmer aktiv bleibt (Standard:60)max_participants- Maximale Teilnehmer pro Raum. Auf0für kein Limit setzen (Standard:20)enable_remote_unmute- Serverseitiges Stummschalten/Aufheben der Stummschaltung von Teilnehmern erlauben (Standard:true)
Kapazitätsoptimierung:
- Kleine Team-Meetings:
max_participants: 10-20 - Große Webinare:
max_participants: 100(oder0für unbegrenzt) - Ressourcenbeschränkte Server:
max_participantssenken, um CPU-/Speicherverbrauch zu reduzieren
Umgebungsvariablen
Konfigurationswerte können durch Umgebungsvariablen überschrieben werden. Die Benennung folgt einer abschnittsspezifischen Präfix-Konvention:
Für Docker-Deployments siehe die Docker-Anleitung.
export SERVER_PORT=8090
export DB_PATH=/var/lib/bedrud/bedrud.db
export JWT_SECRET=production-secret
export LIVEKIT_HOST=http://localhost:8090/livekit
export LIVEKIT_API_KEY=prodkey
export LIVEKIT_API_SECRET=prodsecretVollständige Umgebungsvariablen-Referenz
| Umgebungsvariable | YAML-Pfad | Beschreibung |
|---|---|---|
SERVER_PORT | server.port | HTTP-Listening-Port |
SERVER_ENABLE_TLS | server.enableTLS | HTTPS aktivieren (true/false) |
SERVER_CERT_FILE | server.certFile | Pfad zum TLS-Zertifikat |
SERVER_KEY_FILE | server.keyFile | Pfad zum privaten TLS-Schlüssel |
SERVER_DOMAIN | server.domain | Domainname |
SERVER_EMAIL | server.email | E-Mail für Let’s Encrypt |
SERVER_USE_ACME | server.useACME | Automatisches Let’s Encrypt aktivieren (true/false) |
SERVER_TRUSTED_PROXIES | server.trustedProxies | Kommagetrennte vertrauenswürdige Proxy-IPs |
SERVER_PROXY_HEADER | server.proxyHeader | Header zum Auslesen der Client-IP (z. B. X-Forwarded-For) |
DB_HOST | database.host | Datenbank-Host (PostgreSQL) |
DB_PORT | database.port | Datenbank-Port |
DB_USER | database.user | Datenbank-Benutzer |
DB_PASSWORD | database.password | Datenbank-Passwort |
DB_NAME | database.dbname | Datenbankname |
DB_TYPE | database.type | sqlite oder postgres |
DB_PATH | database.path | SQLite-Dateipfad oder PostgreSQL-Connection-String |
LIVEKIT_HOST | livekit.host | Externe LiveKit-URL |
LIVEKIT_INTERNAL_HOST | livekit.internalHost | Interne LiveKit-URL |
LIVEKIT_API_KEY | livekit.apiKey | LiveKit API-Schlüssel (auto-generated as gen-<32hex> if empty) |
LIVEKIT_API_SECRET | livekit.apiSecret | LiveKit API-Secret (64-char hex auto-generated if empty) |
JWT_SECRET | auth.jwtSecret | Secret zum Signieren von JWT-Tokens |
AUTH_FRONTEND_URL | auth.frontendURL | Frontend-URL für OAuth-Weiterleitungen |
AUTH_PASSKEY_CHALLENGE_TTL | auth.passkeyChallengeTTL | Gültigkeitsdauer der Passkey-Herausforderung in Minuten |
CORS_ALLOWED_ORIGINS | cors.allowedOrigins | Kommagetrennte erlaubte Origins |
CORS_ALLOWED_HEADERS | cors.allowedHeaders | Erlaubte Request-Header |
CORS_ALLOWED_METHODS | cors.allowedMethods | Erlaubte HTTP-Methoden |
CORS_ALLOW_CREDENTIALS | cors.allowCredentials | Credentials erlauben (true/false) |
CORS_EXPOSE_HEADERS | cors.exposeHeaders | Header, die dem Browser offengelegt werden |
CORS_MAX_AGE | cors.maxAge | Preflight-Cache-Dauer in Sekunden |
RATELIMIT_AUTH_MAX | rateLimit.authMaxRequests | Maximale Auth-Anfragen pro Zeitfenster |
RATELIMIT_AUTH_WINDOW | rateLimit.authWindowSecs | Auth-Ratenlimit-Zeitfenster in Sekunden |
RATELIMIT_GUEST_MAX | rateLimit.guestMaxRequests | Maximale Gastbeitritts-Anfragen pro Zeitfenster |
RATELIMIT_GUEST_WINDOW | rateLimit.guestWindowSecs | Gast-Ratenlimit-Zeitfenster in Sekunden |
LIVEKIT_CONFIG_PATH | livekit.configPath | Path to external LiveKit YAML config |
LIVEKIT_NODE_IP | livekit.nodeIP | Explicit node IP for embedded LiveKit RTC (disables STUN) |
SERVER_CERT_ALGORITHM | server.certAlgorithm | Key algorithm for cert generation: ed25519, ecdsa256, rsa2048, rsa4096 |
SERVER_MAX_PARTICIPANTS_LIMIT | server.maxParticipantsLimit | Hard ceiling for room capacity (default 1000) |
SERVER_MAX_ROOMS_PER_USER | server.maxRoomsPerUser | Max active rooms per user (default 100, 0 = unlimited) |
CHAT_MAX_UPLOAD_BYTES_PER_USER | chat.maxUploadBytesPerUser | Per-user upload quota in bytes (default 524288000, 0 = unlimited) |
CHAT_GLOBAL_DISK_THRESHOLD_BYTES | chat.globalDiskThresholdBytes | Global upload storage ceiling in bytes (default 0 = unlimited) |
CHAT_MAX_MESSAGE_COUNT | chat.maxMessageCount | Max chat messages kept per room (default 10000, 0 = unlimited) |
CHAT_MESSAGE_TTL_HOURS | chat.messageTTLHours | Max age of chat messages in hours (default 2160 = 90 days, 0 = forever) |
QUEUE_POLL_INTERVAL | queue.pollInterval | Job poll interval in ms (default 500) |
QUEUE_MAX_ATTEMPTS | queue.maxAttempts | Max job retries before marking failed (default 3) |
QUEUE_CONCURRENCY | queue.concurrency | Worker goroutine count (default 1) |
EMAIL_SMTP_HOST | email.smtpHost | SMTP server hostname |
EMAIL_SMTP_PORT | email.smtpPort | SMTP server port (default 587) |
EMAIL_USERNAME | email.username | SMTP username |
EMAIL_PASSWORD | email.password | SMTP password |
EMAIL_FROM_ADDRESS | email.fromAddress | From email address |
EMAIL_FROM_NAME | email.fromName | From display name (default “Bedrud”) |
EMAIL_TLS_SKIP_VERIFY | email.tlsSkipVerify | Skip TLS certificate validation for self-signed SMTP certs |
EMAIL_SMTPS_MODE | email.smtpsMode | Enable direct TLS (SMTPS) mode for port 465 |
Produktions-Checkliste
-
jwtSecretundsessionSecretauf starke zufällige Werte ändern -
logger.levelaufinfooderwarnsetzen - TLS konfigurieren (über Installationsprogramm oder Reverse Proxy)
-
cors.allowedOriginsauf Ihre Produktionsdomain setzen - OAuth-Anbieter bei Bedarf konfigurieren
- LiveKit RTC-Portbereich in der Firewall öffnen
- Protokollrotation für
/var/log/bedrud/einrichten
Für das vollständige Produktionssetup siehe den Deployment-Leitfaden.