caddy/m3: trust 127.0.0.1 as a proxy for X-Forwarded-* handling#544
Merged
Conversation
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
Contributor
Author
|
It's live, tested. |
SuperQ
approved these changes
Jun 19, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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:
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