From 8ff438bd248d2a65c5a35129496e7f3baf860c7e Mon Sep 17 00:00:00 2001 From: Scrublord MacBad Date: Wed, 29 Apr 2026 23:07:52 +0200 Subject: [PATCH] Implement TURN server (coturn) for WebRTC video calls Add coturn Deployment with hostNetwork mode and init container for secret substitution. Include SOPS-encrypted shared secret, TLS certificate for turn.axion1337.chat, and Synapse TURN configuration with proper relay URIs and credentials. Resolves DTLS timeout issues in RTC video calls by providing media relay for clients behind NAT/Firewall. Co-Authored-By: Claude Haiku 4.5 --- apps/production/coturn-secret.yaml | 22 +++ apps/production/coturn.yaml | 162 ++++++++++++++++++ .../custom-configs/synapse-values.yaml | 11 +- apps/production/kustomization.yaml | 4 + apps/production/matrix-certificates.yaml | 13 ++ 5 files changed, 211 insertions(+), 1 deletion(-) create mode 100644 apps/production/coturn-secret.yaml create mode 100644 apps/production/coturn.yaml diff --git a/apps/production/coturn-secret.yaml b/apps/production/coturn-secret.yaml new file mode 100644 index 0000000..8d99474 --- /dev/null +++ b/apps/production/coturn-secret.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: Secret +metadata: + name: coturn-secret + namespace: matrix +stringData: + TURN_SECRET: ENC[AES256_GCM,data:SILIqMB+fmAMFITAL7lG1hOgICec6BJf1mOcK0gdmnCHWYqRuJv7jgjfGylG25xzQKi+zE7Qual9PnkZG2KiOA==,iv:+GZqLGusE4Q0x2jEEtFxj06rryyQmQhXdkTy4eE8ZHw=,tag:OpSZkinPTAi1ZKWyo8OX3A==,type:str] +sops: + age: + - recipient: age14l0hwfqylwpemz5y2ghh2yxk0phszlnj3qlejhue0fw0kz3tmfgqdsjzdh + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAyRk1mK3NWc1l4T0JCOFpF + S0RuQ3ViZmo3QTNVL2JvZ0hzMy91R2l0TEhzCk01a1VGdk1sdVg4aWswTzRibXI4 + ZlJtNFF5MjBONEZOaWVpeU5taHl2bkEKLS0tIGxpUHY3NUFLWFBaWm1QSlZiVFkx + MEJleHFnd3oyT3VPL2dsYkpMUlRkOWMKcKUIgsQ/ff49pGGXMnYwJmwqPVC7woAR + IEzvhcNX97xx746SnrxZe5t2YadsYMkYIl0nvqBPJhSlvqMNafpQbQ== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2026-04-29T21:06:21Z" + mac: ENC[AES256_GCM,data:UhyR5m1HYWrZHwNLW5sg2PxbpaydWbP5cekghGlzSpQg7CYEcvZw3tJ/qB8zA19xZSM7tdSHOXdD+QytRq6qW59M1unqMaumA43B6JxQg1C1NdXAW0mkSc2WiNchvgpVii9P/TVlzSSIRwC3YGCQUsfa3SSfNzI4Z6fMuBnhYLE=,iv:4HYxbrYSRJLe1KcQ6q8bpee8/Lx1m3pPmisb/L2Mu64=,tag:l7n3u+Pg6533OzwtNUZvNw==,type:str] + encrypted_regex: ^(data|stringData)$ + version: 3.12.2 diff --git a/apps/production/coturn.yaml b/apps/production/coturn.yaml new file mode 100644 index 0000000..9038940 --- /dev/null +++ b/apps/production/coturn.yaml @@ -0,0 +1,162 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: coturn-config + namespace: matrix +data: + turnserver.conf: | + # TURN Server configuration + realm=axion1337.chat + + # Listen ports + listening-port=3478 + listening-ip=0.0.0.0 + alt-listening-port=5349 + alt-listening-ip=0.0.0.0 + + # External IPs (for clients behind NAT) + relay-ip=49.13.132.245 + external-ip=49.13.132.245 + + # Relay port range + min-bps=0 + bps-capacity=0 + + # Authentication + use-auth-secret + static-auth-secret=$TURN_SECRET + + # HTTPS/TLS + cert=/etc/coturn/tls/tls.crt + pkey=/etc/coturn/tls/tls.key + + # Performance tuning + max-bps=0 + bps-capacity=0 + log-file=stdout + + # Logging + verbose +--- +apiVersion: v1 +kind: Service +metadata: + name: coturn + namespace: matrix +spec: + type: ClusterIP + ports: + - name: stun-udp + port: 3478 + protocol: UDP + - name: stun-tcp + port: 3478 + protocol: TCP + - name: turns-tcp + port: 5349 + protocol: TCP + selector: + app: coturn +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: coturn + namespace: matrix +spec: + replicas: 1 + selector: + matchLabels: + app: coturn + template: + metadata: + labels: + app: coturn + annotations: + prometheus.io/scrape: "false" + spec: + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + initContainers: + - name: init-config + image: busybox:1.28 + command: + - sh + - -c + - | + TURN_SECRET=$(cat /etc/coturn-secret/TURN_SECRET) + sed "s|\$TURN_SECRET|$TURN_SECRET|g" /etc/coturn-template/turnserver.conf > /etc/coturn/turnserver.conf + chmod 644 /etc/coturn/turnserver.conf + resources: + limits: + cpu: 100m + memory: 64Mi + requests: + cpu: 50m + memory: 32Mi + volumeMounts: + - name: config-template + mountPath: /etc/coturn-template + - name: config + mountPath: /etc/coturn + - name: secret + mountPath: /etc/coturn-secret + readOnly: true + containers: + - name: coturn + image: coturn/coturn:latest + imagePullPolicy: IfNotPresent + ports: + - name: stun-udp + containerPort: 3478 + protocol: UDP + - name: stun-tcp + containerPort: 3478 + protocol: TCP + - name: turns-tcp + containerPort: 5349 + protocol: TCP + volumeMounts: + - name: config + mountPath: /etc/coturn + - name: tls + mountPath: /etc/coturn/tls + readOnly: true + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 100m + memory: 128Mi + livenessProbe: + exec: + command: + - /bin/sh + - -c + - "netstat -uln | grep 3478 || exit 1" + initialDelaySeconds: 30 + periodSeconds: 10 + volumes: + - name: config + emptyDir: {} + - name: config-template + configMap: + name: coturn-config + - name: secret + secret: + secretName: coturn-secret + defaultMode: 0400 + - name: tls + secret: + secretName: turn-axion1337-chat-tls + affinity: + nodeAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + preference: + matchExpressions: + - key: kubernetes.io/hostname + operator: In + values: + - matrix diff --git a/apps/production/custom-configs/synapse-values.yaml b/apps/production/custom-configs/synapse-values.yaml index e9538c0..3ea2719 100644 --- a/apps/production/custom-configs/synapse-values.yaml +++ b/apps/production/custom-configs/synapse-values.yaml @@ -57,4 +57,13 @@ data: config: | room_list_publication_rules: - user_id: "*" - action: allow \ No newline at end of file + action: allow + turn: + config: | + turn_uris: + - "turn:turn.axion1337.chat?transport=udp" + - "turn:turn.axion1337.chat?transport=tcp" + - "turns:turn.axion1337.chat?transport=tcp" + turn_shared_secret: "cab3c8408363515d9b4cdc3384a1f76ca17a973242fdfdc72b67ac4d86158527" + turn_user_lifetime: 86400000 + turn_allow_guests: false \ No newline at end of file diff --git a/apps/production/kustomization.yaml b/apps/production/kustomization.yaml index 6affd67..260f0b8 100644 --- a/apps/production/kustomization.yaml +++ b/apps/production/kustomization.yaml @@ -3,12 +3,16 @@ kind: Kustomization resources: - matrix-postgres-auth.yaml - cert-issuer.yaml + - matrix-certificates.yaml # Neue Dateien: - custom-configs/synapse-values.yaml - custom-configs/element-values.yaml - custom-configs/mas-secret.yaml - element-web-docs-configmap.yaml - element-web-docs-server.yaml + # TURN Server für WebRTC + - coturn-secret.yaml + - coturn.yaml # HelmRelease (muss ganz unten stehen, damit die ConfigMaps vorher da sind!) - element-server-suite.yaml # Custom Apex Ingress für Element Web + Well-Known auf axion1337.chat diff --git a/apps/production/matrix-certificates.yaml b/apps/production/matrix-certificates.yaml index b06ea29..99c5efb 100644 --- a/apps/production/matrix-certificates.yaml +++ b/apps/production/matrix-certificates.yaml @@ -62,3 +62,16 @@ spec: kind: ClusterIssuer dnsNames: - admin.axion1337.chat +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: turn-axion1337-chat-cert + namespace: matrix +spec: + secretName: turn-axion1337-chat-tls + issuerRef: + name: letsencrypt-prod + kind: ClusterIssuer + dnsNames: + - turn.axion1337.chat