Repository navigation
Auth events on HTTP layer use TCP remote IP instead of X-Forwarded-For client IP when behind reverse proxy #2806
Replies: 5 comments 8 replies
|
I see that the answer is always:
But the proxy protocol cannot and will never be able to be used on the HTTP layer. If it is enabled, the dashboard will no longer work because the dashboard expects a proxy protocol that cannot and will never be able to exist on the HTTP layer. |
|
I think I've found a solution, but I need to understand it first.
Note : 203.0.113.50 is a randome IP I use for send log hereDynamic traefik file |
🚨🚨🚨 CRITICAL NOTICE BEFORE SOLUTION 🚨🚨🚨
|
| Component | Action |
|---|---|
| Traefik | TCP router with HostSNI for dashboard mail domains, TLS passthrough, and Proxy Protocol v2 |
| Stalwart | Enable Proxy Protocol on HTTPS listener (443) and set proxy.trusted-networks to the Traefik network (e.g. 172.20.0.0/24) or Traefik’s fixed IP |
| HTTP router | Remove mail domains so dashboard traffic is only routed via TCP passthrough |
With this setup, auth.success and auth.failed will log the real client IP instead of the proxy IP when users connect to the web dashboard.
|
NOTE : Since you are a highly intelligent individual with an enormous brain and are aware that websites must always be secure, you always use websecure (443) and even your web entry point (80) has a redirection instruction to websecure, so we want to communicate with Stalwart via its HTTPS 443 port. Logically, if we do 80 (traefik)<443(traefik)<8080(Stalwart), there will be some issues with our package. Why Not Use the HTTP Port (8080) with Proxy Protocol?An alternative would be to use a TCP router with 1. HTTP/2 vs HTTP/1.1With
Modern browsers use HTTP/2 over HTTPS. The decrypted stream is therefore HTTP/2, not HTTP/1.1. Stalwart’s HTTP listener (port 8080) expects HTTP/1.1 and does not handle HTTP/2. Resulting error: The HTTP listener tries to parse the HTTP/2 preface as HTTP/1.1 and fails. 2. Why Passthrough to 443 WorksWith
The HTTPS listener is designed to support both protocols after TLS termination. 3. Summary
4. ConclusionUsing the HTTP port (8080) with Proxy Protocol is not viable because:
The solution is to use TLS passthrough to port 443, where Stalwart terminates TLS and correctly handles both HTTP/1.1 and HTTP/2. |
|
Im using traefik too, I used a version of the config found in the docs. Whilst everything mostly worked, my JMAP mail clients seemed "flakey". Having to reconnect them and not updating inboxes quickly. I followed this post to configure traefik. So now the only http router i have is for the autoconfig endpoints. Im using the tcp router for all https traffic to my mail domain. Everything seems to be running a lot more smoothly. Only thing I did that isn't on this post (but is probably implied) is setup TLS within Stalwart so Stalwart has the certs for my domain (or have I got this wrong and I dont need to do that?) Thanks for your post |



Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Issue Description
When Stalwart is behind Traefik with
http.use-x-forwarded = true, HTTP request handling correctly uses the client IP fromX-Forwarded-For/X-Real-IP, but authentication events (auth.success, auth.failed) still use the TCP remote IP (the proxy) instead of the client IP.Environment
Stalwart behind Traefik reverse proxy
http.use-x-forwarded = truein Stalwart configTraefik sends
X-Forwarded-ForandX-Real-IPheadersExpected behavior
All HTTP-related events (including auth) should use the client IP from the forwarded headers when
http.use-x-forwardedis enabled.Actual behavior:
http.request-urlcorrectly shows both IPs: TCP remote IP (proxy) and client IP from headersauth.success and auth.failed only show the TCP remote IP (proxy), not the client IP from the headers
Example logs: 203.0.113.50 Is a random IP address that I chose to anonymize my log
Correct: http.request-url shows both IPs (client IP from X-Forwarded-For is used)
Incorrect: auth.success uses only TCP layer IP (proxy), ignores X-Forwarded-For
Additional context
Other TCP protocols (SMTP, IMAP, POP3, etc.) work correctly with Proxy Protocol
Proxy Protocol is not usable for HTTP(S), so
X-Forwarded-Foris the only way to get the real client IPhttp.request-bodylogs confirm Traefik sendsX-Forwarded-ForandX-Real-IP correctlyThe issue appears limited to auth-related events, which seem to use the raw TCP remote_ip instead of the resolved client IP from the forwarded headers
And here
http.quest-bodyexemple to confirm that Traefik is sending the headers correctlyX-Forwarded-ForandX-Real-IP correctlyContext 1 : Connection on the dashboard
Context 2 : Connect with mail client to show that everything works well with TCP protocols and that Stalwart does what it should for all other sports and correctly retrieves the client's IP address.
Expected Behavior
When
http.use-x-forwarded = trueis set, Stalwart should use the client IP from thex-real-iporX-Forwarded-ForHTTP header instead of the socket source address (the proxy IP) for all events HTTP-related.Actual Behavior
No response
Reproduction Steps
No response
Relevant Log Output
No response
Stalwart Version
v0.15.x
Installation Method
Docker
Database Backend
RocksDB
Blob Storage
RocksDB
Search Engine
Internal
Directory Backend
Internal
Additional Context
No response
I acknowledge that:
traceand included relevant log output if applicable.All reactions