# Tx OS — Caddy reverse proxy in HTTPS_MODE=auto. # # Issues + renews a real Let's Encrypt certificate for $PUBLIC_DOMAIN. # Used when the operator points a stable custom domain (e.g. # `tx.example.com`) at the box and wants automatic TLS — this keeps # iPad Web Push subscriptions valid forever, because subscriptions # are bound to the origin (host) they were created under and a stable # hostname means they never get orphaned when Tailscale or the LAN IP # changes. # # Requirements: # - PUBLIC_DOMAIN env var must be set (e.g. tx.example.com). # - DNS A/AAAA record for PUBLIC_DOMAIN points at this host. # - Ports 80 + 443 are reachable from the public internet (ACME # HTTP-01 / TLS-ALPN challenge). Behind a NAT/firewall you must # forward both. If only 443 is reachable, switch ACME to DNS-01 # by extending this file with a DNS provider plugin. # - ACME_EMAIL env var SHOULD be set for renewal notifications. # # The site MUST stay single-origin so the API session cookie # (sameSite=lax) keeps working across SPA + /api requests. { {$ACME_EMAIL_DIRECTIVE} admin off } (api_proxy) { @websocket { header Connection *Upgrade* header Upgrade websocket } reverse_proxy /api/socket.io/* api:8080 reverse_proxy /api/* api:8080 } (spa_proxy) { reverse_proxy web:80 } # ---------- HTTPS site for the public custom domain ---------- # Caddy auto-issues + renews the cert via ACME when this host is # reached over HTTPS for the first time. {$PUBLIC_DOMAIN} { encode zstd gzip import api_proxy import spa_proxy } # Plain HTTP → permanent redirect to HTTPS. Caddy still needs :80 # bound so the ACME HTTP-01 challenge can be answered. :80 { redir https://{host}{uri} permanent }