WebRTC Outpost
Configuration repository for a TURN relay that supports a Stoat deployment on GCP. The stack provisions a relay-main Ubuntu 24.04 instance, hardens the host with nftables, fail2ban, and unattended-upgrades, then deploys a turn-rs-based TURN server plus a Coraza-enabled Caddy service with Podman Compose. Caddy handles ACME certificate issuance, HTTPS health checks, and deny-by-default web responses on the TURN hostname. The TURN server handles STUN and TURN traffic on 3478 and TURN over TLS on 5349/TCP, reusing the certificate that Caddy stores in the shared data volume.
Repository Layout
tofu/: OpenTofu infrastructure for the static IP, VM, and GCP firewall rule.ansible/: Host preparation and hardening for Ubuntu 24.04.compose/: Runtime configuration for the TURN server and Caddy.docker/: Custom images for the TURN server wrapper and Caddy..github/workflows/: CI workflows for building images and deploying the stack.
Required GitHub Secrets
R2_ACCESS_KEY_IDR2_SECRET_ACCESS_KEYCLOUDFLARE_ACCOUNT_IDGCP_SA_KEYSSH_PRIVATE_KEYTURN_SHARED_SECRET
Recommended GitHub Variables
GCP_PROJECTGCP_REGIONGCP_ZONETURN_REALMCADDY_EMAIL
Notes
- The OpenTofu S3 backend is configured at deploy time so the Cloudflare R2 endpoint does not need to be committed to the repository.
- The Google provider reads service account credentials from the standard
GOOGLE_APPLICATION_CREDENTIALSshell environment variable. Set it to the JSON key file path for localtofuruns. - The custom TURN wrapper image is built from
ghcr.io/mycrl/turn-server:4.0.1. It waits for the Caddy-managed certificate forTURN_REALM, renders the final TOML config, and then startsturn-server. - Caddy on the relay host only answers
/healthand returns403for other HTTPS requests. TURN and STUN traffic does not pass through Caddy; the TURN server receives it directly through host networking. - The Ansible playbook lowers
net.ipv4.ip_unprivileged_port_startto80so a rootless Podman-managed Caddy container can bind to80and443.
DNS Setup
- Create a DNS
Arecord so the hostname used byTURN_REALMresolves to the OpenTofu-provisionedrelay_ip. - If you use Cloudflare, keep that record set to DNS-only. The orange-cloud proxy does not support TURN or STUN over UDP.
- Optional SRV records can advertise the default ports:
_stun._udpon3478,_turn._udpon3478, and_turns._tcpon5349for the same hostname.
Local OpenTofu Usage
Export the Google credentials path and required OpenTofu variables before running tofu locally:
export GOOGLE_APPLICATION_CREDENTIALS="secret-path"
export TF_VAR_gcp_project="your-gcp-project"
export TF_VAR_gcp_region="us-west1"
export TF_VAR_gcp_zone="us-west1-b"
cd tofu
tofu init
tofu apply
network_name defaults to default, instance_name defaults to relay-main, and admin_ssh_public_key is optional unless you want SSH access provisioned on the VM.