Skip to content

[Bug]: admin cannot be created on fresh install accessed only by authenticating reverse proxy #3902

@kapsh

Description

@kapsh

I confirm that:

  • I have searched the existing open AND closed issues to see if an issue already exists for the bug I've encountered
  • I'm using the latest version (your issue may have been fixed already)

Version

0.55.1

Current Behavior

User "test1" created automatically from Remote-User header, but it is not admin.

# sqlite3 /data/navidrome.db
> select name, is_admin from user;
test1|0

Afterwards no admin can be created. Even if Navidrome accessed directly on :4533, it shows usual login prompt instead of "create admin user".

Expected Behavior

First user is created as admin (same as directly accessed setup does) or, better, Remote-Group header is checked for access control info.

Steps To Reproduce

  1. Fresh installation of Navidrome accessed only through reverse proxy.
  2. Configure ReverseProxyWhitelist to allow header authentication.
  3. Visit proxied service on localhost:8080 .

Attached compose.yml for caddy "authenticating" any user as "test1".
My actual setup I've encountered this issue on includes Caddy with full config and TLS, Authelia with group access rule, Navidrome has correct whitelist, etc. and I can provide more relevant configuration bits if needed, but this reproducible example should be close to what happens between them.

Environment

- OS:
- Browser:
- Client:

How Navidrome is installed?

Docker

Configuration

services:

  caddy:
    image: caddy:2.9
    ports:
    - "8080:80"
    command: 'caddy reverse-proxy -v -f :80 -t navidrome:4533 -H "Remote-User: test1"'

  navidrome:
    image: deluan/navidrome:0.55.1
    hostname: navidrome
    ports:
    environment:
      ND_LOGLEVEL: trace
      ND_REVERSEPROXYWHITELIST: "0.0.0.0/0"

Relevant log output

caddy-1      | {"level":"debug","ts":1743286545.2084093,"logger":"http.handlers.reverse_proxy","msg":"selected upstream","dial":"navidrome:4533","total_upstreams":1}
navidrome-1  | time="2025-03-29T22:15:45Z" level=debug msg="HTTP: GET http://localhost:8080/" elapsedTime="370.979µs" header="{\"Accept\":[\"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\"],\"Accept-Encoding\":[\"gzip, deflate, br, zstd\"],\"Accept-Language\":[\"en-US,en;q=0.7,ru;q=0.3\"],\"Dnt\":[\"1\"],\"Priority\":[\"u=0, i\"],\"Remote-User\":[\"test1\"],\"Sec-Fetch-Dest\":[\"document\"],\"Sec-Fetch-Mode\":[\"navigate\"],\"Sec-Fetch-Site\":[\"none\"],\"Sec-Fetch-User\":[\"?1\"],\"Sec-Gpc\":[\"1\"],\"Upgrade-Insecure-Requests\":[\"1\"],\"User-Agent\":[\"Mozilla/5.0 (X11; Linux x86_64; rv:136.0) Gecko/20100101 Firefox/136.0\"],\"X-Forwarded-For\":[\"172.23.0.1\"],\"X-Forwarded-Host\":[\"localhost:8080\"],\"X-Forwarded-Proto\":[\"http\"]}" httpStatus=302 remoteAddr=172.23.0.1 requestId=navidrome/UsuW7rQ1VY-000001 responseSize=28
caddy-1      | {"level":"debug","ts":1743286545.210683,"logger":"http.handlers.reverse_proxy","msg":"upstream roundtrip","upstream":"navidrome:4533","duration":0.001769134,"request":{"remote_ip":"172.23.0.1","remote_port":"51610","client_ip":"172.23.0.1","proto":"HTTP/1.1","method":"GET","host":"localhost:8080","uri":"/","headers":{"Remote-User":["test1"],"Sec-Fetch-Site":["none"],"Accept":["text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"],"Upgrade-Insecure-Requests":["1"],"Accept-Language":["en-US,en;q=0.7,ru;q=0.3"],"Sec-Fetch-User":["?1"],"User-Agent":["Mozilla/5.0 (X11; Linux x86_64; rv:136.0) Gecko/20100101 Firefox/136.0"],"Accept-Encoding":["gzip, deflate, br, zstd"],"Sec-Fetch-Dest":["document"],"X-Forwarded-Proto":["http"],"Dnt":["1"],"X-Forwarded-For":["172.23.0.1"],"X-Forwarded-Host":["localhost:8080"],"Sec-Fetch-Mode":["navigate"],"Sec-Gpc":["1"],"Priority":["u=0, i"]}},"headers":{"Content-Encoding":["gzip"],"Referrer-Policy":["same-origin"],"Vary":["Origin","Accept-Encoding"],"X-Frame-Options":["DENY"],"Date":["Sat, 29 Mar 2025 22:15:45 GMT"],"Content-Type":["text/html; charset=utf-8"],"Location":["/app/"],"Permissions-Policy":["autoplay=(), camera=(), microphone=(), usb=()"],"X-Content-Type-Options":["nosniff"],"Content-Length":["52"]},"status":302}
caddy-1      | {"level":"debug","ts":1743286545.2151804,"logger":"http.handlers.reverse_proxy","msg":"selected upstream","dial":"navidrome:4533","total_upstreams":1}
navidrome-1  | time="2025-03-29T22:15:45Z" level=trace msg="SQL: `SELECT count(distinct user.id) as count FROM user ORDER BY user.id`" args="map[]" elapsedTime="199.369µs" requestId=navidrome/UsuW7rQ1VY-000002 rowsAffected=1
navidrome-1  | time="2025-03-29T22:15:45Z" level=trace msg="Found username in ReverseProxyUserHeader" requestId=navidrome/UsuW7rQ1VY-000002 username=test1
navidrome-1  | time="2025-03-29T22:15:45Z" level=trace msg="SQL: `SELECT * FROM user WHERE user_name = {:p0} COLLATE NOCASE`" args="map[p0:test1]" elapsedTime="63.03µs" requestId=navidrome/UsuW7rQ1VY-000002 rowsAffected=0
navidrome-1  | time="2025-03-29T22:15:45Z" level=info msg="User passed in header not found" requestId=navidrome/UsuW7rQ1VY-000002 user=test1
navidrome-1  | time="2025-03-29T22:15:45Z" level=trace msg="SQL: `UPDATE user SET created_at = {:p0}, email = {:p1}, id = {:p2}, is_admin = {:p3}, last_access_at = {:p4}, last_login_at = {:p5}, name = {:p6}, password = {:p7}, updated_at = {:p8}, user_name = {:p9} WHERE id = {:p10}`" args="map[p0:0001-01-01 00:00:00 +0000 UTC p1: p10:EZC25DVem96aS5xRIcEFd8 p2:EZC25DVem96aS5xRIcEFd8 p3:false p4:<nil> p5:<nil> p6:test1 p7:g50u1bbktSY9PFc6wztNgJieVzjyjDdeRtLTUJH/nYuwdrfNabUlgpesT3MYzfDCql8ZtDx5b4hO9wpGHwkWwnbMKk8WLsg= p8:2025-03-29 22:15:45.216078627 +0000 UTC m=+17.177520962 p9:test1]" elapsedTime="138.489µs" requestId=navidrome/UsuW7rQ1VY-000002 rowsAffected=0
navidrome-1  | time="2025-03-29T22:15:45Z" level=trace msg="SQL: `INSERT INTO user (created_at,email,id,is_admin,last_access_at,last_login_at,name,password,updated_at,user_name) VALUES ({:p0},{:p1},{:p2},{:p3},{:p4},{:p5},{:p6},{:p7},{:p8},{:p9})`" args="map[p0:2025-03-29 22:15:45.216506136 +0000 UTC m=+17.177948481 p1: p2:EZC25DVem96aS5xRIcEFd8 p3:false p4:<nil> p5:<nil> p6:test1 p7:g50u1bbktSY9PFc6wztNgJieVzjyjDdeRtLTUJH/nYuwdrfNabUlgpesT3MYzfDCql8ZtDx5b4hO9wpGHwkWwnbMKk8WLsg= p8:2025-03-29 22:15:45.216078627 +0000 UTC m=+17.177520962 p9:test1]" elapsedTime="144.579µs" requestId=navidrome/UsuW7rQ1VY-000002 rowsAffected=1

Anything else?

Somewhat related to #141 LDAP or #858 OIDC or #2394 SSO support in general. Creating separate issue because this scenario leaves installation without admin account which may be confusing for first time NV-administrators.

Code of Conduct

  • I agree to follow Navidrome's Code of Conduct

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions