운영에서 LiveKit(SFU)을 직접 호스팅하기 위한 구성과 배포 가이드를 추가한다. 실제 배포는 서버/도메인/TLS 가 필요하므로, 클론 후 값만 채워 배포하는 템플릿 형태. - docker-compose.yml: livekit 서비스를 opt-in 프로파일(selfhost-livekit)로 추가. 기존 dev/운영 동작 불변(프로파일 미지정 시 미생성). 시그널링 7880 은 expose(프록시 TLS 라우팅), 미디어 7881/tcp·7882/udp 는 호스트 공개. 키는 LIVEKIT_KEYS env 주입. - livekit/livekit.prod.yaml: 단일 노드 운영 설정(use_external_ip, tcp/udp 포트). 클러스터링용 redis 블록은 비밀값이라 주석으로 두고 배포 시 사본에 채움. - .env.production.example: LIVEKIT_* 섹션(셀프호스팅/ Cloud 양쪽 안내). - livekit/DEPLOY.md: 사전준비/키생성/기동/프록시(wss)/방화벽/검증(load-test)/ 멀티노드 클러스터링(Redis·캐스케이딩)/운영팁. - .gitignore: livekit/*.local.yaml(클러스터 설정 사본) 제외. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
5.1 KiB
LiveKit 셀프호스팅 배포 가이드 (화상회의 단계 6)
운영에서 LiveKit(SFU)을 직접 호스팅하는 방법. 단일 노드 → 멀티 노드 클러스터 순으로 설명한다.
(간단히 가려면 운영도 LiveKit Cloud 를 그대로 쓸 수 있다 — 그 경우 .env.production 의 LIVEKIT_* 만 Cloud 값으로 두고 아래 셀프호스팅 절차는 생략.)
로컬 dev 에서 셀프호스팅이 막혔던 건 WSL2/Docker Desktop 네트워킹 제약 때문이며, 공인 IP 가 있는 실서버에서는 발생하지 않는다.
1. 사전 준비
- 공인 IP 를 가진 리눅스 서버(도커 설치)
- 도메인 + DNS:
livekit.<도메인>A 레코드 → 서버 공인 IP - 리버스 프록시(TLS 종단): 기존
proxy외부 네트워크의 프록시(Traefik/nginx 등) - 방화벽 개방:
443/tcp— 시그널링(wss, 프록시 경유)7881/tcp— ICE/TCP 폴백7882/udp— ICE/UDP(미디어)
2. 키 생성
API Key 는 임의 식별자, Secret 은 32자 이상 강력한 난수.
echo "LIVEKIT_API_KEY=$(openssl rand -hex 8)"
echo "LIVEKIT_API_SECRET=$(openssl rand -hex 32)"
.env.production 에 채운다:
LIVEKIT_API_KEY=<생성한 key>
LIVEKIT_API_SECRET=<생성한 secret(32자+)>
LIVEKIT_WS_URL=wss://livekit.<도메인> # 브라우저 접속(프론트 빌드에 주입)
LIVEKIT_URL=http://livekit:7880 # 백엔드 → LiveKit 내부 API
LIVEKIT_WS_URL은 프론트 빌드 시VITE_LIVEKIT_URL로 굽혀진다. 값 변경 시 프론트 재빌드 필요.
3. 기동 (단일 노드)
docker compose --profile selfhost-livekit --env-file .env.production up -d --build
selfhost-livekit프로파일을 켜야 LiveKit 컨테이너가 생성된다(미지정 시 미생성).- 설정:
livekit/livekit.prod.yaml(키는LIVEKIT_KEYSenv 로 주입),use_external_ip: true로 공인 IP 자동 광고.
4. 리버스 프록시 라우팅 (시그널링 wss)
wss://livekit.<도메인> → 컨테이너 livekit:7880 으로 라우팅(WebSocket 업그레이드 + TLS 종단).
미디어(7881/7882)는 프록시를 거치지 않는다 — 직접 공인 IP 로 통신.
Traefik(라벨) 예:
# docker-compose 의 livekit 서비스에 labels 추가(운영 프록시 구성에 맞게):
labels:
- "traefik.enable=true"
- "traefik.http.routers.livekit.rule=Host(`livekit.<도메인>`)"
- "traefik.http.routers.livekit.entrypoints=websecure"
- "traefik.http.routers.livekit.tls.certresolver=<resolver>"
- "traefik.http.services.livekit.loadbalancer.server.port=7880"
nginx 예:
server {
listen 443 ssl;
server_name livekit.<도메인>;
# ssl_certificate ... ;
location / {
proxy_pass http://livekit:7880;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 600s;
}
}
5. 검증
- 브라우저에서 회의 입장(두 기기/네트워크에서 영상 확인)
- 부하 테스트:
LIVEKIT_URL=wss://livekit.<도메인> \ LIVEKIT_API_KEY=<key> LIVEKIT_API_SECRET=<secret> \ ./livekit/load-test.sh full
6. 멀티 노드 클러스터링 (수평 확장)
대규모(예: 160명 다수 방)에서 노드 간 트래픽을 분산하려면 Redis 로 LiveKit 노드들을 묶는다.
-
설정에 redis 블록 추가 — 비밀번호가 들어가므로 커밋 파일이 아닌 사본에 둔다.
cp livekit/livekit.prod.yaml livekit/livekit.prod.local.yaml # gitignore 대상livekit.prod.local.yaml에 추가:redis: address: redis:6379 db: 1 # 앱 캐시(db 0)와 분리 password: <REDIS_PASSWORD> # 루트 .env 의 REDIS_PASSWORDcompose 의 livekit 볼륨을 이 사본으로 교체(override 파일 권장).
-
노드 확장
- 단일 호스트에서 replica 만 늘리는 것은 진짜 분산이 아니다(같은 머신·NIC).
- 실제 분산 = 여러 호스트 각각 LiveKit 실행 + 공유 Redis + 시그널링은 프록시가 여러 노드로 LB. RTC 는 각 노드의 공인 IP 로 직접.
- LiveKit 이 방을 노드에 분배(room→node)하고, 한 방이 여러 노드에 걸치면 캐스케이딩으로 노드 간 미디어를 릴레이한다.
- Simulcast/SVC 로 수신측 상황에 맞는 화질 레이어만 전달(기본 활성).
-
부하 분산 검증:
./livekit/load-test.sh full로 다수 참여자를 투입하고, 노드별 참여자/대역폭 분포를 모니터링.
7. 운영 팁
- UDP 수신 버퍼 상향(권장):
sysctl -w net.core.rmem_max=16777216 net.core.wmem_max=16777216(영구화는/etc/sysctl.conf). 미설정 시 LiveKit 이 경고 로그를 남긴다. - 모니터링: LiveKit Prometheus 메트릭(
/metrics) + Grafana — 노드별 참여자/트랙/CPU/대역폭. - 리소스: compose 의
deploy.resources.limits를 트래픽에 맞게 조정(기본 2 CPU / 2GB). .gitignore에livekit/*.local.yaml추가(비밀번호 포함 사본 커밋 방지).