In many proxied environments (e.g. with Caddy or Nginx), Sonarr receives the client’s public IP via the X-Forwarded-For header from a trusted reverse proxy or other application, like Jellyseer. This works as expected. Sonarr logs and uses the client IP.
However, when Sonarr forwards that request downstream to other applications like Jeelyfin, it performs a new outbound HTTP request without preserving or forwarding the original X-Forwarded-For header. As a result, Jellyfin only sees the IP address of the Sonarr container or internal host.
This breaks IP attribution across the chain; logs, rate limiting, and audit trails lose the original client context. This is especially relevant in setups where multiple services (e.g. Jellyseerr → Radarr → Jellyfin) interact and decisions or logs depend on accurate IP tracing.
Why not just add another proxy?
Yes, technically a reverse proxy could be inserted in front of Sonarr to re-inject the missing headers, but doing so adds unnecessary complexity. It introduces more containers, more moving parts, and more points of failure, just to simulate a behavior that could and should be handled at the application level.
Sonarr already has access to the original request and headers. It is in the perfect position to pass that information downstream without relying on an external proxy to patch the gap.
This isn’t about offloading work to a proxy, it’s about maintaining context as a responsible link in a multi-service chain.
Proposal
Sonarr should:
- When receiving a request from a client or reverse proxy, read and store the X-Forwarded-For header, if present.
- When making API requests to the next application or services, include the same X-Forwarded-For header to preserve client identity.
- Optionally, append its own IP to the chain, in standard proxy style.
Example how the header could be assembled:
// Forward X-Forwarded-For header downstream
const response = await fetch(`http://jellyfin.internal${apiPath}`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${jellyfinApiKey}`,
'Content-Type': 'application/json',
'X-Forwarded-For': forwardedForHeader,
},
Why?
- Accurate IP logging across the media stack
- Preserves the original client identity across service boundaries
- Avoids unnecessary proxies just to inject headers
- Aligns with common web architecture best practices
Suggested config flag
To keep it optional and safe for all environments, this could be gated behind a config option like:
preserve_forwarded_ip: true
Should this for whatever reason already be possible, then disregard this request.