From bc677ff805285b9fed920f71b21d9c7ffd4cbf56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Br=C3=BCckner?= Date: Tue, 9 Jun 2026 11:39:45 +0200 Subject: [PATCH] feat(caddy): add standard forwarding headers to every reverse_proxy Every generated reverse_proxy block now emits header_up for X-Forwarded-Proto, X-Real-IP and Host. Caddy already sets the X-Forwarded-* family and Host by default; this makes them explicit and adds X-Real-IP (nginx convention) for backends that expect it. The https:// transport block is preserved alongside the headers. --- ARCHITECTURE.md | 8 ++++++-- server.ts | 12 ++++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 4f68d2a..e67fcd7 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -463,8 +463,12 @@ Manual: POST /api/semaphore/trigger/{bookingId} body { type: 'setup'|'teardown ``` buildCaddyfile(): { local_certs } # global block - per custom route { [encode] [tls internal] reverse_proxy } - upstream prefixed with https:// → reverse_proxy gets a + per custom route { [encode] [tls internal] reverse_proxy { … } } + every reverse_proxy block carries standard forwarding headers: + header_up X-Forwarded-Proto {scheme} + header_up X-Real-IP {remote_host} + header_up Host {host} + upstream prefixed with https:// → block also gets a transport http { tls_insecure_skip_verify } block (for self-signed TLS backends like Semaphore) diff --git a/server.ts b/server.ts index 030ac6a..fe9ed33 100644 --- a/server.ts +++ b/server.ts @@ -82,17 +82,21 @@ function buildCaddyfile(): string { lines.push(`${route.hostname} {`); if (route.compress) lines.push(' encode zstd gzip'); if (route.tls) lines.push(' tls internal'); + lines.push(` reverse_proxy ${route.upstream} {`); + // Standard forwarding headers for every backend. Caddy already sets the + // X-Forwarded-* family and the Host header by default; these make them + // explicit and add X-Real-IP (nginx convention) for backends that expect it. + lines.push(' header_up X-Forwarded-Proto {scheme}'); + lines.push(' header_up X-Real-IP {remote_host}'); + lines.push(' header_up Host {host}'); if (/^https:\/\//i.test(route.upstream)) { // HTTPS upstream (e.g. Semaphore) — connect over TLS and skip certificate // verification, since such backends typically use a self-signed cert. - lines.push(` reverse_proxy ${route.upstream} {`); lines.push(' transport http {'); lines.push(' tls_insecure_skip_verify'); lines.push(' }'); - lines.push(' }'); - } else { - lines.push(` reverse_proxy ${route.upstream}`); } + lines.push(' }'); lines.push('}', ''); }