Files
homelab-optimized/hosts/vms/seattle/derper.yaml
Gitea Mirror Bot fb00a325d1
Some checks failed
Documentation / Build Docusaurus (push) Failing after 5m14s
Documentation / Deploy to GitHub Pages (push) Has been skipped
Sanitized mirror from private repository - 2026-04-18 11:19:59 UTC
2026-04-18 11:19:59 +00:00

48 lines
1.9 KiB
YAML

# Standalone DERP Relay Server — Seattle VPS
# =============================================================================
# Tailscale/Headscale DERP relay for external fallback connectivity.
# Serves as region 901 "Seattle VPS" in the headscale derpmap.
#
# Why standalone (not behind nginx):
# The DERP protocol does an HTTP→binary protocol switch inside TLS.
# It is incompatible with HTTP reverse proxies. Must handle TLS directly.
#
# Port layout:
# 8444/tcp — DERP relay (direct TLS, NOT proxied through nginx)
# 3478/udp — STUN (NAT traversal hints)
#
# TLS cert:
# Issued by Let's Encrypt via certbot DNS challenge (Cloudflare).
# Cert path: /etc/letsencrypt/live/derp-sea.vish.gg/
# Renewal hook at /etc/letsencrypt/renewal-hooks/deploy/derp-sea-symlinks.sh
# auto-restarts this container after renewal.
#
# UFW rules required (one-time, already applied):
# ufw allow 8444/tcp # DERP TLS
# ufw allow 3478/udp # STUN
#
# DNS: derp-sea.vish.gg → YOUR_WAN_IP (managed by ddns-updater.yaml, unproxied)
# =============================================================================
services:
derper:
image: fredliang/derper:latest
container_name: derper
restart: unless-stopped
ports:
- "8444:8444" # DERP TLS — direct, not behind nginx
- "3478:3478/udp" # STUN
volumes:
# Full letsencrypt mount required — live/ contains symlinks into archive/
# mounting only live/ breaks symlink resolution inside the container
- /etc/letsencrypt:/etc/letsencrypt:ro
environment:
- DERP_DOMAIN=derp-sea.vish.gg
- DERP_CERT_MODE=manual
- DERP_CERT_DIR=/etc/letsencrypt/live/derp-sea.vish.gg
- DERP_ADDR=:8444
- DERP_STUN=true
- DERP_STUN_PORT=3478
- DERP_HTTP_PORT=-1 # disable plain HTTP, TLS only
- DERP_VERIFY_CLIENTS=false # allow any node (headscale manages auth)