The home for my hosted personal solutions (syncthing, git, ntfy.sh)
Find a file
Waldson Patrício 438573ea7b Version-control the shared Caddy edge proxy
The droplet's single Caddy container terminates TLS for every site and routes
each host to its upstream over proxy_net. Until now its only copy lived on the
server; capture compose.yaml and the Caddyfile here, with a README covering how
to add a site and reload without downtime. ACME material is git-ignored.
2026-07-23 12:13:20 -03:00
.gitignore Version-control the shared Caddy edge proxy 2026-07-23 12:13:20 -03:00
Caddyfile Version-control the shared Caddy edge proxy 2026-07-23 12:13:20 -03:00
compose.yaml Version-control the shared Caddy edge proxy 2026-07-23 12:13:20 -03:00
README.md Version-control the shared Caddy edge proxy 2026-07-23 12:13:20 -03:00

central-proxy

The shared edge reverse proxy for the DigitalOcean droplet (174.138.36.232). A single Caddy container terminates TLS for every site on the box and routes each hostname to the right upstream container. It is the only thing published on ports 80 and 443; all the application stacks (bigode, nazareonline, ...) sit behind it on the external proxy_net Docker network and speak plain HTTP to it.

Caddy manages Let's Encrypt certificates automatically - it obtains and renews a cert for each hostname listed in the Caddyfile on first request. Issued certs and ACME account keys persist in the caddy_data Docker volume (mounted at /data), not in this repo.

Layout

compose.yaml   the Caddy service: publishes 80/443, joins proxy_net,
               bind-mounts the Caddyfile, persists certs in caddy_data
Caddyfile      one site block per app; each reverse_proxies to a container
               reachable by name on proxy_net

Prerequisites

  • The external network exists: docker network create proxy_net.
  • Each upstream stack attaches its public-facing container to proxy_net, so Caddy can reach it by container name (e.g. nazareonline-web-1:80).
  • DNS A records for every hostname in the Caddyfile point at the droplet.

Adding a site

Add a block to the Caddyfile naming the hostname(s) and the upstream:

www.example.com, example.com {
    reverse_proxy example-web-1:80
}

The upstream container must be on proxy_net. Caddy forwards the original Host and sets X-Forwarded-Proto: https, so upstreams behind it can rebuild HTTPS URLs and do their own host canonicalisation.

Then reload without downtime (does not disturb the other sites):

docker exec central-proxy-caddy-1 caddy reload --config /etc/caddy/Caddyfile

Validate a change before reloading:

docker run --rm -v "$PWD/Caddyfile":/etc/caddy/Caddyfile:ro caddy:2-alpine \
  caddy validate --config /etc/caddy/Caddyfile

Deploy

The compose stack lives at /home/waldson/central-proxy on the droplet. To apply a change, copy the edited Caddyfile up and reload:

scp -i ~/.ssh/deploy_key ./Caddyfile waldson@174.138.36.232:/home/waldson/central-proxy/Caddyfile
ssh -i ~/.ssh/deploy_key waldson@174.138.36.232 \
  'docker exec central-proxy-caddy-1 caddy reload --config /etc/caddy/Caddyfile'

Bring the proxy up (or recreate it after a compose change) from that directory:

docker compose up -d

Notes

  • letsencrypt/acme.json is leftover state from an earlier Traefik-based proxy and is not used by Caddy. It is git-ignored (it contains private keys); it can be deleted from the droplet once you are sure nothing references it.
  • Never docker volume rm caddy_data - that discards every issued certificate and forces re-issuance, which can hit Let's Encrypt rate limits.