A fast, interactive, and production-ready installation script for deploying a CoTURN STUN/TURN server on Ubuntu. Designed for WebRTC applications that need reliable NAT traversal.
curl -fsSL https://raw.githubusercontent.com/wwwakcan/CoTurn-WebRTC-Installer/main/coturn-setup.sh | sudo bashOr with wget:
wget -qO- https://raw.githubusercontent.com/wwwakcan/CoTurn-WebRTC-Installer/main/coturn-setup.sh | sudo bashOr manually:
git clone https://github.com/wwwakcan/CoTurn-WebRTC-Installer.git
cd CoTurn-WebRTC-Installer
sudo bash coturn-setup.sh| Feature | Description |
|---|---|
| 🧙 Interactive Wizard | Step-by-step guided setup with colored terminal UI |
| 🔍 Auto-Detection | Automatically detects public IP, CPU cores, and RAM |
| 🔐 Flexible Auth | Default admin/admin or custom credentials with auto-generated strong passwords |
| 🛡️ TLS/DTLS Support | Self-signed certificate generation or bring your own |
| 🔥 Firewall Setup | Automatic UFW configuration with all required ports |
| ✅ Verification | Post-install checks for service status, TLS, DTLS, and port availability |
| 📋 Ready-to-Use Output | Provides WebRTC iceServers JavaScript configuration |
| ⚡ Pipe-Safe | Works with `curl |
- OS: Ubuntu 20.04, 22.04, or 24.04
- Access: Root or sudo privileges
- Network: Public IP address with open ports
The script guides you through 5 simple steps:
ℹ Detected public IP: 203.0.113.50
▸ Server public IP address [203.0.113.50]:
▸ STUN/TURN port [3478]:
▸ TLS port (TURNS/DTLS) [5349]:
▸ Relay min port [30000]:
▸ Relay max port [65535]:
ℹ Credentials for clients connecting to the TURN server.
ℹ Default: admin / admin
▸ Set custom username/password? [n]: y
▸ TURN username: myuser
ℹ Auto-generated strong password: aB3$kL9m#Qx7pW2Z
▸ Use this password? [y]:
ℹ An SSL certificate is required for TURNS (TLS) and DTLS.
ℹ If you don't have one, a self-signed certificate will be generated.
▸ Do you have an existing SSL certificate? [n]:
ℹ Self-signed certificate will be generated at: /etc/turnserver.pem
ℹ Detected: 4 CPU cores, 8192 MB RAM
▸ Relay threads [4]:
▸ Max allocation lifetime (seconds) [3600]:
▸ Stale nonce duration (seconds) [600]:
┌──────────────────────────────────────────────────┐
│ │
│ Network │
│ Server IP 203.0.113.50 │
│ TURN Port 3478 │
│ TLS Port 5349 │
│ Relay Ports 30000 - 65535 │
│ │
│ Authentication │
│ Username myuser │
│ Password aB3$kL9m#Qx7pW2Z │
│ │
│ SSL/TLS │
│ Certificate /etc/turnserver.pem │
│ Private Key /etc/turnserver.key │
│ Self-signed yes │
│ │
│ Performance │
│ Threads 4 │
│ Max Lifetime 3600s │
│ Stale Nonce 600s │
│ │
└──────────────────────────────────────────────────┘
▸ Proceed with installation? [y]:
| Component | Details |
|---|---|
| CoTURN | Latest version from Ubuntu repositories |
| SSL Certificate | Self-signed (10-year validity) or custom |
| UFW Firewall | Auto-configured with all required ports |
| Systemd Service | Enabled and started automatically |
| Logging | Verbose logging to /var/log/turnserver.log |
| Port | Protocol | Purpose |
|---|---|---|
3478 |
TCP / UDP | STUN + TURN |
5349 |
TCP / UDP | TURNS (TLS) + DTLS |
30000–65535 |
TCP / UDP | Media relay |
After installation, the script outputs a ready-to-use JavaScript configuration:
const pcConfig = {
iceServers: [
{ urls: 'stun:YOUR_SERVER_IP:3478' },
{
urls: [
'turn:YOUR_SERVER_IP:3478?transport=udp',
'turn:YOUR_SERVER_IP:3478?transport=tcp',
'turns:YOUR_SERVER_IP:5349?transport=tcp'
],
username: 'YOUR_USERNAME',
credential: 'YOUR_PASSWORD'
}
]
};
const pc = new RTCPeerConnection(pcConfig);| URI | Use Case |
|---|---|
stun:IP:3478 |
Basic NAT discovery |
turn:IP:3478?transport=udp |
UDP relay — fastest |
turn:IP:3478?transport=tcp |
TCP relay — firewall-friendly |
turns:IP:5349?transport=tcp |
TLS relay — most secure, enterprise networks |
turnutils_stunclient YOUR_SERVER_IPExpected output:
INFO: IPv4. UDP reflexive addr: YOUR_CLIENT_IP:PORT
turnutils_uclient -u YOUR_USER -w YOUR_PASS -p 3478 -T YOUR_SERVER_IPExpected output:
INFO: Total lost packets 0 (0.000000%), total send dropped 0 (0.000000%)
INFO: Average round trip delay XXX ms
Test using Trickle ICE:
- Add server:
turn:YOUR_IP:3478 - Enter username and password
- Click Gather candidates
- Look for
relaytype candidates — if present, TURN is working ✅
| Command | Description |
|---|---|
systemctl status coturn |
Check service status |
systemctl restart coturn |
Restart the server |
systemctl stop coturn |
Stop the server |
tail -f /var/log/turnserver.log |
Watch live logs |
nano /etc/turnserver.conf |
Edit configuration |
| File | Purpose |
|---|---|
/etc/turnserver.conf |
Main configuration |
/etc/turnserver.pem |
SSL certificate |
/etc/turnserver.key |
SSL private key |
/var/log/turnserver.log |
Server logs |
/etc/default/coturn |
Service enable flag |
For production deployments:
- Use strong credentials — Select "yes" during setup to generate a secure password
- Use a real SSL certificate — Consider Let's Encrypt for trusted TLS
- Restrict relay IP ranges — Add
denied-peer-iprules for private networks - Monitor logs — Set up log rotation and alerting
- Keep updated —
apt update && apt upgrade coturn
# Install certbot
apt install -y certbot
# Get certificate (replace with your domain)
certbot certonly --standalone -d turn.yourdomain.com
# Update config
sed -i 's|cert=.*|cert=/etc/letsencrypt/live/turn.yourdomain.com/fullchain.pem|' /etc/turnserver.conf
sed -i 's|pkey=.*|pkey=/etc/letsencrypt/live/turn.yourdomain.com/privkey.pem|' /etc/turnserver.conf
# Restart
systemctl restart coturngrep -i "error\|warning" /var/log/turnserver.log
ss -tulnp | grep -E "3478|5349"# Fix certificate permissions
chown turnserver:turnserver /etc/turnserver.pem /etc/turnserver.key
chmod 644 /etc/turnserver.pem
chmod 600 /etc/turnserver.key
systemctl restart coturn
grep -i "tls\|dtls" /var/log/turnserver.log# Verify firewall
ufw status verbose
ufw allow 30000:65535/udp
ufw allow 30000:65535/tcp- Ensure both STUN and TURN URIs are in
iceServers - Include
transport=udp(some networks block UDP — add TCP fallback) - Add
turns:URI for enterprise/restricted networks - Check relay port range is open on firewall
Contributions are welcome! Feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License — see the LICENSE file for details.
Made with ❤️ for the WebRTC community
⭐ Star this repo if it helped you!