# Standalone DERP Relay Server — Atlantis (Home NAS) # ============================================================================= # Tailscale/Headscale DERP relay for home-network fallback connectivity. # Serves as region 902 "Home - Atlantis" 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: # 8445/tcp — DERP relay (direct TLS, NOT proxied through NPM) # 3480/udp — STUN (NAT traversal hints) # Port 3478 taken by coturn/Jitsi, 3479 taken by coturn/Matrix on matrix-ubuntu. # # TLS cert: # Issued by Let's Encrypt via certbot DNS challenge (Cloudflare). # Cert path: /volume1/docker/derper-atl/certs/ # Cloudflare credentials: /volume1/docker/derper-atl/secrets/cloudflare.ini # Auto-renewed monthly by the cert-renewer sidecar (ofelia + certbot/dns-cloudflare). # On first deploy or manual renewal, run: # docker run -it --rm \ # -v /volume1/docker/derper-atl/certs:/etc/letsencrypt \ # -v /volume1/docker/derper-atl/secrets:/root/.secrets:ro \ # certbot/dns-cloudflare certonly \ # --dns-cloudflare \ # --dns-cloudflare-credentials /root/.secrets/cloudflare.ini \ # -d derp-atl.vish.gg # Then copy certs to flat layout: # cp certs/live/derp-atl.vish.gg/fullchain.pem certs/live/derp-atl.vish.gg/derp-atl.vish.gg.crt # cp certs/live/derp-atl.vish.gg/privkey.pem certs/live/derp-atl.vish.gg/derp-atl.vish.gg.key # # Firewall / DSM rules required (one-time): # Allow inbound 8445/tcp and 3480/udp in DSM → Security → Firewall # # Router port forwards required (one-time, on home router): # 8445/tcp → 192.168.0.200 (Atlantis LAN IP, main interface) # 3480/udp → 192.168.0.200 # # DNS: derp-atl.vish.gg → home public IP (managed by dynamicdnsupdater.yaml, unproxied) # ============================================================================= services: derper-atl: image: fredliang/derper:latest container_name: derper-atl restart: unless-stopped ports: - "8445:8445" # DERP TLS — direct, not behind NPM - "3480:3480/udp" # STUN (3478 taken by coturn/Jitsi, 3479 taken by coturn/Matrix) volumes: # Full letsencrypt mount required — live/ contains symlinks into archive/ # mounting only live/ breaks symlink resolution inside the container - /volume1/docker/derper-atl/certs:/etc/letsencrypt:ro environment: - DERP_DOMAIN=derp-atl.vish.gg - DERP_CERT_MODE=manual - DERP_CERT_DIR=/etc/letsencrypt/live/derp-atl.vish.gg - DERP_ADDR=:8445 - DERP_STUN=true - DERP_STUN_PORT=3480 - DERP_HTTP_PORT=-1 # disable plain HTTP, TLS only - DERP_VERIFY_CLIENTS=false # allow any node (headscale manages auth) cert-renewer: # Runs certbot monthly via supercronic; after renewal copies certs to the # flat layout derper expects, then restarts derper-atl via Docker socket. # Schedule: 03:00 on the 1st of every month. image: certbot/dns-cloudflare:latest container_name: derper-atl-cert-renewer restart: unless-stopped depends_on: - derper-atl entrypoint: >- sh -c " apk add --no-cache supercronic curl && echo '0 3 1 * * /renew.sh' > /crontab && exec supercronic /crontab " volumes: - /var/run/docker.sock:/var/run/docker.sock - /volume1/docker/derper-atl/certs:/etc/letsencrypt - /volume1/docker/derper-atl/secrets:/root/.secrets:ro - /volume1/docker/derper-atl/renew.sh:/renew.sh:ro