Some HTTP requests to Navidrome servers are issued with different host header

Issue description:

While listening to music in my car, I suddenly found my connection failing. Once I got home, I noticed that my phone’s IP address had been blocked on my firewall and digging through the logs, I found these entries in my HAProxy:

ipredacted :4231 [29/Nov/2025:13:15:01.988] http_in~ subsonic_http/subsonic:4747 0/0/0/4/4 200 1384 - - ---- 20/10/2/2/0 0/0 “GET ``https://myexternal.hostname.com/rest/getSong.view?id=ICCPUohlJNGojJ3BZ2Jyv1&u=admin&t=tredacted&s=sredacted&v=1.13.0&c=Symfonium&f=json`` HTTP/2.0”
ipredacted :4231 [29/Nov/2025:13:15:01.988] http_in~ subsonic_http/subsonic:4747 0/0/0/6/6 200 549 - - ---- 20/10/1/1/0 0/0 “GET ``https://myexternal.hostname.com/rest/scrobble.view?id=ICCPUohlJNGojJ3BZ2Jyv1&submission=false&u=admin&t=tredacted&s=sredacted&v=1.13.0&c=Symfonium&f=json`` HTTP/2.0”
ipredacted :1830 [29/Nov/2025:13:15:02.313] http_in~ default_https/ 0/-1/-1/-1/0 403 215 - - PR-- 24/12/0/0/0 0/0 “GET /rest/stream.view?id=i61Z9GAGW3hwgIPdNHz1ZQ&u=admin&t=tredacted&s=sredacted&v=1.13.0&c=Symfonium&f=json HTTP/1.1”
ipredacted :2711 [29/Nov/2025:13:15:02.331] http_in~ default_https/ 0/-1/-1/-1/0 403 215 - - PR-- 23/11/0/0/0 0/0 “GET /rest/stream.view?id=ICCPUohlJNGojJ3BZ2Jyv1&u=admin&t=tredacted&s=sredacted&v=1.13.0&c=Symfonium&f=json HTTP/1.1”

These show Symfonium accessing the server normally, but then intermittently sending HTTP requests without the hosts header, which causes the external proxy to respond with a 403 denied error, and ultimately results in the remote IP getting blacklisted as my log scanning processes assume it is attacking my webserver.

Logs:

Upload description: steltek

Additional information:

Is this potentially caused by some issue/mis-configuration in my reverse proxy? (Issuing redirects to the default host/IP?)

Reproduction steps:

  1. Host Navidrome behind HAProxy with a specific hostname and ACL rules like these:
    use_backend subsonic_http if { hdr(host) -i external.hostname.com }

(Include a default backend that returns an error.)

  1. Use Symfonium to play music. → Some requests will come in without the host header and fall through to the default backend.

Media provider:

Subsonic

Screenshots:

Only you can know exactly what happen on your specific network check their logs.

There’s no random on Symfonium. Your proxy and everything should be able to tell you exactly what happen.

Unfortunately, the entire communication between Symfonium and the proxy is encrypted with TLS1.3 making it very difficult to decrypt and read. I was hoping the debug logs would show something obvious.

On the Navidrome side, I don’t see any redirects as responses to the requests to /rest/stream at least:

GET /rest/stream.view?id=ICCPUohlJNGojJ3BZ2Jyv1&u=admin&t=tredacted&s=sredacted&v=1.13.0&c=Symfonium&f=json HTTP/1.1
host: external.hostname.com
icy-metadata: 1
range: bytes=10545824-45019909
accept-encoding: identity
user-agent: Symfonium/13.6.0a (Linux;Android 16)
x-forwarded-for: ipredacted
x-forwarded-method: GET
x-forwarded-proto: https
x-forwarded-host: external.hostname.com
x-forwarded-uri: /rest/stream.view?id=ICCPUohlJNGojJ3BZ2Jyv1&u=admin&t=tredacted&s=sredacted&v=1.13.0&c=Symfonium&f=json
connection: close


HTTP/1.1 206 Partial Content
Accept-Ranges: bytes
Content-Length: 34474086
Content-Range: bytes 10545824-45019909/45019910
Content-Type: audio/flac
Last-Modified: Fri, 05 Sep 2025 23:15:56 GMT
Permissions-Policy: autoplay=(), camera=(), microphone=(), usb=()
Referrer-Policy: same-origin
Set-Cookie: nd-player-61646d696e=c555cdb2-04c7-46fa-80db-d88ab1d00cda; Path=/; Max-Age=31536000; HttpOnly; SameSite=Strict
Vary: Origin
X-Content-Duration: 191.54
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Date: Sat, 29 Nov 2025 14:19:48 GMT
Connection: close

I do not log headers, but I’m pretty sure the underlying library is not removing the host parameter :wink:

I’m sorry but I can help debugging reverse proxy. (BTW you can read the logs yourself too)

Thanks for the info on the logs. I had forgotten that it’s possible go export them. (There’s no obvious “Logs” menu and the “Manage generated files” didn’t jump out at me.)

Just FYI, I think I’ve got it worked out. Managed to MitM Symfonium and here’s the request I see being sent that falls through to the wrong reverse proxy backend:

GET /rest/stream.view?id=ICCPUohlJNGojJ3BZ2Jyv1&u=admin&t=tredacted&s=sredacted&v=1.13.0&c=Symfonium&f=json HTTP/1.1
User-Agent: Lavf/60.16.100
Accept: */*
Range: bytes=0-
Connection: close
Host: external.hostname.com:443
Icy-MetaData: 1

My proxy config did not redirect to the correct backend when the header states “external.hostname.com:443” with the port included. (Not sure why some requests have only the hostname and others include the port, but that’s the difference that was causing me trouble.)

For anyone using HAProxy, my workaround was:

    use_backend subsonic_http if { hdr(host) -i external.hostname.com external.hostname.com:443 }

… which will now match both variants, or use this at the top of your http frontend to strip the port from the header:

    http-request set-header host %[hdr(host),field(1,:)]

(The latter only if your frontend only serves one port of course.)