Docker Installation

Updated:
Author: Erkin Khidirov

This guide covers deploying Slyber TURN Server in a Docker container, configuring authentication modes, and verifying all system nodes during testing.

Choosing an Authentication Mode

Before starting the container, select the WebRTC client credential verification mode using the AUTH_MODE environment variable:

  • AUTH_MODE="secret" (standalone secret key mode): the server operates without external databases and validates temporary passwords using the HMAC-SHA1 algorithm based on the shared TURN_SECRET key. Suitable for rapid deployment when your backend only needs to issue temporary tokens to clients. Check out the HTTP API.
  • AUTH_MODE="redis" (dynamic mode via Redis): the server checks for the user key in the Redis database on every connection. This allows you to view active sessions in real time, manage their TTL, and instantly disconnect a specific participant right during a call by deleting their key from the database.

By default, with PUBLIC_IP="auto", the server automatically detects its external IPv4 address on startup, so manual IP configuration is not required.

Option 1. Running in secret Mode

Start the Slyber TURN Server container:

Bash
docker pull ghcr.io/slyber-app/slyber-turn-server:latest
docker rm -f slyber_turn 2>/dev/null || true

GEN_SECRET=$(head -c 16 /dev/urandom | od -An -tx1 | tr -d ' \n') && \

docker run -d \
  --name slyber_turn \
  --restart unless-stopped \
  -p 3478:3478/udp \
  -p 3478:3478/tcp \
  -p 8080:8080/tcp \
  -p 50000-50100:50000-50100/udp \
  -e PUBLIC_IP="auto" \
  -e REALM="turn.local" \
  -e AUTH_MODE="secret" \
  -e TURN_SECRET="${GEN_SECRET}" \
  -e RELAY_MIN_PORT=50000 \
  -e RELAY_MAX_PORT=50100 \
  ghcr.io/slyber-app/slyber-turn-server:latest && \
  sleep 1 && \
  docker exec slyber_turn slyber_turn doctor && \
  HOST_IP=$([ -n "${SSH_CONNECTION:-}" ] && curl -fsSL4 --max-time 2 ifconfig.me 2>/dev/null || echo 127.0.0.1) && \
  echo "  TURN / STUN URI : turn:${HOST_IP}:3478 (UDP/TCP)" && \
  echo "  HTTP API URL    : http://${HOST_IP}:8080" && \
  echo "  Realm           : turn.local" && \
  echo "  Auth Mode       : secret (TURN_SECRET=${GEN_SECRET})" && \
  echo "  Test Creds API  : curl -s \"http://${HOST_IP}:8080/api/turn-credentials?user_id=dev\" && echo" && \
  echo "  Run Benchmark   : docker exec slyber_turn slyber_turn bench -clients 20 -duration 5s" && \
  echo "  Live Logs       : docker logs -f slyber_turn" && \
  echo "--------------------------------------------------"

Check the server status using the built-in doctor utility:

Bash
docker exec slyber_turn slyber_turn doctor

Verify temporary credential generation via the HTTP API.

In secret mode, the built-in API on port 8080 generates a ready-to-use username and password pair with a limited lifetime for the specified user_id:

Bash
curl -s "http://127.0.0.1:8080/api/turn-credentials?user_id=some_user_id" && echo ""

Option 2. Running in redis Mode

Start the Slyber TURN Server container connected to Redis:

Bash
docker network create slyber_net 2>/dev/null || true
docker rm -f slyber_redis 2>/dev/null || true
docker run -d \
  --name slyber_redis \
  --restart unless-stopped \
  --network slyber_net \
  -p 6379:6379/tcp \
  redis:alpine redis-server --protected-mode no

docker pull ghcr.io/slyber-app/slyber-turn-server:latest
docker rm -f slyber_turn 2>/dev/null || true

docker run -d \
  --name slyber_turn \
  --restart unless-stopped \
  --network slyber_net \
  -p 3478:3478/udp \
  -p 3478:3478/tcp \
  -p 8080:8080/tcp \
  -p 50000-50100:50000-50100/udp \
  -e PUBLIC_IP="auto" \
  -e REALM="turn.local" \
  -e AUTH_MODE="redis" \
  -e REDIS_ADDR="slyber_redis:6379" \
  -e RELAY_MIN_PORT=50000 \
  -e RELAY_MAX_PORT=50100 \
  ghcr.io/slyber-app/slyber-turn-server:latest && \
  sleep 2 && \
  docker exec slyber_turn slyber_turn --version && \
  docker exec slyber_turn slyber_turn doctor && \
  HOST_IP=$([ -n "${SSH_CONNECTION:-}" ] && curl -fsSL4 --max-time 2 ifconfig.me 2>/dev/null || echo 127.0.0.1) && \
  echo "  TURN / STUN URI : turn:${HOST_IP}:3478 (UDP/TCP)" && \
  echo "  Redis Endpoint  : ${HOST_IP}:6379 (internal: slyber_redis:6379)" && \
  echo "  HTTP Health URL : http://${HOST_IP}:8080/healthz" && \
  echo "  Realm           : turn.local" && \
  echo "  Auth Mode       : redis" && \
  echo "  Inspect Keys    : docker exec slyber_redis redis-cli KEYS \"turn/realm/*\"" && \
  echo "  Live Redis Mon  : docker exec -it slyber_redis redis-cli MONITOR" && \
  echo "  Run Benchmark   : docker exec slyber_turn slyber_turn bench -clients 20 -duration 5s" && \
  echo "  Live Logs       : docker logs -f slyber_turn" && \
  echo "--------------------------------------------------"

Verify the TURN and Redis connection using the self-diagnostic utility:

Bash
docker exec slyber_turn slyber_turn doctor

Working with Redis During Testing: Where Keys Are Stored and How to Inspect Them

In AUTH_MODE="redis" mode, the server looks up keys formatted as turn/realm/<REALM>/user/<USERNAME>/key. The key value is a 32-character MD5 hash of the string <USERNAME>:<REALM>:<PASSWORD> according to RFC 5389.

1. Creating a Test User Manually

To create a user session_777 with the password pass_777 in the turn.local realm with a key TTL of 3600 seconds (1 hour), run:

On Linux:

Bash
KEY_HEX=$(printf "session_777:turn.local:pass_777" | md5sum | awk '{print $1}')
docker exec slyber_redis redis-cli SET "turn/realm/turn.local/user/session_777/key" "$KEY_HEX" EX 3600

On macOS:

Bash
KEY_HEX=$(printf "session_777:turn.local:pass_777" | md5 | tr -d ' \n')
docker exec slyber_redis redis-cli SET "turn/realm/turn.local/user/session_777/key" "$KEY_HEX" EX 3600

2. Viewing All Currently Active Users in Redis

To view the list of all accounts currently stored in the database (including peer pairs like p3_u1_da37e6 generated by the test suite):

Bash
docker exec slyber_redis redis-cli KEYS "turn/realm/*"

Example output:

Code
1) "turn/realm/turn.local/user/session_777/key"
2) "turn/realm/turn.local/user/p3_u1_da37e6/key"
3) "turn/realm/turn.local/user/p3_u2_da37e6/key"

3. Checking a Specific User Hash

To inspect the stored MD5 key for a specific user:

Bash
docker exec slyber_redis redis-cli GET "turn/realm/turn.local/user/session_777/key"

4. Checking the Remaining Key Lifetime (TTL)

To check how many seconds remain before the session is automatically removed from Redis:

Bash
docker exec slyber_redis redis-cli TTL "turn/realm/turn.local/user/session_777/key"

5. Monitoring TURN Server Requests to Redis in Real Time

To verify that the server actively queries keys from the database when establishing a call or triggering an Ice restart, start the live Redis command monitor:

Bash
docker exec -it slyber_redis redis-cli MONITOR

6. Forcibly Disconnecting a User (Key Revocation)

To revoke a user's access, delete their key:

Bash
docker exec slyber_redis redis-cli DEL "turn/realm/turn.local/user/session_777/key"

Running with Docker Compose

To launch the entire infrastructure with a single command, save the following docker-compose.yml:

YAML
services:
  slyber_redis:
    image: redis:alpine
    container_name: slyber_redis
    restart: unless-stopped
    ports:
      - "127.0.0.1:6379:6379/tcp"
    networks:
      - slyber_net

  slyber_turn:
    image: ghcr.io/slyber-app/slyber-turn-server:latest
    container_name: slyber_turn
    restart: unless-stopped
    depends_on:
      - slyber_redis
    networks:
      - slyber_net
    ports:
      - "3478:3478/udp"
      - "3478:3478/tcp"
      - "127.0.0.1:8080:8080/tcp"
      - "50000-50100:50000-50100/udp"
    environment:
      PUBLIC_IP: "auto"
      REALM: "turn.local"
      AUTH_MODE: "redis"
      REDIS_ADDR: "slyber_redis:6379"
      RELAY_MIN_PORT: "50000"
      RELAY_MAX_PORT: "50100"

networks:
  slyber_net:
    driver: bridge

Starting and stopping the stack:

Bash
docker compose up -d
docker compose down

Server Verification and Debugging Cheat Sheet

View TURN server logs in real time: Shows the PUBLIC_IP detected at startup, the active AUTH_MODE, and relay port allocation events:

Bash
docker logs -f slyber_turn

Comprehensive container self-diagnostics: Checks the availability of UDP/TCP sockets on port 3478, HTTP API on port 8080, the relay port pool, and the Redis connection:

Bash
docker exec slyber_turn slyber_turn doctor

Check mapped Docker ports on the host:

Bash
docker port slyber_turn

Check the binary version inside the image:

Bash
docker run --rm ghcr.io/slyber-app/slyber-turn-server:latest --version

Clearing All Keys in Redis Without Stopping Containers

If you need to reset all created accounts in Redis during testing and start with a clean database:

Bash
docker exec slyber_redis redis-cli FLUSHALL

Updating via docker run

Pull the latest image version from the registry:

Bash
docker pull ghcr.io/slyber-app/slyber-turn-server:latest

Remove the current slyber_turn container and recreate it using the new image:

For secret mode:

Bash
SAVED_SECRET=$(docker inspect -f '{{range .Config.Env}}{{println .}}{{end}}' slyber_turn 2>/dev/null | grep '^TURN_SECRET=' | cut -d= -f2-)

GEN_SECRET="${SAVED_SECRET:-$(head -c 16 /dev/urandom | od -An -tx1 | tr -d ' \n')}"
docker rm -f slyber_turn 2>/dev/null || true

docker run -d \
  --name slyber_turn \
  --restart unless-stopped \
  -p 3478:3478/udp \
  -p 3478:3478/tcp \
  -p 8080:8080/tcp \
  -p 50000-50100:50000-50100/udp \
  -e PUBLIC_IP="auto" \
  -e REALM="turn.local" \
  -e AUTH_MODE="secret" \
  -e TURN_SECRET="${GEN_SECRET}" \
  -e RELAY_MIN_PORT=50000 \
  -e RELAY_MAX_PORT=50100 \
  ghcr.io/slyber-app/slyber-turn-server:latest && \
  sleep 1 && \
  docker exec slyber_turn slyber_turn --version && \
  docker exec slyber_turn slyber_turn doctor && \
  HOST_IP=$([ -n "${SSH_CONNECTION:-}" ] && curl -fsSL4 --max-time 2 ifconfig.me 2>/dev/null || echo 127.0.0.1) && \
  echo "  TURN / STUN URI : turn:${HOST_IP}:3478 (UDP/TCP)" && \
  echo "  HTTP API URL    : http://${HOST_IP}:8080" && \
  echo "  Realm           : turn.local" && \
  echo "  Auth Mode       : secret (TURN_SECRET=${GEN_SECRET})" && \
  echo "  Test Creds API  : curl -s \"http://${HOST_IP}:8080/api/turn-credentials?user_id=dev\" && echo" && \
  echo "  Run Benchmark   : docker exec slyber_turn slyber_turn bench -clients 20 -duration 5s" && \
  echo "  Live Logs       : docker logs -f slyber_turn" && \
  echo "--------------------------------------------------"

For redis mode (no need to stop the slyber_redis container, all keys in the database will be preserved):

Bash
docker rm -f slyber_turn 2>/dev/null || true

docker run -d \
  --name slyber_turn \
  --restart unless-stopped \
  --network slyber_net \
  -p 3478:3478/udp \
  -p 3478:3478/tcp \
  -p 8080:8080/tcp \
  -p 50000-50100:50000-50100/udp \
  -e PUBLIC_IP="auto" \
  -e REALM="turn.local" \
  -e AUTH_MODE="redis" \
  -e REDIS_ADDR="slyber_redis:6379" \
  -e RELAY_MIN_PORT=50000 \
  -e RELAY_MAX_PORT=50100 \
  ghcr.io/slyber-app/slyber-turn-server:latest && \
  sleep 1 && \
  docker exec slyber_turn slyber_turn --version && \
  docker exec slyber_turn slyber_turn doctor && \
  HOST_IP=$([ -n "${SSH_CONNECTION:-}" ] && curl -fsSL4 --max-time 2 ifconfig.me 2>/dev/null || echo 127.0.0.1) && \
  echo "  TURN / STUN URI : turn:${HOST_IP}:3478 (UDP/TCP)" && \
  echo "  HTTP Health URL : http://${HOST_IP}:8080/healthz" && \
  echo "  Realm           : turn.local" && \
  echo "  Auth Mode       : redis (REDIS_ADDR=slyber_redis:6379)" && \
  echo "  Inspect Keys    : docker exec slyber_redis redis-cli KEYS \"turn/realm/*\"" && \
  echo "  Live Redis Mon  : docker exec -it slyber_redis redis-cli MONITOR" && \
  echo "  Run Benchmark   : docker exec slyber_turn slyber_turn bench -clients 20 -duration 5s" && \
  echo "  Live Logs       : docker logs -f slyber_turn" && \
  echo "--------------------------------------------------"

Verify that the version has been updated and the server is healthy:

Bash
docker exec slyber_turn slyber_turn --version
docker exec slyber_turn slyber_turn doctor

Environment Variables Table

VariableDefaultDescription
PUBLIC_IPautoAutomatic detection of the server's external IPv4 address (you can specify 127.0.0.1 for local tests on a single machine)
REALMturn.localAuthentication realm of the TURN server
AUTH_MODEsecretAuthentication mode: secret (HMAC-SHA1) or redis (dynamic keys in the DB)
TURN_SECRET—Secret key used to sign temporary passwords in secret mode
REDIS_ADDR127.0.0.1:6379Redis server connection address in redis mode
RELAY_MIN_PORT49152Lower bound of the UDP port range for relaying media streams
RELAY_MAX_PORT65535Upper bound of the UDP port range for relaying media streams