Skip to content

caddy/m3: trust 127.0.0.1 as a proxy for X-Forwarded-* handling#544

Merged
SuperQ merged 1 commit into
masterfrom
fix/http-x-forwarded-headers-caddy-anubis
Jun 19, 2026
Merged

caddy/m3: trust 127.0.0.1 as a proxy for X-Forwarded-* handling#544
SuperQ merged 1 commit into
masterfrom
fix/http-x-forwarded-headers-caddy-anubis

Conversation

@mcint

@mcint mcint commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Add a global servers { trusted_proxies static 127.0.0.1 } block to the m3 Caddyfile.

On m3, requests pass through a localhost proxy chain:

Internet → Caddy :443 → Anubis (unix socket) → Caddy :8080 → PHP-FPM

At each hop Caddy sets X-Real-IP / X-Forwarded-For / X-Forwarded-Proto from {remote_host} and {scheme} so the real client IP and scheme survive the chain. But since Caddy 2.7, X-Forwarded-* headers are only honored when the immediate peer is a trusted proxy; from any untrusted source they are ignored to prevent client-IP spoofing. Because the inner hops arrive over loopback, Caddy treats them as untrusted by default and the :8080 backend sees every request as coming from 127.0.0.1 — breaking access logging, geoip, and any IP-based rate limiting.

Declaring 127.0.0.1 as a trusted proxy tells Caddy to read the real client IP and scheme from the forwarded headers on loopback hops instead of falling back to the connecting address. The scope is deliberately narrow — only loopback is trusted, so externally-supplied X-Forwarded-For headers are still discarded.

Fixes #504
Fixes #543

Add a global `servers { trusted_proxies static 127.0.0.1 }` block to the
m3 Caddyfile.

On m3, requests pass through a localhost proxy chain:

    Internet → Caddy :443 → Anubis (unix socket) → Caddy :8080 → PHP-FPM

At each hop Caddy sets X-Real-IP / X-Forwarded-For / X-Forwarded-Proto
from {remote_host} and {scheme} so the real client IP and scheme survive
the chain. But since Caddy 2.7, X-Forwarded-* headers are only honored
when the immediate peer is a *trusted* proxy; from any untrusted source
they are ignored to prevent client-IP spoofing. Because the inner hops
arrive over loopback, Caddy treats them as untrusted by default and the
:8080 backend sees every request as coming from 127.0.0.1 — breaking
access logging, geoip, and any IP-based rate limiting.

Declaring 127.0.0.1 as a trusted proxy tells Caddy to read the real
client IP and scheme from the forwarded headers on loopback hops instead
of falling back to the connecting address. The scope is deliberately
narrow — only loopback is trusted, so externally-supplied
X-Forwarded-For headers are still discarded.

Fixes #504
Fixes #543
@mcint mcint requested review from ElanHR, SuperQ and patrickod June 19, 2026 08:36
@mcint

mcint commented Jun 19, 2026

Copy link
Copy Markdown
Contributor Author

It's live, tested.

@SuperQ SuperQ merged commit 816d43d into master Jun 19, 2026
1 check passed
@SuperQ SuperQ deleted the fix/http-x-forwarded-headers-caddy-anubis branch June 19, 2026 09:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Anubis config is failing to forward X-Forwarded-* headers all the way through

2 participants