LiveKit 自部署教程:从单机 VM 到 Kubernetes 的生产配置

chongy 发布于 2026-06-21 71 次阅读


LiveKit 是一个开源 WebRTC SFU。简单说,它负责房间、信令、音视频转发、数据通道,以及客户端之间的实时连接。你可以直接用 LiveKit Cloud,也可以把 LiveKit Server 跑在自己的服务器上。自部署的好处很直接:数据、网络、地域、成本和扩展方式都由你控制。代价也同样直接:TLS、TURN、Redis、端口、防火墙、升级和监控,都要自己管。

这篇教程按生产落地来写。目标不是“本地跑起来看看”,而是让你能在一台云服务器或 Kubernetes 集群里部署一个能给真实用户使用的 LiveKit。

资料来源主要来自 LiveKit 官方文档、官方 config-sample.yaml、GitHub Release 和 Helm 文档。

适合谁读

你适合自部署 LiveKit,如果你有这些需求:

  • 想把音视频服务放在自己的云账号或机房里
  • 对数据驻留、内网访问或合规有要求
  • 已经有 Kubernetes、Prometheus、日志系统和对象存储
  • 想控制 WebRTC 的端口、TURN、TLS、带宽和扩容策略
  • 需要配合自部署的 Agents、Ingress、Egress 或 SIP 服务

如果你只是做一个 MVP,或者团队没人愿意维护 WebRTC 基础设施,LiveKit Cloud 会省很多事。

LiveKit 自部署的核心组件

最小生产部署通常包含这些东西:

  • LiveKit Server:核心 SFU 和 API 服务
  • Redis:房间状态、节点发现、分布式消息总线
  • HTTPS 入口:给客户端连接 wss://livekit.example.com
  • TURN:提高复杂网络环境下的连通率,尤其是公司网络、VPN、严格防火墙
  • 防火墙规则:开放 WebRTC 所需端口
  • 监控:Prometheus 指标、日志、健康检查

可选组件:

  • Egress:录制房间、导出单轨、推流到 RTMP 平台
  • Ingress:接入 RTMP、WHIP、SRT 等外部媒体源
  • SIP Server:电话呼入呼出
  • Agents:AI Agent worker,连接到你的自部署 LiveKit Server

LiveKit 自部署不是只起一个容器。真正麻烦的地方在网络。

部署路线怎么选

常见有三条路线。

1. 本地开发

适合 SDK 开发、验证 token、跑 demo。

# macOS
brew update && brew install livekit

# Linux
curl -sSL https://get.livekit.io | bash

# 开发模式启动
livekit-server --dev

开发模式会使用固定密钥:

API key: devkey
API secret: secret

默认只监听 127.0.0.1:7880。如果你想让局域网里的手机或其他机器访问,可以这样启动:

livekit-server --dev --bind 0.0.0.0

注意:开发模式不要放到公网。

2. 单机 VM + Docker Compose + Caddy

这是多数小团队最容易落地的方式。官方推荐用生成器生成配置,它会给你生成 Caddy、Docker Compose、LiveKit、Redis 和初始化脚本。

适合:

  • 一台云服务器起步
  • 有域名
  • 想自动申请 TLS 证书
  • 暂时不想维护 Kubernetes

3. Kubernetes + Helm

适合已经有集群的团队。LiveKit 官方提供 Helm chart,可以部署分布式 LiveKit Server、Service 和 Ingress。

但有一个关键点:LiveKit Pod 需要直接访问宿主机网络,通常会使用 host networking。WebRTC 的 UDP/TCP 媒体端口会直接打到节点上,所以通常一个节点只能跑一个 LiveKit Pod。Kubernetes 可以做,但不要把它当普通 Web 服务来部署。

另外,LiveKit 官方明确不建议部署在 serverless 或 private cluster 上。额外 NAT 层会让 WebRTC 变得很难排查。

准备域名

生产部署至少准备一个主域名:

livekit.example.com

客户端连接时会使用:

wss://livekit.example.com

如果你启用 TURN/TLS,建议再准备一个 TURN 域名:

turn.example.com

两个域名都要解析到你的服务器或负载均衡器。证书必须是受信任 CA 签发的证书,自签证书不适合给浏览器和移动端 SDK 用。

如果使用 Caddy,证书可以自动申请。前提是:

  • DNS 已经指向服务器
  • 80 和 443 端口可访问
  • 云厂商安全组没有挡住入站流量

单机 VM 部署

前提条件

你需要:

  • 一台 Linux VM,建议 Ubuntu 或 Amazon Linux
  • 一个域名,并能添加子域名 DNS 记录
  • Docker / Docker Compose,官方生成脚本可以帮你装
  • 公网 IP
  • 云安全组或防火墙配置权限

生成配置

在本地开发机运行官方生成器:

docker pull livekit/generate
docker run --rm -it -v $PWD:/output livekit/generate

生成器会问你域名、是否启用 Ingress/Egress 等选项。完成后会在当前目录生成一个以域名命名的文件夹,里面通常有:

caddy.yaml
docker-compose.yaml
livekit.yaml
redis.conf
init_script.sh
cloud_init.xxxx.yaml

如果云厂商支持 cloud-init,最省事的方式是创建 VM 时把 cloud_init.xxxx.yaml 粘到 User Data 里。机器启动后会自动安装 Docker、写入配置、启动服务。

如果不用 cloud-init,也可以把 init_script.sh 拷到服务器上执行:

scp init_script.sh root@your-server:/root/
ssh root@your-server
chmod +x init_script.sh
sudo ./init_script.sh

脚本完成后,一般会把配置放到:

/opt/livekit

并创建 systemd 服务:

systemctl status livekit-docker
systemctl stop livekit-docker
systemctl start livekit-docker

单机 VM 需要开放的端口

如果按官方 VM 方案部署,至少开放:

  • 80/TCP:证书申请,HTTP-01 challenge
  • 443/TCP:HTTPS、WebSocket、TURN/TLS
  • 7881/TCP:WebRTC over TCP
  • 3478/UDP:TURN/UDP
  • 50000-60000/UDP:WebRTC UDP 媒体端口

如果启用 Ingress:

  • 1935/TCP:RTMP Ingress
  • 7885/UDP:WHIP Ingress WebRTC

如果启用 SIP:

  • 5060/UDP 和 5060/TCP:SIP signaling
  • 5061/TCP:SIP TLS
  • 10000-20000/UDP:SIP RTP 媒体端口

WebRTC 最怕“服务启动了,但 UDP 没通”。如果用户能进房间但没有声音、视频黑屏、连接很慢,第一件事就是查 UDP 端口和候选地址。

生产配置文件怎么写

生产环境建议使用 YAML 配置文件,而不是一堆命令行参数。LiveKit 支持:

livekit-server --config /path/to/livekit.yaml

也支持把 YAML 内容放进 LIVEKIT_CONFIG 环境变量。

一个简化的生产配置如下:

port: 7880
log_level: info

rtc:
  tcp_port: 7881
  port_range_start: 50000
  port_range_end: 60000
  use_external_ip: true

redis:
  address: redis.example.internal:6379

keys:
  your_api_key: your_api_secret

turn:
  enabled: true
  domain: turn.example.com
  tls_port: 3478

# prometheus_port: 6789

几个字段要特别注意。

port

port: 7880 是 LiveKit API 和 WebSocket 的主端口。生产环境一般不要直接暴露给公网,而是放在能终止 TLS 的负载均衡器或反向代理后面。

客户端连接的是:

wss://livekit.example.com

不是裸的 ws://ip:7880。

redis

配置 Redis 后,LiveKit 会自动进入分布式模式。Redis 用来保存房间数据、节点状态和消息总线。即使你现在只有一个节点,生产环境也建议接 Redis,后续扩容会少很多迁移成本。

Redis 如果启用密码、TLS、Sentinel 或 Cluster,需要按官方 config-sample.yaml 的对应字段配置。

keys

这里配置 API key 和 secret:

keys:
  prod_key_xxx: prod_secret_xxx

你的后端签发 access token 时需要用这组 key/secret。不要把 secret 放进前端。

rtc.use_external_ip

云服务器常见情况是:进程看到的是内网 IP,但客户端必须连接公网 IP。use_external_ip: true 会让 LiveKit 尝试通过 STUN 发现公网 IP,并把它作为 ICE candidate 告诉客户端。

如果你在复杂 NAT、双网卡或内网部署里遇到连接问题,要重点检查这里。

UDP 端口范围

默认推荐是:

rtc:
  port_range_start: 50000
  port_range_end: 60000

每个参与者通常会消耗端口资源。端口范围太小,房间人数或并发房间上去后会出问题。

LiveKit 也支持 UDP mux,把 UDP 媒体流量收敛到单个端口:

rtc:
  udp_port: 7882

设置 rtc.udp_port 后,port_range_start 和 port_range_end 就不再使用。这个方案对防火墙友好,但是否适合你的规模和网络,要实际压测。

TURN 怎么配

TURN 是自部署 LiveKit 里最值得认真配置的部分。理想情况下,WebRTC 直接用 UDP 连接 SFU,延迟低、质量好。但现实里很多用户在公司网络、学校网络、VPN、酒店 Wi-Fi 或移动运营商 NAT 后面,直接 UDP 可能失败。

LiveKit 内置 TURN Server,并且和 LiveKit 的认证集成。只有已经建立信令连接的客户端才能使用 TURN。

TURN/TLS

TURN/TLS 对很多防火墙最友好,因为看起来像普通 HTTPS 流量。

示例:

turn:
  enabled: true
  tls_port: 5349
  domain: turn.example.com
  cert_file: /path/to/turn.crt
  key_file: /path/to/turn.key

如果没有四层负载均衡器,turn.tls_port 通常需要设成 443,因为这是会被广告给客户端的端口。

如果你用官方 VM + Caddy 生成器,证书和 443 入口会帮你处理很多细节。

TURN/UDP

如果网络允许 UDP,TURN/UDP 的延迟通常比 TURN/TCP/TLS 更好:

turn:
  enabled: true
  udp_port: 443

有些网络允许 UDP 443,因为 QUIC/HTTP3 越来越常见。这个配置可以提高连通率。

TURN 的常见坑

  • TURN 域名和证书不匹配
  • 证书文件路径在容器里不存在
  • 云安全组只开了 TCP 443,没开 UDP
  • turn.tls_port 配了 5349,但客户端实际只能访问 443
  • 多节点部署时,TURN/TLS 前面没有合适的四层负载均衡器

Kubernetes 部署

Kubernetes 部署适合已经有基础设施团队的场景。官方 Helm repo:

helm repo add livekit https://helm.livekit.io
helm repo update

安装:

helm install livekit livekit/livekit-server \
  --namespace livekit \
  --create-namespace \
  --values values.yaml

升级:

helm repo update
helm upgrade livekit livekit/livekit-server \
  --namespace livekit \
  --values values.yaml

配置变更后要注意:如果只是 ConfigMap 变了,Kubernetes 不一定会自动重启 Pod。必要时手动触发 rollout restart。

kubectl rollout restart deployment/livekit -n livekit

Kubernetes 的几个现实限制

第一,LiveKit 需要 host networking。媒体端口要直接打到节点上。

第二,通常一个节点只跑一个 LiveKit Pod。因为端口是固定映射到宿主机的。

第三,升级时要考虑房间里的用户。LiveKit 支持 drain,官方 Helm chart 的 terminationGracePeriodSeconds 默认设得很长,用来让旧 Pod 慢慢退出,而不是直接踢掉正在通话的人。

第四,TLS 终止一般交给 Ingress 或云负载均衡器,TURN/TLS 证书可能还要单独以 Kubernetes Secret 形式导入:

kubectl create secret tls livekit-turn-tls \
  --cert turn.crt \
  --key turn.key \
  --namespace livekit

Kubernetes 前置依赖

通常需要:

  • Redis
  • 主域名证书
  • TURN/TLS 证书
  • Helm
  • 云厂商负载均衡器或 Ingress Controller
  • 正确的防火墙和安全组

AWS 上常见选择是 ALB Ingress Controller。DigitalOcean 上官方文档提到 Nginx Ingress Controller 和 cert-manager。

Egress:录制和推流

LiveKit Cloud 默认提供 Egress。自部署时,Egress 是单独服务,需要额外部署。

Egress 可以做:

  • 房间合成录制
  • 单轨录制
  • 输出 MP4 或 HLS
  • 推流到 YouTube Live、Twitch、Facebook 等 RTMP 平台

Egress worker 会自动负载均衡任务。官方建议每个 Egress 实例至少给:

4 CPU / 4 GB RAM

Egress 配置示例:

api_key: your-api-key
api_secret: your-api-secret
ws_url: wss://livekit.example.com
redis:
  address: redis.example.internal:6379

s3:
  access_key: xxx
  secret: xxx
  region: ap-east-1
  bucket: livekit-recordings

Docker 运行时有一个容易踩的点:从 Egress v1.7.6 起,Chrome sandbox 默认启用。Room Composite 和 Web Egress 依赖 Chrome,如果 Docker 没加权限,可能报 chrome failed to start。

官方 Docker 示例需要:

docker run --rm \
  --cap-add SYS_ADMIN \
  -e EGRESS_CONFIG_FILE=/out/config.yaml \
  -v ~/livekit-egress:/out \
  livekit/egress

Kubernetes 里可以用 Helm:

helm install livekit-egress livekit/egress \
  --namespace livekit \
  --values egress-values.yaml

如果你要同时录制多个房间,记得增加副本数或配置 autoscaling。一个实例不是无限吞任务。

Ingress:接入 RTMP / WHIP

Ingress 用来把外部媒体源送进 LiveKit 房间,比如 OBS 推 RTMP,或用 WHIP 接入 WebRTC 流。

自部署时,Ingress 也是单独服务。

官方建议每个 Ingress 实例至少:

4 CPU / 4 GB RAM

Ingress 服务配置示例:

api_key: your-api-key
api_secret: your-api-secret
ws_url: wss://livekit.example.com
redis:
  address: redis.example.internal:6379

rtmp_port: 1935
whip_port: 8080
rtc_config:
  udp_port: 7885
  use_external_ip: true

LiveKit Server 还需要知道 Ingress 的公开地址,这样 CreateIngress API 才能返回正确的推流地址:

ingress:
  rtmp_base_url: 'rtmps://ingress.example.com/live'
  whip_base_url: 'https://ingress.example.com/whip'

如果多个 Ingress worker 并行,需要在前面放 TCP 负载均衡器。WHIP 可以走 HTTP 反向代理,RTMP 更适合 TCP LB。

SIP:电话接入

LiveKit SIP Server 可以让电话呼入 LiveKit 房间,也可以从 LiveKit 发起外呼。自部署时需要单独部署 SIP 服务。

最简单的 Docker Compose:

wget https://raw.githubusercontent.com/livekit/sip/main/docker-compose.yaml
docker compose up

本地配置示例:

api_key: your-api-key
api_secret: your-api-secret
ws_url: ws://localhost:7880
redis:
  address: localhost:6379
sip_port: 5060
rtp_port: 10000-20000
use_external_ip: true
logging:
  level: debug

SIP 的端口必须从公网可达,尤其是:

  • 5060:SIP signaling
  • 10000-20000/UDP:RTP 媒体

如果电话能呼入但没有声音,优先查 RTP 端口、SDP 里的公网 IP,以及 SIP provider 侧的 ACL。

监控和排障

Prometheus

LiveKit Server 可以开启 Prometheus 指标:

prometheus_port: 6789

然后抓:

http://livekit-node:6789/metrics

Egress 和 Ingress 也支持 Prometheus 端口,可用于 autoscaling。

健康检查

API / WebSocket 入口要有负载均衡健康检查。Ingress/Egress 也有自己的 health endpoint。Kubernetes 里建议配置 readiness/liveness probe,不要只看容器进程是否存在。

日志级别

生产用 info。排障时临时改成 debug,排完恢复。WebRTC 日志非常容易刷屏。

log_level: info

Ingress 里是:

logging:
  level: info

验证部署是否成功

1. 检查 API 和 WebSocket 域名

curl -I https://livekit.example.com

TLS 证书必须正常,不能有浏览器不信任的问题。

2. 用 LiveKit CLI 连接

安装 CLI 后,可以添加自部署项目:

lk cloud auth

如果你不用 Cloud 登录,而是本地自部署项目,按 CLI 提示添加 server URL、API key 和 secret。实际命令会随 CLI 版本变化,建议以 lk --help 为准。

3. 生成 token,跑一个前端 demo

你的后端要用 API key/secret 签发 token。前端只拿 token 和 wss://livekit.example.com。

不要把 API secret 放进浏览器代码。

4. 测 UDP 连通性

在真实网络里测试:

  • 家庭宽带
  • 公司网络
  • 手机 4G/5G
  • VPN 后面
  • 海外用户网络

WebRTC “我本地可以”没有太大意义。TURN 和 UDP 的问题只有跨网络测试才会暴露。

升级策略

单机 VM 官方脚本默认会生成 /opt/livekit/docker-compose.yaml。升级时可以改 LiveKit 镜像:

image: livekit/livekit-server:v1.13.1

然后:

docker pull livekit/livekit-server:v1.13.1
systemctl restart livekit-docker

如果你想总是跑最新版,可以用:

image: livekit/livekit-server:latest

但生产环境我不建议这样做。固定版本、先 staging、再生产,排障会轻松很多。

Kubernetes 用 Helm upgrade。升级前看 release notes,尤其是 LiveKit Server、Egress、Ingress、SIP 的版本是否匹配。

本文整理时,GitHub 最新 release 显示:

  • LiveKit Server:v1.13.1
  • Egress:v1.13.0
  • Ingress:v1.5.0

实际部署前请重新检查 GitHub Release。

常见问题

用户能进房间,但没有音视频

优先查:

  • 50000-60000/UDP 是否开放
  • 云安全组是否只开了 TCP,没开 UDP
  • rtc.use_external_ip 是否正确
  • ICE candidate 里是否出现内网 IP
  • TURN 是否配置并可访问

公司网络里连不上

配置 TURN/TLS,并尽量让它走 443:

turn:
  enabled: true
  domain: turn.example.com
  tls_port: 443

如果 UDP 443 可用,也可以加 TURN/UDP。

多节点房间会不会跨节点

LiveKit 的单个 room 会落在一个节点上。Redis 让集群节点能发现彼此、做路由和负载选择,但一个房间本身仍然要能被单节点承载。所以大房间容量取决于单节点 CPU 和带宽。

Kubernetes 可以随便扩 Pod 吗

不能像普通 HTTP 服务那样随便扩。LiveKit Pod 需要 host networking 和固定媒体端口。通常一个节点一个 Pod,并且节点防火墙要开放对应端口。

自部署支持 Egress、Ingress、SIP 吗

支持,但它们都是独立服务,不是 LiveKit Server 启动后自动就有。需要分别部署、配置 Redis、API key/secret、LiveKit ws_url,并开放各自端口。

一份可执行的上线清单

上线前至少检查这些项:

  • 域名解析正确:livekit.example.com、turn.example.com
  • TLS 证书可信且未过期
  • LiveKit API 入口走 HTTPS/WSS
  • Redis 已配置,且 LiveKit 能连接
  • API key/secret 只在后端和服务端保存
  • UDP 媒体端口已开放
  • TURN/TLS 已配置并从公网可访问
  • 手机网络、公司网络、VPN 网络都测试过
  • Prometheus 指标已接入
  • 日志能集中查看
  • 升级流程已经在 staging 跑过
  • Egress/Ingress/SIP 如需使用,已经单独压测

总结

LiveKit 自部署真正的门槛不是把容器跑起来,而是把 WebRTC 网络环境处理好。单机 VM 方案适合快速上线,官方生成器能省掉大量 Caddy、Docker Compose 和证书配置。Kubernetes 方案适合已有基础设施团队的场景,但要接受 host networking、节点端口和灰度升级带来的复杂度。

如果你只记住三件事:

  1. 生产环境要用可信 TLS 和 wss://。
  2. UDP 和 TURN 配置决定真实用户的连通率。
  3. Redis、监控、固定版本和升级流程,是从“能跑”到“能维护”的分界线。

把这三件事做好,LiveKit 自部署就不是玄学。剩下的才是容量规划、录制、接入外部流、SIP 电话和 AI Agent 这些更上层的问题。

参考资料

  • LiveKit Self-hosting overview:https://docs.livekit.io/home/self-hosting/
  • LiveKit Deployment:https://docs.livekit.io/home/self-hosting/deployment/
  • LiveKit VM deployment:https://docs.livekit.io/home/self-hosting/vm/
  • LiveKit Kubernetes:https://docs.livekit.io/home/self-hosting/kubernetes/
  • LiveKit Firewall configuration:https://docs.livekit.io/home/self-hosting/ports-firewall/
  • LiveKit Egress self-hosting:https://docs.livekit.io/home/self-hosting/egress/
  • LiveKit Ingress self-hosting:https://docs.livekit.io/home/self-hosting/ingress/
  • LiveKit SIP self-hosting:https://docs.livekit.io/home/self-hosting/sip/
  • LiveKit server config sample:https://github.com/livekit/livekit/blob/master/config-sample.yaml