Bedrud 文档

Bedrud 使用 LiveKit 处理实时视频和音频通信。LiveKit 提供 SFU(选择性转发单元)媒体服务器,Bedrud 负责认证、房间管理和管控功能。

内嵌模式 vs 外部模式

Bedrud 支持两种 LiveKit 部署模式:

  1. 内嵌模式(默认): 后端在内部启动并管理 LiveKit 服务器进程。无需额外基础设施—后端处理 LiveKit 进程的完整生命周期。
  2. 外部模式: Bedrud 连接到独立的 LiveKit 服务器或集群。适用于水平扩缩容或使用托管的 LiveKit Cloud 实例。

配置外部模式

要使用外部 LiveKit 服务器,请在 config.yaml 中设置以下配置项:

livekit:
  host: "wss://livekit.example.com:7880"    # Client WebSocket URL (ws:// or wss://)
  internalHost: "https://livekit.example.com:7880"  # Server-to-server API URL
  apiKey: "your-api-key"
  apiSecret: "your-api-secret"
  external: true          # Skip embedded LiveKit startup
  skipTLSVerify: false    # Set true if LiveKit uses self-signed certs

embeddedfalse 时,Bedrud 将跳过启动内嵌的 LiveKit 二进制文件。API 密钥和密钥必须与外部服务器的凭据匹配。

有关 LiveKit 集群的设置和配置,请参阅 LiveKit 文档

Webhook 配置(仅限外部模式)

使用外部 LiveKit 服务器时,必须配置 webhook,以便 LiveKit 通知 Bedrud 参与者断开连接和房间关闭事件。没有 webhook,数据库状态将变得过时。

端点: https://<your-domain>/api/livekit/webhook

身份验证: 使用 LiveKit 的 JWT 签名——即上面配置的同一个 apiKey/apiSecret。无需单独的密钥。

LiveKit Cloud: 设置 → Webhooks → 创建新的 webhook。输入端点 URL 并选择您的 API 密钥。

自托管 LiveKit: 添加到您的 LiveKit YAML 配置(例如 livekit.yaml):

webhook:
  urls: ["https://bedrud.example.com/api/livekit/webhook"]
  api_key: "your-api-key"

如果没有正确配置 webhook,participant_disconnectedroom_finished 事件将无法传递给 Bedrud。管理面板可能会显示过时的参与者数据,房间也不会自动清理。

LiveKit 版本兼容性

Bedrud 的内嵌 LiveKit 模式会自动生成兼容的配置。但是,如果您自托管外部 LiveKit 服务器,请注意 LiveKit 各版本之间的破坏性变更:

  • LiveKit v1.12+ 已从其配置中移除了顶层 tls 字段。如果您在 LiveKit YAML 中使用了 tls:,请删除它。在 Bedrud 配置中为 internalHost 配置 http://,为 host 配置 ws://。TURN TLS 在 turn: 部分仍然受支持。
  • LiveKit v1.11 及更早版本 在顶层支持 tls:。请为 internalHost 使用 https://,为 host 使用 wss://

如有疑问,请使用 livekit-server --version 检查您的 LiveKit 服务器版本,并查阅 LiveKit 发布说明

嵌入式配置生成 (Embedded Config Generation)

当在嵌入式模式下启用 TLS 时,Bedrud 会生成一个临时的 LiveKit YAML 配置文件(/tmp/bedrud-livekit-*.yaml):

  • 启用 TURN,domainserver.host 自动设置,udp_port: 3478tls_port: 5349,服务器 TLS 证书被重复用于 TURN/TLS
  • node_ip 通过 livekit.nodeIPserver.host → 出站 IP 自动检测的优先级解析
  • bind_addresses 被省略(LiveKit 默认绑定所有接口)

临时文件在 LiveKit 进程退出时被清理。要使用静态配置绕过自动生成,请设置 livekit.configPathLIVEKIT_CONFIG_PATH

工作原理

1. 房间创建

当用户在 Bedrud 中创建房间时,服务器不会立即创建 LiveKit 房间。LiveKit 房间在第一个参与者加入时按需创建。

2. 加入令牌

当用户加入会议时:

  1. 前端向 /api/room/join 发送请求。

  2. 后端验证用户是否有权加入该房间。

  3. 后端使用其 API Key 和 Secret 生成签名的 JWT(加入令牌)。

  4. 令牌包含:

    • 房间名称。
    • 用户的身份标识(显示名称)。
    • 权限—例如用户是否可以发布音频或共享屏幕。
  5. 前端接收此令牌并直接连接到 LiveKit 媒体端口(默认 7880)。

3. 房间控制(管理员)

后端使用 LiveKit Go SDK 执行管理操作:

  • 踢出: 断开参与者的连接。
  • 静音: 强制静音参与者的麦克风。
  • 权限: 实时更改参与者的可操作权限。

网络架构

  • API 端口(8090/443): 处理 HTTP 请求和用于通话建立的 WebSocket 信令。
  • 媒体端口(7880): 使用 WebRTC 协议处理视频和音频数据。当 UDP 被阻止时,ICE/TCP 回退使用端口 7881。
  • TURN 端口(3478 UDP / 5349 TLS): 为受限 NAT 或防火墙后的客户端中继媒体。参见 TURN 服务器指南

有关防火墙和端口要求,请参阅 WebRTC 连接

Troubleshooting

Startup & Config Crashes

SymptomCauseFix
Container crash-loops, logs could not resolve external IPuse_external_ip: true without explicit node_ip in DockerSet node_ip: <lan-ip> under rtc: and use_external_ip: false
LiveKit exits with TURN domain required on v1.12+turn.tls_port is set but no domain or TLS cert/keyAdd domain: under turn:, provide cert_file/key_file, or remove tls_port for UDP-only TURN
field tls not found on startupLiveKit v1.12+ removed top-level tls: config fieldRemove tls: block from LiveKit YAML; use http:// / ws:// in Bedrud config
LIVEKIT_CONFIG env var not picked upEntrypoint doesn’t parse env var (pre-v1.7 or custom entrypoint)LiveKit reads LIVEKIT_CONFIG natively since v1.7 — verify version; pass via --config-body only if needed
Docker: --config-body via sh -c fails with flag provided but not defined: -cImage entrypoint is /livekit-server directly — command gets appended, not wrapped by shellDon’t use a shell wrapper, LIVEKIT_CONFIG env var is supported natively by the binary
Docker Compose: $LIVEKIT_CONFIG expands to empty stringCompose substitutes $VAR from host environment, not containerUse $$LIVEKIT_CONFIG to escape docker-compose variable substitution
YAML parsing error from LIVEKIT_CONFIGIncorrect YAML indentation or syntaxValidate: docker run --rm -e LIVEKIT_CONFIG livekit-server --config-body "$LIVEKIT_CONFIG"

Connectivity

SymptomCauseFix
Admin dashboard shows “LiveKit disconnected”Bedrud can’t reach LiveKit HTTP APIVerify internalHost in config; run curl http://<internalHost>/ from Bedrud host; check firewall
Token generated but client connection times outLiveKit WebSocket unreachable from browserCheck host in livekit: config (must be reachable by clients); verify DNS/firewall; test with wscat
Embedded LiveKit not startingMissing binary or permissionEnsure internal/livekit/bin/livekit-server exists (even empty file for build); check Bedrud server logs
Port 7880 already in useAnother process on same portChange livekit.port or use different Docker port mapping
Redis connection fails in LiveKit logsRedis unreachable or wrong addressVerify redis.address: in LiveKit YAML; check container network connectivity
curl http://127.0.0.1:7880 returns connection refusedLiveKit crashed during startupCheck docker logs / journalctl; look for RTC/TURN validation errors near the bottom of the log
Token expired before client connectedShort JWT validity windowRequest a fresh token via POST /api/room/join before each connection attempt

Media & TURN

SymptomCauseFix
Participants join but no audio/videoUDP port range blocked or wrong node_ipOpen UDP 50000-60000; verify node_ip is the externally reachable address
Clients behind NAT can’t connectTURN not configured or ports blockedEnable TURN; open UDP 3478 (and TCP 5349 for TLS); verify TURN domain resolves
Could not resolve external IP on startup (non-Docker)No STUN internet access or DNS failureSet explicit node_ip and use_external_ip: false
Self-signed cert errors with external LiveKitBedrud’s skipTLSVerify is falseSet skipTLSVerify: true in Bedrud’s livekit: config
Clients connect via relay unnecessarilynode_ip is a private IP behind NATSet node_ip to the public IP or use use_external_ip: true with STUN access
TURN relay not used by clientsDirect WebRTC path is working (expected)Check chrome://webrtc-internalssrflx candidates = direct path, no TURN needed

Webhook & State

SymptomCauseFix
Database shows stale active participants after disconnectWebhook not configured for external LiveKitAdd webhook: block to LiveKit YAML with URL https://<domain>/api/livekit/webhook
Participants never marked inactiveFirewall blocking webhook delivery from LiveKit to BedrudCheck LiveKit logs for webhook delivery errors; ensure port 443/8090 is reachable from LiveKit
Room not cleaned up after all leaveempty_timeout / departure_timeout too highReduce values in LiveKit YAML room: section

Recording (Egress)

Bedrud uses LiveKit’s RoomCompositeEgress API to record rooms as MP4 files.

Prerequisites

  • Redis — LiveKit egress requires Redis for coordinating egress workers. Without Redis, StartRoomCompositeEgress returns permission errors.

  • Egress S3 storage (external mode only) — For external LiveKit, you must configure an egress: section in your LiveKit YAML so recordings are stored to durable S3-compatible storage. Otherwise the FileURL is a local path unreachable from Bedrud.

    egress:
      s3:
        access_key: "your-s3-access-key"
        secret_key: "your-s3-secret-key"
        endpoint: "http://minio:9000"
        bucket: "bedrud-recordings"
        region: "us-east-1"
        force_path_style: true

Troubleshooting: Recording

SymptomCauseFix
twirp error unauthenticated: permissions denied when starting recordingEgress JWT missing Room field in grantUpdate egressAuthContext to include Room: roomName in the VideoGrant
twirp error unauthenticated: permissions denied even with valid API keyRedis not configured for LiveKit, or egress workers unavailableAdd redis: section to LiveKit YAML; ensure Redis is healthy
Recording starts but FileURL is a local path (e.g., /tmp/...)No egress: S3 config — LiveKit writes to worker temp dirAdd egress.s3: block to LiveKit YAML pointing to S3-compatible storage
process_recording job fails to downloadExternal LK’s file URL points to inaccessible local pathConfigure egress S3 so LiveKit produces S3 URLs

See also the TURN Server Guide for TURN-specific troubleshooting, WebRTC Connectivity for STUN/ICE/firewall debugging, and Installation Troubleshooting for port/perm/setup issues.

另请参阅