Ansible playbook for automated deployment of a coturn TURN/STUN server on Ubuntu 22.04 and 24.04 using Docker Compose.
- What the Playbook Does
- Project Structure
- Quick Start
- Server URLs
- Verification after Deployment
- Useful Commands
- Admin CLI
- Docker — checks if Docker is installed, installs it from the official repository if not
- Certbot — installs certbot and obtains a certificate via
--standalone(only whencert_source: certbot, port 80 must be free) - Files — creates
/opt/coturn/, copies configuration files, generates.envwith mode0600 - Firewall — opens ports in ufw:
80TCP (certbot only),3478UDP/TCP,5349TCP/UDP, relay port range UDP (only when ufw is active) - Start — runs
docker compose up -d - Cron — sets up certificate renewal with a deploy-hook that restarts coturn only when the certificate is actually renewed
ansible/
├── deploy.yml — main playbook
├── inventory.ini — server list
├── vars/
│ ├── main.yml — all settings (IP, domain, ports, auth, logging)
│ ├── secrets.yml — CLI password
│ └── users.yml — TURN users and passwords
├── templates/
│ └── env.j2 — .env template for coturn container
└── files/
├── coturn.conf.template — coturn configuration template
├── docker-compose.yml — Docker Compose service definition
└── entrypoint.sh — container entrypoint script
Edit inventory.ini:
[turn_servers]
turn1 ansible_host=YOUR_SERVER_IP ansible_user=root ansible_ssh_private_key_file=~/.ssh/your_keyEdit vars/main.yml. Only two parameters at the top need to be changed — everything else is derived automatically:
server_ip: "YOUR_SERVER_IP"
domain: "YOUR_DOMAIN"Certificate source (cert_source):
certbot— automatically obtain a Let's Encrypt certificate (port 80 must be free)manual— use an existing certificate (Let's Encrypt or purchased)
For manual mode, set the root directory and subdirectory containing fullchain.pem and privkey.pem:
cert_source: "manual"
manual_cert_root: "/path/to/certs/root"
manual_cert_subdir: "YOUR_DOMAIN"Works with Let's Encrypt and purchased certificates. For purchased certificates: files must be named
fullchain.pemandprivkey.pem. Symlinks are allowed if their targets are also insidemanual_cert_root.
Authentication mode (auth_mode):
password— long-term credentials, recommended for productionnoauth— open relay without credentials, for testing only
All optional settings are in vars/main.yml:
| Parameter | Default | Description |
|---|---|---|
min_port |
49152 |
Relay port range start. Each port = 1 concurrent TURN allocation |
max_port |
49452 |
Relay port range end. Total ports must be ≥ total_quota |
total_quota |
100 |
Max simultaneous TURN allocations across all users |
user_quota |
20 |
Max simultaneous TURN allocations per user |
max_bps |
0 |
Max bandwidth per allocation in bits/s. 0 = unlimited. Example: 1048576 = 1 Mbit/s |
mobility |
false |
Allow clients to change IP mid-call (e.g. WiFi → 4G). true / false |
log_level |
verbose |
Logging verbosity: normal, verbose, Verbose |
Edit vars/users.yml:
turn_users:
- username: "user1"
password: "StrongPassword1!"Edit vars/secrets.yml:
cli_password: "StrongCliPassword!"ansible-playbook -i inventory.ini deploy.yml| Protocol | URL | Description |
|---|---|---|
| STUN | stun:YOUR_DOMAIN:3478 |
STUN only, no credentials required |
| TURN | turn:YOUR_DOMAIN:3478 |
TURN over UDP, fallback to TCP automatically |
| TURN UDP | turn:YOUR_DOMAIN:3478?transport=udp |
TURN over UDP (explicit) |
| TURN TCP | turn:YOUR_DOMAIN:3478?transport=tcp |
TURN over TCP (explicit) |
| TURNS TLS | turns:YOUR_DOMAIN:5349 |
TURN over TLS (encrypted) |
Test the TURN/STUN server using Trickle ICE:
- Enter the TURN URI:
turn:YOUR_DOMAIN:3478?transport=udp - Enter TURN username and password from
vars/users.yml - Click Gather candidates
If relay candidates appear — TURN is working correctly.
# View coturn logs
docker logs -f coturn-coturn-1
# Redeploy with Ansible
ansible-playbook -i inventory.ini deploy.ymlConnect to the coturn admin interface from the server:
nc 127.0.0.1 5766Enter cli_password from vars/secrets.yml when prompted.
Available commands:
| Command | Description |
|---|---|
ps <username> |
Show active sessions for a user |
pc |
Print current configuration and allocation stats |