Enable VoIP calls for Matrix Synapse on Kubernetes

Using voice / video calls on your Synapse server can be tricky, especially if you have your homeserver setup at home, with a dynamic public IP. Luckily tricky doesn't mean impossible, like the requirements from Synapse itself might suggest.

This Guide will walk you through setting up a Turnserver (coturn in this case) in Kubernetes, behind a dynamic IP.

Setting up TURN

The turnserver needs to be aware of your public IP Address. Unfortunately almost all home ISP connections use a dynamic public IP, so this address changes daily. Turn does not recognize this IP change and will cease to function. To work around this, I created this docker image that will detect the IP change.

First create a folder to store your kubernetes manifests in, with mkdir coturn && cd coturn/. Next create the configMap for coturn with the following content

apiVersion: v1
kind: ConfigMap
metadata:
  name: coturn-conf
data:
  coturn.conf: |
    log-file=stdout
    #Use your INTERAL IP under which the K8 Host will be reachable through
    relay-ip={{INTERNAL_IP_OF_K8_Host}}
    #If dont want to use TLS replace with listening-port=5349
    tls-listening-port=5349
    min-port=49160
    max-port=49200
    use-auth-secret
    static-auth-secret=SuperSecureSecretCHANGEME
    #This domain needs to point to your Public IP under which coturn will be reachable through
    realm=turn.example.com:5349
    #If you want to disable TLS delete the next two lines
    cert=/var/run/secret/tls.crt
    pkey=/var/run/secret/tls.key
    no-cli
configMap.yaml

Note: It's important, that you set the relay IP correctly. If  you have a multi node cluster, it is necessary to pin coturn to a specific host, so that you can be sure which internal IP to point it to. There is no need to specifiy the external / public IP, as the POD will automatically detect it.

Next the deployment itself

apiVersion: apps/v1
kind: Deployment
metadata:
  name: coturn
spec:
  selector:
    matchLabels:
      app: coturn
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: coturn
    spec:
      hostNetwork: true
      containers:
        - image: dexxter1911/dynamic-coturn:latest
          name: turn
          env:
          - name: TURN_CONFIG
            value: /etc/coturn.conf
          #CHECK_INTERVAL defines the interval seconds between IP checks.
          - name: CHECK_INTERVAL
            value: "500"
          volumeMounts:
          - name: cert
            mountPath: /var/run/secret
            readOnly: true
          - name: conf
            mountPath: /etc/coturn.conf
            subPath: coturn.conf
      volumes:
      #In my case this is a wildcard certificate which automatically includes turn.example.com
      - name: cert
        secret:
          secretName: example.com
      - name: conf
        configMap:
          name: coturn-conf
          items:
          - key: coturn.conf
            path: coturn.conf
deployment.yaml

Note: This deployment will run on the host network itself. This is to avoid multiple NATs and the need to port forward a lot of ports through a service. It might be possible to use a service, I haven't tried though.

Now apply the manifests with

kubectl apply -f configMap.yaml
kubectl apply -f deployment.yaml

Synapse configuration

Locate your homeserver.yaml configuration file, search for TURN and add the following config

## TURN ##

# The public URIs of the TURN server to give to clients
#
turn_uris:
  - "turns:turn.example.com:5349?transport=tcp"
  - "turns:turn.example.com:5349?transport=udp"
  - "turn:turn.example.com:5349?transport=tcp"
  - "turn:turn.example.com:5349?transport=udp"

# The shared secret used to compute passwords for the TURN server
#
turn_shared_secret: "{{TheSecretYouSetInTheTurnConfigMap}}"

# How long generated TURN credentials last
#
turn_user_lifetime: 1h
homeserver.yaml

Note: If you do not use TLS just omit the lines starting with turns:.

After you made the change, save and exit the config and restart Synapse.  Lastly you need to portforward a few Ports from your Router:

  • 5349/udp
  • 5349/tcp
  • 49160 - 49200/udp

They need to be forwarded to the host that is running the Turnserver POD. That's it! All that is left is verifying that it works. This can be done with this site. Input your Synapse domain and either a User / Password combination or  an access token. You can get an access token through Element Desktop: All Settings -> Help & About; scroll down; click <click to reveal> next to Access Token.

Your setup is working if you see something like this.

Show Comments