All checks were successful
deploy / deploy (push) Successful in 42s
Adds a coturn pod that gives clients a relay path when direct UDP to JVB:10001 doesn't make it through carrier NAT (the typical mobile-data failure mode the user hit). Same domain as the rest — meet.it.financeflow.de — because TURN ports (3478/5349) don't collide with the Ingress on 443. - 80-coturn.yaml: hostNetwork Deployment binding STUN+TURN on 3478 (UDP/TCP) and TURNS on 5349 (UDP/TCP), inline-templates turnserver.conf with PUBLIC_IP + TURN_CREDENTIALS_SECRET. TLS cert mounted from the same jitsi-tls Secret cert-manager already manages for the web Ingress. CronJob restarts coturn weekly so cert renewals propagate. - 10-config.yaml: STUN now points at our own coturn; TURN_HOST/TURNS_HOST set so Prosody mod_external_services hands TURN endpoints to clients during XMPP session init. RESOLUTION capped at 480p, START_VIDEO_MUTED=5 keeps large rooms light on bandwidth. - generate-secrets.sh + 20-secrets.yaml.example: TURN_CREDENTIALS_SECRET added so Prosody and coturn share the HMAC key (already pre-synced out-of-band into the cluster). - deploy.yml: sed __PUBLIC_IP__ in coturn manifest, rollout-status coturn. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
163 lines
5.5 KiB
YAML
163 lines
5.5 KiB
YAML
# coturn — STUN+TURN relay for clients whose network can't reach JVB
|
|
# directly. Hosted on the same node as JVB; hostNetwork: true so the
|
|
# TURN listening ports bind on the public NIC. The TLS cert is the
|
|
# same one cert-manager already issues for the jitsi-web Ingress —
|
|
# we mount the jitsi-tls Secret as a volume. Watch out: when the cert
|
|
# renews, this pod must be restarted to pick up the new file (the
|
|
# weekly CronJob below handles that).
|
|
#
|
|
# Auth model: HMAC time-limited credentials. coturn validates with
|
|
# `use-auth-secret` + `static-auth-secret=<TURN_CREDENTIALS_SECRET>`;
|
|
# Prosody hands out matching credentials per session via
|
|
# mod_external_services. Both read the secret from the same k8s
|
|
# Secret entry so they stay in lockstep.
|
|
#
|
|
# Port plan (mirrors required FritzBox forwards):
|
|
# UDP 3478 STUN + TURN (cleartext)
|
|
# TCP 3478 TURN over TCP — first cleartext fallback
|
|
# UDP 5349 TURN over DTLS
|
|
# TCP 5349 TURN over TLS — works through most firewalls
|
|
# UDP 50000-50100 relay range — actual media flows on these
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: coturn
|
|
namespace: jitsi
|
|
spec:
|
|
replicas: 1
|
|
strategy:
|
|
type: Recreate
|
|
selector:
|
|
matchLabels: { app: coturn }
|
|
template:
|
|
metadata:
|
|
labels: { app: coturn }
|
|
spec:
|
|
hostNetwork: true
|
|
dnsPolicy: ClusterFirstWithHostNet
|
|
containers:
|
|
- name: coturn
|
|
image: coturn/coturn:4.7-alpine
|
|
# Inline-template the config so we can interpolate the env-var
|
|
# secret without an extra ConfigMap-then-envsubst dance.
|
|
command: ["/bin/sh", "-c"]
|
|
args:
|
|
- |
|
|
set -eu
|
|
cat > /tmp/turnserver.conf <<EOF
|
|
listening-port=3478
|
|
tls-listening-port=5349
|
|
listening-ip=0.0.0.0
|
|
external-ip=${PUBLIC_IP}
|
|
relay-ip=${PUBLIC_IP}
|
|
cert=/certs/tls.crt
|
|
pkey=/certs/tls.key
|
|
# Jitsi/Prosody hands out HMAC-signed time-limited creds
|
|
# using this same secret — coturn validates them.
|
|
use-auth-secret
|
|
static-auth-secret=${TURN_CREDENTIALS_SECRET}
|
|
realm=meet.it.financeflow.de
|
|
# Relay port range. Forward these on the router.
|
|
min-port=50000
|
|
max-port=50100
|
|
log-file=stdout
|
|
simple-log
|
|
no-loopback-peers
|
|
no-multicast-peers
|
|
no-tlsv1
|
|
no-tlsv1_1
|
|
fingerprint
|
|
# Don't allow relaying to internal addresses — TURN should
|
|
# only relay to the public internet.
|
|
denied-peer-ip=10.0.0.0-10.255.255.255
|
|
denied-peer-ip=172.16.0.0-172.31.255.255
|
|
denied-peer-ip=192.168.0.0-192.168.255.255
|
|
EOF
|
|
exec turnserver -c /tmp/turnserver.conf
|
|
env:
|
|
- name: PUBLIC_IP
|
|
value: "__PUBLIC_IP__"
|
|
- name: TURN_CREDENTIALS_SECRET
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: jitsi-secrets
|
|
key: TURN_CREDENTIALS_SECRET
|
|
ports:
|
|
- { name: stun-udp, containerPort: 3478, hostPort: 3478, protocol: UDP }
|
|
- { name: stun-tcp, containerPort: 3478, hostPort: 3478, protocol: TCP }
|
|
- { name: turns-udp, containerPort: 5349, hostPort: 5349, protocol: UDP }
|
|
- { name: turns-tcp, containerPort: 5349, hostPort: 5349, protocol: TCP }
|
|
volumeMounts:
|
|
- { name: tls, mountPath: /certs, readOnly: true }
|
|
resources:
|
|
requests: { cpu: 100m, memory: 128Mi }
|
|
limits: { cpu: 1, memory: 512Mi }
|
|
volumes:
|
|
- name: tls
|
|
secret:
|
|
secretName: jitsi-tls
|
|
items:
|
|
- { key: tls.crt, path: tls.crt }
|
|
- { key: tls.key, path: tls.key }
|
|
---
|
|
# Cert-manager renews the Let's-Encrypt cert ~30 days before expiry.
|
|
# The Secret content updates automatically, but coturn keeps the old
|
|
# in-memory cert until it's restarted. Restart once a week — Sundays
|
|
# 03:00 — gives us plenty of slack vs. the 90-day cert lifetime and
|
|
# 30-day renewal window.
|
|
apiVersion: batch/v1
|
|
kind: CronJob
|
|
metadata:
|
|
name: coturn-cert-refresh
|
|
namespace: jitsi
|
|
spec:
|
|
schedule: "0 3 * * 0"
|
|
concurrencyPolicy: Forbid
|
|
successfulJobsHistoryLimit: 1
|
|
failedJobsHistoryLimit: 2
|
|
jobTemplate:
|
|
spec:
|
|
template:
|
|
spec:
|
|
serviceAccountName: coturn-restarter
|
|
restartPolicy: OnFailure
|
|
containers:
|
|
- name: kubectl
|
|
image: bitnami/kubectl:1.30
|
|
command: ["/bin/sh", "-c"]
|
|
args:
|
|
- kubectl -n jitsi rollout restart deployment/coturn
|
|
---
|
|
# Minimal RBAC for the CronJob — only allows rolling-restart of the
|
|
# coturn Deployment, nothing else. Scoped to the jitsi namespace.
|
|
apiVersion: v1
|
|
kind: ServiceAccount
|
|
metadata:
|
|
name: coturn-restarter
|
|
namespace: jitsi
|
|
---
|
|
apiVersion: rbac.authorization.k8s.io/v1
|
|
kind: Role
|
|
metadata:
|
|
name: coturn-restarter
|
|
namespace: jitsi
|
|
rules:
|
|
- apiGroups: ["apps"]
|
|
resources: ["deployments"]
|
|
resourceNames: ["coturn"]
|
|
verbs: ["get", "patch"]
|
|
---
|
|
apiVersion: rbac.authorization.k8s.io/v1
|
|
kind: RoleBinding
|
|
metadata:
|
|
name: coturn-restarter
|
|
namespace: jitsi
|
|
subjects:
|
|
- kind: ServiceAccount
|
|
name: coturn-restarter
|
|
namespace: jitsi
|
|
roleRef:
|
|
kind: Role
|
|
name: coturn-restarter
|
|
apiGroup: rbac.authorization.k8s.io
|