2026 03 20 Caddy Gateway Exposure Design
Expose Assistance Project via Remote Caddy Gateway
Date: 2026-03-20 Status: Deployed
Overview#
Expose all HTTP services in the assistance monorepo through the remote Caddy gateway at proxy using the assistance.prod.assistance.bg delegated subzone.
Dev services are exposed under assistance.dev.assistance.bg (pointing to dev ports on suse-10).
Prod Services (assistance.prod.assistance.bg)#
Dev Services (assistance.dev.assistance.bg)#
Excluded (non-HTTP / dev-only)#
- PostgreSQL (3058 prod / 3048 dev) - TCP database
- Meilisearch (3059 prod / 3049 dev) - search (internal only)
- Mailpit SMTP - dev email catcher only
DNS Architecture#
Zone hierarchy under Cloudflare-managed assistance.bg:
1assistance.bg (Cloudflare — public domain)2├── prod.assistance.bg (Linode zone, NS delegated from CF)3│ └── assistance.prod.assistance.bg (Linode subzone, NS delegated from prod)4│ ├── A @ → 139.162.191.1205│ ├── A www → 139.162.191.1206│ ├── A docs → 139.162.191.1207│ ├── A ds → 139.162.191.1208│ ├── A ui → 139.162.191.1209│ ├── A learn → 139.162.191.12010│ ├── A manager → 139.162.191.12011│ ├── A auth → 139.162.191.12012│ ├── A billing → 139.162.191.12013│ ├── A html → 139.162.191.12014│ └── A index → 139.162.191.12015├── dev.assistance.bg (Linode zone, NS delegated from CF)16│ └── assistance.dev.assistance.bg (Linode subzone, NS delegated from dev)Caddy Configuration#
All site blocks include:
import common_headers- security headersimport ip_allowlist- restrict to allowed IPsimport zone_index assistance.prod.assistance.bg- zone index at /_zonereverse_proxytosuse-10.lan.assistance.bg:<port>withimport svc_proxy
The www block acts as a unified gateway with path-based routing:
/api/auth/*→ auth-api (strip prefix)/api/billing/*→ billing-api (strip prefix)/docs*,/learn*,/design-system*,/ui-library*,/manager*→ respective apps/blog*→ blog dev server :3063 when using path-based dev access (see below)- catch-all → www
Blog at /blog on www (dev)#
The blog app uses Next.js basePath: '/blog'. If Caddy sends /blog* to suse-10.lan.assistance.bg:3063, the path must not be stripped: upstream expects /blog/_next/..., not /_next/.... Hot reload uses WebSockets (e.g. wss://www.assistance.dev.assistance.bg/blog/_next/webpack-hmr). Caddy’s reverse_proxy forwards Upgrade/Connection by default; HTTP 502 on that socket usually means the blog process is not listening on 3063, the matcher strips /blog, or a timeout closes the upgrade. Production blog is normally the separate host blog.assistance.bg (Cloudflare Workers), not a path on www.
Paste-ready Caddy fragment: docs/infrastructure/caddy-www-blog-path.caddy (adjust upstream host if Caddy and Next run on the same machine).
Individual per-service blocks also exist for direct access.
File Structure#
1192.168.3.20:/home/vchavkov/src/BA/registry/2 caddy/3 Caddyfile # All site blocks (Groups 8 + 9 for assistance)4 zones/5 assistance.prod.assistance.bg/6 index.html # Zone index listing all services7 assistance.dev.assistance.bg/8 index.html9 scripts/10 sync.sh # rsync + validate + reloadDeployment#
- Edit Caddyfile on
192.168.3.20:/home/vchavkov/src/BA/registry/caddy/Caddyfile - Run
ssh 192.168.3.20 'cd /home/vchavkov/src/BA/registry && bash scripts/sync.sh'
Constraints#
- All sites under *.prod.assistance.bg and *.dev.assistance.bg MUST have ip_allowlist
- TTL for all DNS records: 300 seconds (A records), 86400 (NS records)
- Use service registry API at 192.168.3.20:9070 for DNS (not Linode API directly)
- Never edit /etc/caddy/Caddyfile on proxy directly
- Prod ports: 13000-14000, 18080-18090 range (from podman-compose.yml)
- Dev ports: 3040-3047 range (native processes via mise)