# The reference TLS proxy overlay (ADR 0044's `proxy` service). Use it on top of the base: # # docker compose -f compose.yaml -f compose.proxy.yaml up -d # # Caddy terminates TLS with publicly trusted ACME certificates and publishes the deployment's only # ports. It reaches `api` and `object-storage` on the `edge` network, which this overlay creates and # attaches them to; `postgres` is never on it. # # Client addresses. Caddy is the only peer the API trusts to say who the client is: this overlay # puts the API in trusted-proxy mode for exactly the proxy's fixed address, and the Caddyfile # overwrites X-Forwarded-For with the one address Caddy resolved. Because the address must be # fixed for "only the proxy" to be expressible, `edge` has an explicit subnet whose dynamic range is # its lower half; the proxy (and the tunnel connector, if used) take addresses from the upper half, # which Docker never hands to another container. services: proxy: image: caddy:2.11.4-alpine@sha256:6aeddd44c3078b0f9a35206472a11420648a79c184603ef95957d0a20044cb2b restart: unless-stopped read_only: true tmpfs: - /tmp cap_drop: - ALL cap_add: - NET_BIND_SERVICE security_opt: - no-new-privileges:true ports: # 80 answers ACME HTTP-01 challenges and redirects everything else to HTTPS. Set # EKKLESIA_PUBLISH_ADDRESS to bind one host interface instead of all of them. - "${EKKLESIA_PUBLISH_ADDRESS:-0.0.0.0}:${EKKLESIA_HTTP_PORT:-80}:80" - "${EKKLESIA_PUBLISH_ADDRESS:-0.0.0.0}:${EKKLESIA_HTTPS_PORT:-443}:443" - "${EKKLESIA_PUBLISH_ADDRESS:-0.0.0.0}:${EKKLESIA_HTTPS_PORT:-443}:443/udp" environment: EKKLESIA_HOSTNAME: ${EKKLESIA_HOSTNAME:?EKKLESIA_HOSTNAME is required, for example ekklesia.example.org} EKKLESIA_STORAGE_HOSTNAME: ${EKKLESIA_STORAGE_HOSTNAME:?EKKLESIA_STORAGE_HOSTNAME is required, for example storage.ekklesia.example.org} # The split topology only (ADR 0045, Caddyfile.split.example), where EKKLESIA_HOSTNAME is the # API's hostname and this is the Dashboard's. Caddyfile.example ignores it; the split # configuration refuses to start without it. EKKLESIA_DASHBOARD_HOSTNAME: ${EKKLESIA_DASHBOARD_HOSTNAME:-} EKKLESIA_ACME_EMAIL: ${EKKLESIA_ACME_EMAIL:?EKKLESIA_ACME_EMAIL is required for ACME account notices} EKKLESIA_TUNNEL_ADDRESS: ${EKKLESIA_TUNNEL_ADDRESS:-10.249.250.253} volumes: - ${EKKLESIA_CADDYFILE:-./Caddyfile}:/etc/caddy/Caddyfile:ro # The installation-private CA, so Caddy can verify object-storage's certificate. - ${EKKLESIA_TLS_DIR:-/etc/ekklesia/tls}/ca.crt:/etc/caddy/ekklesia-ca.crt:ro - proxy-data:/data - proxy-config:/config networks: edge: ipv4_address: ${EKKLESIA_PROXY_ADDRESS:-10.249.250.254} depends_on: api: condition: service_healthy object-storage: condition: service_healthy api: networks: edge: {} environment: # Exactly one trusted peer: this proxy. Set here from the same variable that fixes the proxy's # address, so the two cannot drift apart. These override any value in ekklesia.env. EKKLESIA_CLIENT_ADDRESS_MODE: trusted-proxy EKKLESIA_CLIENT_ADDRESS_HEADER: x-forwarded-for EKKLESIA_CLIENT_ADDRESS_TRUSTED_PROXIES: ${EKKLESIA_PROXY_ADDRESS:-10.249.250.254}/32 object-storage: networks: edge: {} networks: edge: ipam: config: - subnet: ${EKKLESIA_EDGE_SUBNET:-10.249.250.0/24} # Docker assigns dynamic addresses only from this range. Keep the fixed proxy and tunnel # addresses outside it. ip_range: ${EKKLESIA_EDGE_DYNAMIC_RANGE:-10.249.250.0/25} volumes: proxy-data: proxy-config: