A self-hosted WebRTC TURN relay server for AndroMeld.
AndroMeld connects your phone, Mac, and browser directly via P2P whenever possible. However, some restrictive network environments (such as cellular data, corporate/campus Wi-Fi, or symmetric NATs) prevent direct peer-to-peer connections. A TURN relay server bridges the gap by relaying encrypted traffic when direct connections fail.
- End-to-End Encrypted: The relay only forwards encrypted packets and cannot inspect your data.
- On-Demand Fallback: Normal direct connections remain unchanged. The relay is only engaged when P2P fails.
| Cloudflare Workers (Recommended) | Docker (Self-Hosted) | |
|---|---|---|
| Requirements | Cloudflare account * | Linux VPS with public IPv4 + Domain name |
| Runs on | Cloudflare global edge network | Your own server |
| Cost | Free for first 1,000 GB/month | Server cost only |
* Cloudflare requires a payment method. The first 1,000 GB of traffic each month is free, $0.05/GB thereafter.
- Go to Realtime > TURN Keys in your Cloudflare dashboard.
- Click Create (any name works).
- Cloudflare will display a Key ID and an API Token. Copy both immediately (the API token is only shown once).
Click the button below to deploy to Cloudflare (this will request GitHub authorization to automatically fork and build this repository):
Enter the Key ID and API Token from step 1 when prompted, then finish the deployment.
Deploy from the command line (optional)
If you prefer a terminal, you can also deploy locally:
git clone https://github.com/heruoxin/webrtc_turn
cd webrtc_turn/cloudflare
npm install
npm run setupOnce deployed, paste the assigned *.workers.dev URL into your AndroMeld Android client, under Remote access > Relay server.
- For security, the setup page is only served for 30 minutes after a deployment (returns 404 afterward). Redeploy from your Cloudflare dashboard to open it again.
Requires a Linux server with a public IP. (Docker Desktop on macOS/Windows is not supported because coturn requires network_mode: host.)
Add an A record (e.g., turn.example.com) pointing to your server's public IP. The bundled Caddy instance automatically obtains and renews SSL certificates.
Note: AndroMeld clients support
https://only.
Ensure the following ports are open on your server firewall / cloud security group:
| Port | Protocol | Purpose |
|---|---|---|
80, 443 |
TCP | Credential API endpoint & SSL certificate issuance |
3478 |
TCP & UDP | TURN relay control connections |
49160-49200 |
UDP | TURN relayed traffic port range |
cd docker
cp .env.example .envOpen .env and fill in the values (commands to generate random secrets are included in the file comments):
PUBLIC_HOST: Your domain name (e.g.,turn.example.com)ACCESS_TOKEN: A secret access token for your endpointTURN_STATIC_SECRET: A shared static secret for coturn authentication
Start the containers:
docker compose up -dYour relay URL is ready at:
https://turn.example.com/?token=YOUR_ACCESS_TOKEN
Advanced: Enabling TURN over TLS (Port 5349)
Relay traffic on port 3478 is unencrypted at the transport level and may be blocked by strict firewalls. Port 5349 wraps TURN traffic in TLS:
- Provide valid SSL certificates on disk for coturn.
- In
docker-compose.yml, remove--no-tlsand add--tls-listening-port=5349,--cert, and--pkey. - Append
turns:${PUBLIC_HOST}:5349?transport=tcptoTURN_URLSin.env. - Remember to restart coturn when certificates renew.
Paste your relay URL into your AndroMeld Android client, under Remote access > Relay server.
Sending a GET request to your relay URL returns temporary ICE credentials valid for 24 hours:
{
"iceServers": [
{
"urls": ["turn:turn.example.com:3478?transport=udp"],
"username": "1787332426:2d81ab8fe31fe13b",
"credential": "YjHN93xmrXKuN2JnPIl1mcWgBXc="
}
],
"ttl": 86400
}- Invalid token returns
401 Unauthorized. - Any other path returns
404 Not Found.
