ProxyProtocol not visible in logs

Issue Description

Hello,
I have a visibility issue in the logs.

Expected Behavior

remote IP should be logged and the x-forwarded-for as well , same should apply for the source IP when using proxyprotocol.

Actual Behavior

Currently I only see the Proxy IP (traefik in k8s ; 10.244.0.0/16) in the logs. And blocked IPs from x-forwarded-for but not for classic logs
HTTP listeners are configured without proxyprotocol ; but x-forwarded-for is enabled for them at global level.
While others are configured with ; at listener level, not global.

Relevant Log Output

2026-05-08T07:46:08Z INFO Authentication successful (auth.success) listenerId = “imaps”, localPort = 993, remoteIp = 10.244.4.156, remotePort = 36980, accountName = “test123”, accountId = 2, id = 1, details = “Authenticated with app password”
2026-05-08T04:30:33Z INFO Blocked IP address (security.ip-blocked) listenerId = “https”, localPort = 443, remoteIp = 10.244.2.233, remotePort = 52766, listenerId = “https”, remoteIp = 195.178.110.199
2026-05-08T09:06:44Z INFO Authentication successful (auth.success) listenerId = “http”, localPort = 8080, remoteIp = 10.244.4.149, remotePort = 38538, accountName = “[email protected]”, accountId = 1

Stalwart Version

v0.16.x

Installation Method

Docker

Database Backend

PostgreSQL

Blob Storage

S3-compatible

Search Engine

PostgreSQL

Directory Backend

Internal

I have reviewed the documentation and FAQ and confirm that my issue is NOT addressed there.

on

I have searched this support forum (open and closed topics) and confirm this is not a duplicate.

on

I understand that topics in this category are triaged by a bot first but a human reply will follow up. If you’d prefer a human-only reply, add the no-ai tag to your topic.

on

Based on the docs and the reported symptoms, there are two distinct issues here:


Why the proxy IP is shown instead of the real client IP

Stalwart only replaces the connection’s remoteIp with the real client IP when both of these are true:

  1. The Proxy Protocol header is actually being sent by Traefik on that connection.
  2. Stalwart is configured to trust that source address — i.e., Traefik’s pod IP/CIDR must appear in either:
    • proxyTrustedNetworks on the global SystemSettings singleton (Settings → Network → General in the WebUI), OR
    • overrideProxyTrustedNetworks on the specific NetworkListener (Settings → Network → Listeners).

Your logs show remoteIp = 10.244.4.156 etc., which are Traefik pod IPs. This means Stalwart is receiving the connection from Traefik but is not trusting that source as a proxy — so it never reads the Proxy Protocol header and just logs Traefik’s address. The fix is to add your pod CIDR (e.g. 10.244.0.0/16) to proxyTrustedNetworks or to overrideProxyTrustedNetworks on each mail listener.


HTTP listeners and X-Forwarded-For

For the HTTP/HTTPS listeners (where Traefik is doing HTTP-mode forwarding rather than TCP passthrough), Proxy Protocol is the wrong mechanism. Instead, enable useXForwarded: true on the Http singleton (Settings → Network → HTTP → General). From the docs:

The flag should not be enabled when the proxy protocol is in use.

So for HTTP listeners: use useXForwarded, not overrideProxyTrustedNetworks. For all TCP mail listeners (SMTP, IMAPS, etc.): use Proxy Protocol + trusted networks, not useXForwarded. Mixing the two on the same listener won’t work.


Summary of required changes

Listener Mechanism Required config
http / https X-Forwarded-For Http.useXForwarded = true
smtp, imaps, etc. Proxy Protocol overrideProxyTrustedNetworks: ["10.244.0.0/16"] on each listener

Also ensure Traefik is actually emitting Proxy Protocol v2 on those TCP entrypoints — the official Stalwart Traefik example uses traefik.tcp.services.<name>.loadbalancer.proxyProtocol.version=2 labels on the Stalwart container.

See the full Traefik configuration guide and Proxy Protocol docs for reference.

This is an automated reply from the Stalwart Help Bot. Other community members may follow up if this answer is incomplete or wrong. If you found it useful, mention @helpbot in any reply to ask follow-up questions and the bot will respond again.

I confirm that 10.244.0.0/16 is set in the webui for imaps listener as **Override proxy networks.

For the proxyprotocol itself ; I have these manifests:
**
apiVersion: traefik.io/v1alpha1

kind: ServersTransportTCP

metadata:

name: proxyprotocol2

namespace: mailserver

spec:

terminationDelay: 100ms

proxyProtocol:

version: 2

apiVersion: traefik.io/v1alpha1

kind: IngressRouteTCP

metadata:

name: ingressroutetcp-imaptls

namespace: mailserver

spec:

entryPoints:

- imap

routes:

  • match: HostSNI(`*`)

    services:

    • name: stalwart

      port: 993

      nativeLB: true

      serversTransport: proxyprotocol2

You should not mix proxy protocol and X-Forwarded-For headers. If your reverse proxy supports the proxy protocol, then use that for all ports. If Stalwart is not seeing the real client IP it means that the proxy is not sending the proxy protocol header or that its IP is not in the trusted proxy network.