From bb21f02ddeacb0a4e35a75395079438d069a7118 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jeremiah=20Men=C3=A9trey?= Date: Sun, 28 Apr 2024 02:57:01 +0200 Subject: [PATCH 01/11] Dedicated reverse proxy documentation Related to https://github.com/navidrome/navidrome/pull/2558 --- content/en/docs/Usage/reverse-proxy.md | 54 ++++++++++++++++++++++++++ content/en/docs/Usage/security.md | 21 +--------- 2 files changed, 56 insertions(+), 19 deletions(-) create mode 100644 content/en/docs/Usage/reverse-proxy.md diff --git a/content/en/docs/Usage/reverse-proxy.md b/content/en/docs/Usage/reverse-proxy.md new file mode 100644 index 00000000..86e5bd2b --- /dev/null +++ b/content/en/docs/Usage/reverse-proxy.md @@ -0,0 +1,54 @@ +--- +title: "Reverse proxy authentication" +linkTitle: "Reverse proxy authentication" +date: 2024-04-27 +weight: 60 +description: > + Delegate authentication to another system +--- + +## Configuration + +By default, reverse proxy authentication is disabled in Navidrome. To enable the feature, a trusted reverse proxy must be configured with the `ReverseProxyWhitelist` configuration option. The option takes an IPv4 or IPv6 range in CIDR notation. + +When set, Navidrome validates requests' source IP address against the `ReverseProxyWhitelist` configuration option. If the address doesn't match, reverse proxy authentication is not used even if the reverse proxy user header is present (see below), and falls back to a standard authentication mechanism. + +With reverse proxy authentication enabled, Navidrome gets the username of the authenticated user from incoming requests' `Remote-User` HTTP header. The header can be changed via the `ReverseProxyUserHeader` configuration option. + +If a user is successfully authenticated by the proxy but does not exist in the Navidrome DB, it will be created with a random password. + +### Sharing endpoint + +If you plan to use the Sharing feature, where you can create unauthenticated links to parts of your library, you'll need to whitelist `/share/*` URLs. + +### Subsonic endpoint + +The subsonic endpoint also supports reverse proxy authentication, and will ignore the subsonic authentication parameters (`u`, `p`, `t` and `s`) if the reverse proxy user header is present. If the header is absent or has an empty value, Navidrome will fall back to the standard subsonic authentication scheme. + +If your reverse proxy does not support the standard subsonic authentication scheme, or if the subsonic clients you want to use don't support an alternate authentication mechanism also supported by your proxy (such as BasicAuth), you can still configure your proxy to bypass authentication on `/rest/*` URLs and let Navidrome perform authentication for those requests. In that case, your users will have to update their (initially random) password in Navidrome, to use it with their subsonic client. + +Note that the Navidrome web app uses a mix of internal and subsonic APIs, and receives subsonic credentials from the server. It is planned to address this (TODO: Create issue and add link), but in the meantime you will need to either configure your proxy to still bypass authentication on the subsonic endpoint for the Navidrome web app, identified as the subsonic client `NavidromeUI` (`c=NavidromeUI`) and let Navidrome handle that authentication, or use your standard authentication mechanism (e.g. relying on session cookies) for that client. + +## Security considerations + +### Listening on a UNIX socket + +If you are listening on a UNIX socket, Navidrome will allow any connection to authenticate, as there is no remote IP exposed. Make sure to properly protect the socket with user access controls. + +### Reverse proxy with a dynamic IP address + +Navidrome does not support resolving hostnames in the `ReverseProxyWhitelist` configuration option. + +In scenarios where the reverse proxy has a dynamic IP address, for example if you use docker-compose, you might need to use `0.0.0.0/0` to allow requests from the reverse proxy. + +This creates an impersonation vulnerability, as Navidrome will blindly accept the value in the `Remote-User` header. For example, if you deploy multiple services with docker-compose, other services could potentially make requests to Navidrome and impersonate an admin. + +### Potential HPP vulnerability + +In the subsonic endpoint, if the reverse proxy user header is present and not empty, Navidrome will not require (if absent) and ignore (if present) the subsonic authentication parameters (`u`, `p`, `t` and `s`), so it should not be vulnerable to an HTTP Parameter Pollution vulnerability (where different systems use different credential sources to authenticate users) with respect to authentication. + +In that sense, Navidrome does not adhere strictly to the subsonic protocol, which *requires* the subsonic authentication parameters. + +It is still recommended configuring your proxy to strip those parameters from the query after the user has been authenticated to avoid potential HPP vulnerabilities in your deployment. + +Note that opensubsonic specifies (and Navidrome supports) an [HTTP form POST extension](https://opensubsonic.netlify.app/docs/extensions/formpost/), and you should also scrub the subsonic authentication parameters from the body. diff --git a/content/en/docs/Usage/security.md b/content/en/docs/Usage/security.md index 4a035675..58d314eb 100644 --- a/content/en/docs/Usage/security.md +++ b/content/en/docs/Usage/security.md @@ -30,24 +30,7 @@ in your computer, and only listen to `localhost`. This can be achieved by settin ## Reverse proxy authentication -When reverse proxy authentication is used, the verification is done by another system. By checking a specific HTTP header, -Navidrome assumes you are already authenticated. This header can be configured via `ReverseProxyUserHeader` configuration -option. By default, the `Remote-User` header is used. - -By default, Navidrome denies every attempt. Authentication proxy needs to be whitelisted in CIDR format, using -`ReverseProxyWhitelist`. Both IPv4 and IPv6 are supported. - -**NOTE**: if you are listening on a UNIX socket, Navidrome will allow any connection to authenticate, as there is no -remote IP exposed. Make sure to properly protect the socket with user access controls. - -If you enable this feature and uses a Subsonic client, you must whitelist the Subsonic API URL, as this authentication -method is incompatible with the Subsonic authentication. You will need to whitelist the `/rest/*` URLs. - -If a user is successfully authenticated by the proxy, but it does not exist in the Navidrome DB, it will be created with -a random password. The user can change this password if they plan to use a Subsonic client. - -If you plan to use the Sharing option, where you can create unauthenticated links to parts of your library, you'll -need to whitelist `/share/*` URLs. +See the dedicated section on [Reverse proxy authentication](../reverse-proxy/#security-considerations) ## Transcoding configuration @@ -69,5 +52,5 @@ don't forget to remove this option or set it to `false`. To protect against brute-force attacks, Navidrome is configured by default with a login rate limiter, It uses a [Sliding Window](https://blog.cloudflare.com/counting-things-a-lot-of-different-things/#slidingwindowstotherescue) algorithm to block too many consecutive login attempts. It is enabled by default and you don't need to do anything. -The rate limiter can be fine tuned using the flags `AuthRequestLimit` and `AuthWindowLength` and can be disabled by +The rate limiter can be fine tuned using the flags `AuthRequestLimit` and `AuthWindowLength` and can be disabled by setting `AuthRequestLimit` to `0`, though it is not recommended. From 872fcf8051e1855251fc88e9cb8077cb18a5b9b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jeremiah=20Men=C3=A9trey?= Date: Wed, 1 May 2024 03:06:49 +0200 Subject: [PATCH 02/11] Move security stuff back to the security page The security considerations are already centralized in a single page, it should not be changed for just one aspect of Navidrome. I also changed the HPP vulnerability section to make it less scary, as this is a pretty normal concern for reverse proxy authentication, and hopefully navidrome already plays nice with this. It is also not very usefull to mention hardening by stripping other credential sources without listing the sources (and I don't get exactly how all of them work yet). --- content/en/docs/Usage/reverse-proxy.md | 32 ++++++-------------------- content/en/docs/Usage/security.md | 26 +++++++++++++++++++-- 2 files changed, 31 insertions(+), 27 deletions(-) diff --git a/content/en/docs/Usage/reverse-proxy.md b/content/en/docs/Usage/reverse-proxy.md index 86e5bd2b..dd59c7b7 100644 --- a/content/en/docs/Usage/reverse-proxy.md +++ b/content/en/docs/Usage/reverse-proxy.md @@ -9,9 +9,11 @@ description: > ## Configuration -By default, reverse proxy authentication is disabled in Navidrome. To enable the feature, a trusted reverse proxy must be configured with the `ReverseProxyWhitelist` configuration option. The option takes an IPv4 or IPv6 range in CIDR notation. +By default, reverse proxy authentication is disabled. To enable the feature, either: +* Configure a trusted reverse proxy with the `ReverseProxyWhitelist` configuration option. The option takes an IPv4 or IPv6 range in CIDR notation. +* Configure a UNIX socket with the `Address` option. -When set, Navidrome validates requests' source IP address against the `ReverseProxyWhitelist` configuration option. If the address doesn't match, reverse proxy authentication is not used even if the reverse proxy user header is present (see below), and falls back to a standard authentication mechanism. +When enabled via the `ReverseProxyWhitelist` option, Navidrome validates requests' source IP address against the `ReverseProxyWhitelist` configuration option. If the address doesn't match, reverse proxy authentication is not used even if the reverse proxy user header is present (see below), and falls back to a standard authentication mechanism. With reverse proxy authentication enabled, Navidrome gets the username of the authenticated user from incoming requests' `Remote-User` HTTP header. The header can be changed via the `ReverseProxyUserHeader` configuration option. @@ -19,7 +21,7 @@ If a user is successfully authenticated by the proxy but does not exist in the N ### Sharing endpoint -If you plan to use the Sharing feature, where you can create unauthenticated links to parts of your library, you'll need to whitelist `/share/*` URLs. +If you plan to use the Sharing feature, where you can create unauthenticated links to parts of your library, you'll need to whitelist the `/share/*` URLs. ### Subsonic endpoint @@ -29,26 +31,6 @@ If your reverse proxy does not support the standard subsonic authentication sche Note that the Navidrome web app uses a mix of internal and subsonic APIs, and receives subsonic credentials from the server. It is planned to address this (TODO: Create issue and add link), but in the meantime you will need to either configure your proxy to still bypass authentication on the subsonic endpoint for the Navidrome web app, identified as the subsonic client `NavidromeUI` (`c=NavidromeUI`) and let Navidrome handle that authentication, or use your standard authentication mechanism (e.g. relying on session cookies) for that client. -## Security considerations +## Security -### Listening on a UNIX socket - -If you are listening on a UNIX socket, Navidrome will allow any connection to authenticate, as there is no remote IP exposed. Make sure to properly protect the socket with user access controls. - -### Reverse proxy with a dynamic IP address - -Navidrome does not support resolving hostnames in the `ReverseProxyWhitelist` configuration option. - -In scenarios where the reverse proxy has a dynamic IP address, for example if you use docker-compose, you might need to use `0.0.0.0/0` to allow requests from the reverse proxy. - -This creates an impersonation vulnerability, as Navidrome will blindly accept the value in the `Remote-User` header. For example, if you deploy multiple services with docker-compose, other services could potentially make requests to Navidrome and impersonate an admin. - -### Potential HPP vulnerability - -In the subsonic endpoint, if the reverse proxy user header is present and not empty, Navidrome will not require (if absent) and ignore (if present) the subsonic authentication parameters (`u`, `p`, `t` and `s`), so it should not be vulnerable to an HTTP Parameter Pollution vulnerability (where different systems use different credential sources to authenticate users) with respect to authentication. - -In that sense, Navidrome does not adhere strictly to the subsonic protocol, which *requires* the subsonic authentication parameters. - -It is still recommended configuring your proxy to strip those parameters from the query after the user has been authenticated to avoid potential HPP vulnerabilities in your deployment. - -Note that opensubsonic specifies (and Navidrome supports) an [HTTP form POST extension](https://opensubsonic.netlify.app/docs/extensions/formpost/), and you should also scrub the subsonic authentication parameters from the body. +Make sure to check the reverse proxy authentication section in the dedicated [Security Considerations](../security#reverse-proxy-authentication) page. diff --git a/content/en/docs/Usage/security.md b/content/en/docs/Usage/security.md index 58d314eb..c1434e57 100644 --- a/content/en/docs/Usage/security.md +++ b/content/en/docs/Usage/security.md @@ -26,11 +26,33 @@ behind a reverse proxy (Ex: Caddy, Nginx, Traefik, Apache) for added security, i There are tons of good resources on the web on how to properly setup a reverse proxy. When using Navidrome in such configuration, you may want to prevent Navidrome from listening to all IPs configured -in your computer, and only listen to `localhost`. This can be achieved by setting the `Address` flag to `localhost` +in your computer, and only listen to `localhost`. This can be achieved by setting the `Address` flag to `localhost`. ## Reverse proxy authentication -See the dedicated section on [Reverse proxy authentication](../reverse-proxy/#security-considerations) +When reverse proxy authentication is enabled, Navidrome trusts the reverse proxy user header (configured with the `ReverseProxyUserHeader` option, by default `Remote-User`). + +In principle, the reverse proxy user header is ignored if requests don't come from a reverse proxy trusted with the `ReverseProxyWhitelist` option. This check can however be fooled by requests with a forged source IP address if the reverse proxy can be bypassed (e.g. sent by a compromised service running next to Navidrome). + +### Listening on a UNIX socket + +If you are listening on a UNIX socket (`Address` option), Navidrome will allow any connection to authenticate using the reverse proxy user header, as there is no remote IP exposed. + +Make sure to properly protect the socket with user access controls. + +### Reverse proxy with a dynamic IP address + +Navidrome does not support resolving hostnames in the `ReverseProxyWhitelist` configuration option. + +In scenarios where the reverse proxy has a dynamic IP address, for example when you use docker, you might consider using `0.0.0.0/0` to allow requests from the reverse proxy. This essentially disables the check, so you have to make sure that only the reverse proxy can send requests to Navidrome. + +In particular with docker and docker-compose, without extra configuration containers are usually placed on the same default network and can therefore freely communicate. + +### Potential HPP vulnerability + +When reverse proxy authentication is enabled, Navidrome currently does not disable the other authentication methods. This could potentially create an HTTP Parameter Pollution vulnerability if the reverse proxy is misconfigured, or due to a bug or oversight in Navidrome. + +You should make sure that the reverse proxy user header is always set for requests against protected endpoints. As a rule of thumb, for a reverse proxy authentication setup, the only endpoints that are not protected are `/rest/*` (depending on whether your proxy can handle the subsonic authentication scheme) and `/share/*`. ## Transcoding configuration From f22aadf232e6d741d06bba4f5264f19d8e9fa504 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jeremiah=20Men=C3=A9trey?= Date: Wed, 1 May 2024 03:34:14 +0200 Subject: [PATCH 03/11] Move subsonic for the navidrome webapp to its own section --- content/en/docs/Usage/reverse-proxy.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/content/en/docs/Usage/reverse-proxy.md b/content/en/docs/Usage/reverse-proxy.md index dd59c7b7..3b48325f 100644 --- a/content/en/docs/Usage/reverse-proxy.md +++ b/content/en/docs/Usage/reverse-proxy.md @@ -19,6 +19,8 @@ With reverse proxy authentication enabled, Navidrome gets the username of the au If a user is successfully authenticated by the proxy but does not exist in the Navidrome DB, it will be created with a random password. +You might also be interested in the `EnableUserEditing` option, which allows disabling the User page that lets users change their Navidrome password. + ### Sharing endpoint If you plan to use the Sharing feature, where you can create unauthenticated links to parts of your library, you'll need to whitelist the `/share/*` URLs. @@ -29,7 +31,13 @@ The subsonic endpoint also supports reverse proxy authentication, and will ignor If your reverse proxy does not support the standard subsonic authentication scheme, or if the subsonic clients you want to use don't support an alternate authentication mechanism also supported by your proxy (such as BasicAuth), you can still configure your proxy to bypass authentication on `/rest/*` URLs and let Navidrome perform authentication for those requests. In that case, your users will have to update their (initially random) password in Navidrome, to use it with their subsonic client. -Note that the Navidrome web app uses a mix of internal and subsonic APIs, and receives subsonic credentials from the server. It is planned to address this (TODO: Create issue and add link), but in the meantime you will need to either configure your proxy to still bypass authentication on the subsonic endpoint for the Navidrome web app, identified as the subsonic client `NavidromeUI` (`c=NavidromeUI`) and let Navidrome handle that authentication, or use your standard authentication mechanism (e.g. relying on session cookies) for that client. +### Navidrome Web App + +The Navidrome web app uses a mix of internal and subsonic APIs, and receives subsonic credentials from the server to use for requests against the subsonic API. As the credentials received from the server likely won't match those in your dedicated authentication service, you need to handle subsonic requests from the Navidrome web app (identified as the subsonic client `NavidromeUI` via the `c` query parameter) in a special way. You can either: +* Ignore the subsonic authentication parameters and authenticate those requests the same way as non-subsonic requests. This relies on the fact that requests to the subsonic API will look the same to the proxy as requests to the internal API (e.g. same session cookies). +* Bypass authentication on your proxy for those requests and let Navidrome handle it. This relies on the fact that the web app receives the subsonic credentials when it loads, and it can load only if the proxy has already authenticated the user. + +Note that if you don't intend to support third-party subsonic clients, you can simply place the subsonic endpoint behind the same protection rule as the rest of the application, i.e. you don't need any special handling to bypass authentication. ## Security From 285c30516e908d16e54a39141fa13d32429177b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jeremiah=20Men=C3=A9trey?= Date: Thu, 2 May 2024 17:30:16 +0200 Subject: [PATCH 04/11] Add traefik example --- content/en/docs/Usage/reverse-proxy.md | 54 +++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/content/en/docs/Usage/reverse-proxy.md b/content/en/docs/Usage/reverse-proxy.md index 3b48325f..e3d625e7 100644 --- a/content/en/docs/Usage/reverse-proxy.md +++ b/content/en/docs/Usage/reverse-proxy.md @@ -13,7 +13,7 @@ By default, reverse proxy authentication is disabled. To enable the feature, eit * Configure a trusted reverse proxy with the `ReverseProxyWhitelist` configuration option. The option takes an IPv4 or IPv6 range in CIDR notation. * Configure a UNIX socket with the `Address` option. -When enabled via the `ReverseProxyWhitelist` option, Navidrome validates requests' source IP address against the `ReverseProxyWhitelist` configuration option. If the address doesn't match, reverse proxy authentication is not used even if the reverse proxy user header is present (see below), and falls back to a standard authentication mechanism. +When enabled via the `ReverseProxyWhitelist` option, Navidrome validates the requests' source IP address against the `ReverseProxyWhitelist` configuration option. If the address doesn't match, reverse proxy authentication is not used even if the reverse proxy user header is present (see below), and falls back to a standard authentication mechanism. With reverse proxy authentication enabled, Navidrome gets the username of the authenticated user from incoming requests' `Remote-User` HTTP header. The header can be changed via the `ReverseProxyUserHeader` configuration option. @@ -42,3 +42,55 @@ Note that if you don't intend to support third-party subsonic clients, you can s ## Security Make sure to check the reverse proxy authentication section in the dedicated [Security Considerations](../security#reverse-proxy-authentication) page. + +## Example + +In this example, Navidrome is behind the [Traefik](https://traefik.io) reverse proxy, and [Authelia](https://www.authelia.com) is used to authenticate requests, with the help of Traefik's [ForwardAuth](https://doc.traefik.io/traefik/middlewares/http/forwardauth/) middleware. Each service has its own subdomain. Docker Compose is used to deploy the whole thing. + +The Navidrome Web App uses the standard authentication page from Authelia, and subsonic clients are expected to send credentials using BasicAuth. + +This example does not go into the details of configuring Traefik, Authelia and Navidrome, but gives an overview of how those services can be integrated. If you need more details, Authelia has a pretty good documentation for integration with Traefik and other reverse proxies. Below is a `docker-compose.yml` excerpt stripped down to the relevant parts: + +```yaml +authelia: + image: authelia/authelia:4.38.8 + labels: + # The login page and user dashboard need to be reachable from the web + traefik.http.routers.authelia.rule: Host(`auth.${DOMAIN}`) + traefik.http.routers.authelia.entrypoints: https + # Standard authentication middleware to be used by web services + traefik.http.middlewares.authelia.forwardauth.address: http://authelia:9091/api/verify?rd=https://auth.${DOMAIN}/ + traefik.http.middlewares.authelia.forwardauth.authResponseHeaders: Remote-User + # Basicauth middleware for subsonic clients + traefik.http.middlewares.authelia-basicauth.forwardauth.address: http://authelia:9091/api/verify?auth=basic + traefik.http.middlewares.authelia-basicauth.forwardauth.authResponseHeaders: Remote-User + +navidrome: + image: deluan/navidrome:0.52.0 + labels: + # Default rule which uses Authelia's web-based authentication. If you enable + # navidrome's Sharing feature, you can configure Authelia to bypass + # authentication for /share/* URLs, so you don't need an extra rule here. + traefik.http.routers.navidrome.rule: Host(`music.${DOMAIN}`) + traefik.http.routers.navidrome.entrypoints: https + traefik.http.routers.navidrome.middlewares: authelia@docker + # Requests to the subsonic endpoint use the basicauth middleware, unless + # they come from the Navidrome Web App ("NavidromeUI" subsonic client), in + # which case the default authelia middleware is used. + traefik.http.routers.navidrome-subsonic.rule: Host(`music.${DOMAIN}`) && PathPrefix(`/rest/`) && !Query(`c`, `NavidromeUI`) + traefik.http.routers.navidrome-subsonic.entrypoints: https + traefik.http.routers.navidrome-subsonic.middlewares: authelia-basicauth@docker + environment: + # Navidrome does not resolve hostnames in this option, and by default + # traefik will get assigned an IP address dynamically, so all IPs must be + # trusted. + # This means that any other service in the same docker network can make + # requests to navidrome, and easily impersonate an admin. + # If you assign a static IP to your traefik service, configure it here. + ND_REVERSEPROXYWHITELIST: 0.0.0.0/0 + # Since authentication is entirely handled by Authelia, users don't need to + # manage their password in Navidrome anymore. + ND_ENABLEUSEREDITING: false +``` + +Note that only a handful of subsonic clients support BasicAuth (as it is not standardized by the subsonic specification), e.g. on Android DSub and Symfonium do, and on iOS play:Sub does. If you want to support all subsonic clients, you can have a look at the Traefik plugin [BasicAuth adapter for Subsonic](https://plugins.traefik.io/plugins/6521c6de39e2d7caa2181888/basic-auth-adapter-for-subsonic) which transforms subsonic authentication parameters into a BasicAuth header that Authelia can handle. From 53cb9fb679b12b3c15faa06ed9c31a3619aa57f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jeremiah=20Men=C3=A9trey?= Date: Sun, 5 May 2024 14:26:12 +0200 Subject: [PATCH 05/11] Add Caddy example with subsonic response rewriting --- content/en/docs/Usage/reverse-proxy.md | 78 +++++++++++++++++++++++--- 1 file changed, 71 insertions(+), 7 deletions(-) diff --git a/content/en/docs/Usage/reverse-proxy.md b/content/en/docs/Usage/reverse-proxy.md index e3d625e7..8a81ee8d 100644 --- a/content/en/docs/Usage/reverse-proxy.md +++ b/content/en/docs/Usage/reverse-proxy.md @@ -31,6 +31,12 @@ The subsonic endpoint also supports reverse proxy authentication, and will ignor If your reverse proxy does not support the standard subsonic authentication scheme, or if the subsonic clients you want to use don't support an alternate authentication mechanism also supported by your proxy (such as BasicAuth), you can still configure your proxy to bypass authentication on `/rest/*` URLs and let Navidrome perform authentication for those requests. In that case, your users will have to update their (initially random) password in Navidrome, to use it with their subsonic client. +{{< alert title="Note" >}} +Most reverse proxies and authentication services don't support the subsonic authentication scheme out of the box. + +A handful of clients claim to support BasicAuth (e.g. DSub and Symfonium on Android, and play:Sub on iOS), but even then it might not work as you expect (as it is not standardized by the subsonic specification): you will likely need to generate a subsonic error response instead of a proper BasicAuth authentication failure response. Otherwise, some clients might display an unexpected error such as "server unreachable" when the credentials are incorrect, and other clients might refuse to connect altogether even with valid credentials. +{{< /alert >}} + ### Navidrome Web App The Navidrome web app uses a mix of internal and subsonic APIs, and receives subsonic credentials from the server to use for requests against the subsonic API. As the credentials received from the server likely won't match those in your dedicated authentication service, you need to handle subsonic requests from the Navidrome web app (identified as the subsonic client `NavidromeUI` via the `c` query parameter) in a special way. You can either: @@ -43,11 +49,69 @@ Note that if you don't intend to support third-party subsonic clients, you can s Make sure to check the reverse proxy authentication section in the dedicated [Security Considerations](../security#reverse-proxy-authentication) page. -## Example +## Examples + +### Caddy with forward_auth + +In this example, Navidrome is behind the [Caddy](https://caddyserver.com) reverse proxy, and [Authentik](https://goauthentik.io) is used to authenticate requests, with the help of Caddy's [forward_auth](https://caddyserver.com/docs/caddyfile/directives/forward_auth) middleware. + +This example does not go into the details of configuring Caddy, Authentik and Navidrome, but gives an overview of how those services can be integrated. Below is a `Caddyfile` excerpt stripped down to the relevant parts: + +```Caddyfile +example.com + +reverse_proxy /outpost.goauthentik.io/* http://authentik:9000 + +@protected not path /share/* /rest/* +forward_auth @protected http://authentik:9000 { + uri /outpost.goauthentik.io/auth/caddy + copy_headers X-Authentik-Username>Remote-User +} + +# Authentik uses the Authorization header if present, so should be able to +# authenticate subsonic clients that support BasicAuth. +# If you want to have Navidrome authenticate subsonic requests, remove this +# forward_auth block. +@subsonic path /rest/* +forward_auth @subsonic http://authentik:9000 { + uri /outpost.goauthentik.io/auth/caddy + copy_headers X-Authentik-Username>Remote-User + + # Some clients that claim to support basicauth still expect a subsonic + # response in case of authentication failure instead of a proper basicauth + # response. + @error status 1xx 3xx 4xx 5xx + handle_response @error { + respond < + + + SUBSONICERR 200 + } +} + +reverse_proxy navidrome:4533 +``` + +Note that if you want to whitelist the unprotected paths as part of your Authentik configuration instead of doing it in Caddy, the `copy_headers` subdirective [won't work as expected](https://caddy.community/t/stop-copying-empty-forward-auth-header/17485): Authentik won't set the `X-Authentik-Username` header for whitelisted paths, but Caddy will still copy the header with an incorrect value. In order to make it work, you need a workaround: + +```Caddyfile +forward_auth http://authentik:9000 { + uri /outpost.goauthentik.io/auth/caddy + # copy_headers subdirective removed +} + +# Only set the Remote-User header if the request was actually authentified (user +# header set by Authentik), as opposed to whitelisted (user header not set). +@hasUsername `{http.reverse_proxy.header.X-Authentik-Username} != null` +request_header @hasUsername Remote-User {http.reverse_proxy.header.X-Authentik-Username} +``` + +### Traefik with ForwardAuth In this example, Navidrome is behind the [Traefik](https://traefik.io) reverse proxy, and [Authelia](https://www.authelia.com) is used to authenticate requests, with the help of Traefik's [ForwardAuth](https://doc.traefik.io/traefik/middlewares/http/forwardauth/) middleware. Each service has its own subdomain. Docker Compose is used to deploy the whole thing. -The Navidrome Web App uses the standard authentication page from Authelia, and subsonic clients are expected to send credentials using BasicAuth. +The Navidrome Web App uses the standard authentication page from Authelia, and there is limited support for some subsonic clients that support BasicAuth (in particular the error response rewriting in case of authentication failure is missing). This example does not go into the details of configuring Traefik, Authelia and Navidrome, but gives an overview of how those services can be integrated. If you need more details, Authelia has a pretty good documentation for integration with Traefik and other reverse proxies. Below is a `docker-compose.yml` excerpt stripped down to the relevant parts: @@ -56,10 +120,10 @@ authelia: image: authelia/authelia:4.38.8 labels: # The login page and user dashboard need to be reachable from the web - traefik.http.routers.authelia.rule: Host(`auth.${DOMAIN}`) + traefik.http.routers.authelia.rule: Host(`auth.example.com`) traefik.http.routers.authelia.entrypoints: https # Standard authentication middleware to be used by web services - traefik.http.middlewares.authelia.forwardauth.address: http://authelia:9091/api/verify?rd=https://auth.${DOMAIN}/ + traefik.http.middlewares.authelia.forwardauth.address: http://authelia:9091/api/verify?rd=https://auth.example.com/ traefik.http.middlewares.authelia.forwardauth.authResponseHeaders: Remote-User # Basicauth middleware for subsonic clients traefik.http.middlewares.authelia-basicauth.forwardauth.address: http://authelia:9091/api/verify?auth=basic @@ -71,13 +135,13 @@ navidrome: # Default rule which uses Authelia's web-based authentication. If you enable # navidrome's Sharing feature, you can configure Authelia to bypass # authentication for /share/* URLs, so you don't need an extra rule here. - traefik.http.routers.navidrome.rule: Host(`music.${DOMAIN}`) + traefik.http.routers.navidrome.rule: Host(`music.example.com`) traefik.http.routers.navidrome.entrypoints: https traefik.http.routers.navidrome.middlewares: authelia@docker # Requests to the subsonic endpoint use the basicauth middleware, unless # they come from the Navidrome Web App ("NavidromeUI" subsonic client), in # which case the default authelia middleware is used. - traefik.http.routers.navidrome-subsonic.rule: Host(`music.${DOMAIN}`) && PathPrefix(`/rest/`) && !Query(`c`, `NavidromeUI`) + traefik.http.routers.navidrome-subsonic.rule: Host(`music.example.com`) && PathPrefix(`/rest/`) && !Query(`c`, `NavidromeUI`) traefik.http.routers.navidrome-subsonic.entrypoints: https traefik.http.routers.navidrome-subsonic.middlewares: authelia-basicauth@docker environment: @@ -93,4 +157,4 @@ navidrome: ND_ENABLEUSEREDITING: false ``` -Note that only a handful of subsonic clients support BasicAuth (as it is not standardized by the subsonic specification), e.g. on Android DSub and Symfonium do, and on iOS play:Sub does. If you want to support all subsonic clients, you can have a look at the Traefik plugin [BasicAuth adapter for Subsonic](https://plugins.traefik.io/plugins/6521c6de39e2d7caa2181888/basic-auth-adapter-for-subsonic) which transforms subsonic authentication parameters into a BasicAuth header that Authelia can handle. +If you want to add support for the subsonic authentication scheme in order to support all subsonic clients, you can have a look at the Traefik plugin [BasicAuth adapter for Subsonic](https://plugins.traefik.io/plugins/6521c6de39e2d7caa2181888/basic-auth-adapter-for-subsonic) which transforms subsonic authentication parameters into a BasicAuth header that Authelia can handle. From 18057cd7fff9682aa342293065bfb5ec17db0d72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jeremiah=20Men=C3=A9trey?= Date: Sun, 5 May 2024 14:52:18 +0200 Subject: [PATCH 06/11] Rephrasing, moving info around --- content/en/docs/Usage/reverse-proxy.md | 97 +++++++++++++------------- 1 file changed, 50 insertions(+), 47 deletions(-) diff --git a/content/en/docs/Usage/reverse-proxy.md b/content/en/docs/Usage/reverse-proxy.md index 8a81ee8d..ed30478a 100644 --- a/content/en/docs/Usage/reverse-proxy.md +++ b/content/en/docs/Usage/reverse-proxy.md @@ -13,7 +13,7 @@ By default, reverse proxy authentication is disabled. To enable the feature, eit * Configure a trusted reverse proxy with the `ReverseProxyWhitelist` configuration option. The option takes an IPv4 or IPv6 range in CIDR notation. * Configure a UNIX socket with the `Address` option. -When enabled via the `ReverseProxyWhitelist` option, Navidrome validates the requests' source IP address against the `ReverseProxyWhitelist` configuration option. If the address doesn't match, reverse proxy authentication is not used even if the reverse proxy user header is present (see below), and falls back to a standard authentication mechanism. +When enabled via the `ReverseProxyWhitelist` option, Navidrome validates the requests' source IP address against range configured in `ReverseProxyWhitelist`. If the address doesn't match, reverse proxy authentication is not used even if the reverse proxy user header is present (see below), and falls back to a standard authentication mechanism. With reverse proxy authentication enabled, Navidrome gets the username of the authenticated user from incoming requests' `Remote-User` HTTP header. The header can be changed via the `ReverseProxyUserHeader` configuration option. @@ -41,7 +41,7 @@ A handful of clients claim to support BasicAuth (e.g. DSub and Symfonium on Andr The Navidrome web app uses a mix of internal and subsonic APIs, and receives subsonic credentials from the server to use for requests against the subsonic API. As the credentials received from the server likely won't match those in your dedicated authentication service, you need to handle subsonic requests from the Navidrome web app (identified as the subsonic client `NavidromeUI` via the `c` query parameter) in a special way. You can either: * Ignore the subsonic authentication parameters and authenticate those requests the same way as non-subsonic requests. This relies on the fact that requests to the subsonic API will look the same to the proxy as requests to the internal API (e.g. same session cookies). -* Bypass authentication on your proxy for those requests and let Navidrome handle it. This relies on the fact that the web app receives the subsonic credentials when it loads, and it can load only if the proxy has already authenticated the user. +* Bypass authentication on your proxy for those requests and let Navidrome handle it. This relies on the fact that the web app receives the subsonic credentials from the server when it loads, and it can load only if the proxy has already authenticated the user. Note that if you don't intend to support third-party subsonic clients, you can simply place the subsonic endpoint behind the same protection rule as the rest of the application, i.e. you don't need any special handling to bypass authentication. @@ -51,12 +51,15 @@ Make sure to check the reverse proxy authentication section in the dedicated [Se ## Examples +For the examples below, it is assumed that you are familiar with the various products in use, i.e. reverse proxy, authentication service but also Navidrome. + +The examples focus on the integration between the products, and provide configuration snippets stripped down to the relevant parts, which you can adapt to the specifics of your deployment. + ### Caddy with forward_auth In this example, Navidrome is behind the [Caddy](https://caddyserver.com) reverse proxy, and [Authentik](https://goauthentik.io) is used to authenticate requests, with the help of Caddy's [forward_auth](https://caddyserver.com/docs/caddyfile/directives/forward_auth) middleware. -This example does not go into the details of configuring Caddy, Authentik and Navidrome, but gives an overview of how those services can be integrated. Below is a `Caddyfile` excerpt stripped down to the relevant parts: - +`Caddyfile` excerpt stripped down to the relevant parts: ```Caddyfile example.com @@ -111,50 +114,50 @@ request_header @hasUsername Remote-User {http.reverse_proxy.header.X-Authentik-U In this example, Navidrome is behind the [Traefik](https://traefik.io) reverse proxy, and [Authelia](https://www.authelia.com) is used to authenticate requests, with the help of Traefik's [ForwardAuth](https://doc.traefik.io/traefik/middlewares/http/forwardauth/) middleware. Each service has its own subdomain. Docker Compose is used to deploy the whole thing. -The Navidrome Web App uses the standard authentication page from Authelia, and there is limited support for some subsonic clients that support BasicAuth (in particular the error response rewriting in case of authentication failure is missing). - -This example does not go into the details of configuring Traefik, Authelia and Navidrome, but gives an overview of how those services can be integrated. If you need more details, Authelia has a pretty good documentation for integration with Traefik and other reverse proxies. Below is a `docker-compose.yml` excerpt stripped down to the relevant parts: +The error response rewriting for subsonic authentication failure is not implemented, which means that subsonic clients are expected to handle correctly BasicAuth error responses (HTTP 401 with `WWW-Authenticate` header). +`docker-compose.yml` excerpt stripped down to the relevant parts: ```yaml -authelia: - image: authelia/authelia:4.38.8 - labels: - # The login page and user dashboard need to be reachable from the web - traefik.http.routers.authelia.rule: Host(`auth.example.com`) - traefik.http.routers.authelia.entrypoints: https - # Standard authentication middleware to be used by web services - traefik.http.middlewares.authelia.forwardauth.address: http://authelia:9091/api/verify?rd=https://auth.example.com/ - traefik.http.middlewares.authelia.forwardauth.authResponseHeaders: Remote-User - # Basicauth middleware for subsonic clients - traefik.http.middlewares.authelia-basicauth.forwardauth.address: http://authelia:9091/api/verify?auth=basic - traefik.http.middlewares.authelia-basicauth.forwardauth.authResponseHeaders: Remote-User - -navidrome: - image: deluan/navidrome:0.52.0 - labels: - # Default rule which uses Authelia's web-based authentication. If you enable - # navidrome's Sharing feature, you can configure Authelia to bypass - # authentication for /share/* URLs, so you don't need an extra rule here. - traefik.http.routers.navidrome.rule: Host(`music.example.com`) - traefik.http.routers.navidrome.entrypoints: https - traefik.http.routers.navidrome.middlewares: authelia@docker - # Requests to the subsonic endpoint use the basicauth middleware, unless - # they come from the Navidrome Web App ("NavidromeUI" subsonic client), in - # which case the default authelia middleware is used. - traefik.http.routers.navidrome-subsonic.rule: Host(`music.example.com`) && PathPrefix(`/rest/`) && !Query(`c`, `NavidromeUI`) - traefik.http.routers.navidrome-subsonic.entrypoints: https - traefik.http.routers.navidrome-subsonic.middlewares: authelia-basicauth@docker - environment: - # Navidrome does not resolve hostnames in this option, and by default - # traefik will get assigned an IP address dynamically, so all IPs must be - # trusted. - # This means that any other service in the same docker network can make - # requests to navidrome, and easily impersonate an admin. - # If you assign a static IP to your traefik service, configure it here. - ND_REVERSEPROXYWHITELIST: 0.0.0.0/0 - # Since authentication is entirely handled by Authelia, users don't need to - # manage their password in Navidrome anymore. - ND_ENABLEUSEREDITING: false +services: + authelia: + image: authelia/authelia:4.38.8 + labels: + # The login page and user dashboard need to be reachable from the web + traefik.http.routers.authelia.rule: Host(`auth.example.com`) + traefik.http.routers.authelia.entrypoints: https + # Standard authentication middleware to be used by web services + traefik.http.middlewares.authelia.forwardauth.address: http://authelia:9091/api/verify?rd=https://auth.example.com/ + traefik.http.middlewares.authelia.forwardauth.authResponseHeaders: Remote-User + # Basicauth middleware for subsonic clients + traefik.http.middlewares.authelia-basicauth.forwardauth.address: http://authelia:9091/api/verify?auth=basic + traefik.http.middlewares.authelia-basicauth.forwardauth.authResponseHeaders: Remote-User + + navidrome: + image: deluan/navidrome:0.52.0 + labels: + # Default rule which uses Authelia's web-based authentication. If you enable + # navidrome's Sharing feature, you can configure Authelia to bypass + # authentication for /share/* URLs, so you don't need an extra rule here. + traefik.http.routers.navidrome.rule: Host(`music.example.com`) + traefik.http.routers.navidrome.entrypoints: https + traefik.http.routers.navidrome.middlewares: authelia@docker + # Requests to the subsonic endpoint use the basicauth middleware, unless + # they come from the Navidrome Web App ("NavidromeUI" subsonic client), in + # which case the default authelia middleware is used. + traefik.http.routers.navidrome-subsonic.rule: Host(`music.example.com`) && PathPrefix(`/rest/`) && !Query(`c`, `NavidromeUI`) + traefik.http.routers.navidrome-subsonic.entrypoints: https + traefik.http.routers.navidrome-subsonic.middlewares: authelia-basicauth@docker + environment: + # Navidrome does not resolve hostnames in this option, and by default + # traefik will get assigned an IP address dynamically, so all IPs must be + # trusted. + # This means that any other service in the same docker network can make + # requests to navidrome, and easily impersonate an admin. + # If you assign a static IP to your traefik service, configure it here. + ND_REVERSEPROXYWHITELIST: 0.0.0.0/0 + # Since authentication is entirely handled by Authelia, users don't need to + # manage their password in Navidrome anymore. + ND_ENABLEUSEREDITING: false ``` -If you want to add support for the subsonic authentication scheme in order to support all subsonic clients, you can have a look at the Traefik plugin [BasicAuth adapter for Subsonic](https://plugins.traefik.io/plugins/6521c6de39e2d7caa2181888/basic-auth-adapter-for-subsonic) which transforms subsonic authentication parameters into a BasicAuth header that Authelia can handle. +If you want to add support for the subsonic authentication scheme in order to support all subsonic clients, you can have a look at the Traefik plugin [BasicAuth adapter for Subsonic](https://plugins.traefik.io/plugins/6521c6de39e2d7caa2181888/basic-auth-adapter-for-subsonic) which transforms subsonic authentication parameters into a BasicAuth header that Authelia can handle, and performs the error response rewriting. From 5aa822ae4d3b0d71c84cb0d9763420e11bb2a075 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jeremiah=20Men=C3=A9trey?= Date: Sun, 5 May 2024 18:04:06 +0200 Subject: [PATCH 07/11] Add links in the main options page --- .../en/docs/Usage/configuration-options.md | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/content/en/docs/Usage/configuration-options.md b/content/en/docs/Usage/configuration-options.md index 3e5781e5..03d15565 100644 --- a/content/en/docs/Usage/configuration-options.md +++ b/content/en/docs/Usage/configuration-options.md @@ -105,16 +105,16 @@ make it all uppercase. Ex: `ND_LOGLEVEL=debug`. See below for all available opti ### Basic configuration -| In config file | As an env var | Description | Default Value | -|----------------|------------------|-------------------------------------------------------------------------------------------------------------------|------------------------------| -| | `ND_CONFIGFILE` | Load configurations from an external config file | `"./navidrome.toml"` | -| MusicFolder | `ND_MUSICFOLDER` | Folder where your music library is stored. Can be read-only | `"./music"` | -| DataFolder | `ND_DATAFOLDER` | Folder to store application data (DB) | `"./data"` | -| CacheFolder | `ND_CACHEFOLDER` | Folder to store cache data (transcoding, images...) | `"/cache"` | -| LogLevel | `ND_LOGLEVEL` | Log level. Useful for troubleshooting. Possible values: `error`, `warn`, `info`, `debug`, `trace` | `"info"` | -| Address | `ND_ADDRESS` | Address the server will bind to. Can be an IPv4 or IPv6. Also supports `unix:/path/to/file` for Unix socket files | `0.0.0.0` and `::` (all IPs) | -| BaseUrl | `ND_BASEURL` | Base URL to configure Navidrome behind a proxy (examples: `/music`, `https://music.example.com`) | _Empty_ | -| Port | `ND_PORT` | HTTP port Navidrome will use | `4533` | +| In config file | As an env var | Description | Default Value | +|----------------|------------------|-------------------------------------------------------------------------------------------------------------------------------------------|------------------------------| +| | `ND_CONFIGFILE` | Load configurations from an external config file | `"./navidrome.toml"` | +| MusicFolder | `ND_MUSICFOLDER` | Folder where your music library is stored. Can be read-only | `"./music"` | +| DataFolder | `ND_DATAFOLDER` | Folder to store application data (DB) | `"./data"` | +| CacheFolder | `ND_CACHEFOLDER` | Folder to store cache data (transcoding, images...) | `"/cache"` | +| LogLevel | `ND_LOGLEVEL` | Log level. Useful for troubleshooting. Possible values: `error`, `warn`, `info`, `debug`, `trace` | `"info"` | +| Address | `ND_ADDRESS` | Address the server will bind to. Can be an IPv4 or IPv6. Also supports `unix:/path/to/file` for Unix socket files[\*][reverse-proxy-auth] | `0.0.0.0` and `::` (all IPs) | +| BaseUrl | `ND_BASEURL` | Base URL to configure Navidrome behind a proxy (examples: `/music`, `https://music.example.com`) | _Empty_ | +| Port | `ND_PORT` | HTTP port Navidrome will use | `4533` | ### Advanced configuration @@ -166,8 +166,8 @@ make it all uppercase. Ex: `ND_LOGLEVEL=debug`. See below for all available opti | Prometheus.Enabled | `ND_PROMETHEUS_ENABLED` | Enable extra endpoint with [Prometheus](https://prometheus.io/docs/introduction/overview/) metrics. | `false` | | Prometheus.MetricsPath | `ND_PROMETHEUS_METRICSPATH` | Custom path for Prometheus metrics. Useful for blocking unauthorized metrics requests. | `"/metrics"` | | RecentlyAddedByModTime | `ND_RECENTLYADDEDBYMODTIME` | Uses music files' modification time when sorting by "Recently Added". Otherwise use import time | `false` | -| ReverseProxyUserHeader[\*][reverse-proxy-auth] | `ND_REVERSEPROXYUSERHEADER` | HTTP header containing user name from authenticated proxy | `"Remote-User"` | -| ReverseProxyWhitelist[\*][reverse-proxy-auth] | `ND_REVERSEPROXYWHITELIST` | Comma separated list of IP CIDRs which are allowed to use reverse proxy authentication, empty means "deny all" | _Empty_ | +| ReverseProxyUserHeader[\*][reverse-proxy-auth] | `ND_REVERSEPROXYUSERHEADER` | HTTP header containing user name from authenticated proxy. Click [here][reverse-proxy-config] for details | `"Remote-User"` | +| ReverseProxyWhitelist[\*][reverse-proxy-auth] | `ND_REVERSEPROXYWHITELIST` | Comma separated list of IP CIDRs which are allowed to use reverse proxy authentication, empty means "deny all". Click [here][reverse-proxy-config] for details | _Empty_ | | Scanner.Extractor[\*][extractors] | `ND_SCANNER_EXTRACTOR` | Select metadata extractor implementation. Options: `taglib` or `ffmpeg` | `"taglib"` | | Scanner.GenreSeparators | `ND_SCANNER_GENRESEPARATORS` | List of separators to split genre tags | `";/,"` | | Scanner.GroupAlbumReleases | `ND_SCANNER_GROUPALBUMRELEASES` | "true" groups albums with the same Artist + Album Title as one album; "false" splits re-issues (=different Release Date) into separate albums | `false` | @@ -203,8 +203,9 @@ make it all uppercase. Ex: `ND_LOGLEVEL=debug`. See below for all available opti [lastfm-integration]: /docs/usage/external-integrations/#lastfm [encrypt-passwords]: /docs/usage/security/#encrypted-passwords [reverse-proxy-auth]: /docs/usage/security/#reverse-proxy-authentication +[reverse-proxy-config]: /docs/usage/reverse-proxy [albumcoverart]: /docs/usage/artwork/#albums -[artistcoverart]: /docs/usage/artwork/#artists +[artistcoverart]: /docs/usage/artwork/#artists [mediafilecoverart]: /docs/usage/artwork/#mediafiles [jukebox-mode]: /docs/usage/jukebox [jukebox-config]: /docs/usage/jukebox/#configuration From 06417bdfbaf8e9c3d563547fa8d6e9cccbd356a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jeremiah=20Men=C3=A9trey?= Date: Sun, 5 May 2024 19:11:18 +0200 Subject: [PATCH 08/11] Clarifications for the Navidrome Web App --- content/en/docs/Usage/reverse-proxy.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/content/en/docs/Usage/reverse-proxy.md b/content/en/docs/Usage/reverse-proxy.md index ed30478a..1d5da5bc 100644 --- a/content/en/docs/Usage/reverse-proxy.md +++ b/content/en/docs/Usage/reverse-proxy.md @@ -13,7 +13,7 @@ By default, reverse proxy authentication is disabled. To enable the feature, eit * Configure a trusted reverse proxy with the `ReverseProxyWhitelist` configuration option. The option takes an IPv4 or IPv6 range in CIDR notation. * Configure a UNIX socket with the `Address` option. -When enabled via the `ReverseProxyWhitelist` option, Navidrome validates the requests' source IP address against range configured in `ReverseProxyWhitelist`. If the address doesn't match, reverse proxy authentication is not used even if the reverse proxy user header is present (see below), and falls back to a standard authentication mechanism. +When enabled via the `ReverseProxyWhitelist` option, Navidrome validates the requests' source IP address against the range configured in `ReverseProxyWhitelist`. If the address doesn't match, reverse proxy authentication is not used even if the reverse proxy user header is present (see below), and falls back to a standard authentication mechanism. With reverse proxy authentication enabled, Navidrome gets the username of the authenticated user from incoming requests' `Remote-User` HTTP header. The header can be changed via the `ReverseProxyUserHeader` configuration option. @@ -72,7 +72,8 @@ forward_auth @protected http://authentik:9000 { } # Authentik uses the Authorization header if present, so should be able to -# authenticate subsonic clients that support BasicAuth. +# authenticate subsonic clients that support BasicAuth. Requests from the +# Navidrome Web App will be authenticated via the existing session cookie. # If you want to have Navidrome authenticate subsonic requests, remove this # forward_auth block. @subsonic path /rest/* From d1736bdfbb5ebcec406dc2d71f923ea7e3d331bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jeremiah=20Men=C3=A9trey?= Date: Mon, 30 Sep 2024 23:52:31 +0200 Subject: [PATCH 09/11] Update documentation for explicit socket auth config Related to navidrome/navidrome#3046 and navidrome/navidrome#3062. --- .../en/docs/Usage/configuration-options.md | 24 +++++++++---------- content/en/docs/Usage/reverse-proxy.md | 8 +++---- content/en/docs/Usage/security.md | 4 ++-- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/content/en/docs/Usage/configuration-options.md b/content/en/docs/Usage/configuration-options.md index d5293d84..c9395787 100644 --- a/content/en/docs/Usage/configuration-options.md +++ b/content/en/docs/Usage/configuration-options.md @@ -105,16 +105,16 @@ make it all uppercase. Ex: `ND_LOGLEVEL=debug`. See below for all available opti ### Basic configuration -| In config file | As an env var | Description | Default Value | -|----------------|------------------|-------------------------------------------------------------------------------------------------------------------------------------------|------------------------------| -| | `ND_CONFIGFILE` | Load configurations from an external config file | `"./navidrome.toml"` | -| MusicFolder | `ND_MUSICFOLDER` | Folder where your music library is stored. Can be read-only | `"./music"` | -| DataFolder | `ND_DATAFOLDER` | Folder to store application data (DB) | `"./data"` | -| CacheFolder | `ND_CACHEFOLDER` | Folder to store cache data (transcoding, images...) | `"/cache"` | -| LogLevel | `ND_LOGLEVEL` | Log level. Useful for troubleshooting. Possible values: `error`, `warn`, `info`, `debug`, `trace` | `"info"` | -| Address | `ND_ADDRESS` | Address the server will bind to. Can be an IPv4 or IPv6. Also supports `unix:/path/to/file` for Unix socket files[\*][reverse-proxy-auth] | `0.0.0.0` and `::` (all IPs) | -| BaseUrl | `ND_BASEURL` | Base URL to configure Navidrome behind a proxy (examples: `/music`, `https://music.example.com`) | _Empty_ | -| Port | `ND_PORT` | HTTP port Navidrome will use | `4533` | +| In config file | As an env var | Description | Default Value | +|----------------|------------------|----------------------------------------------------------------------------------------------------|------------------------------| +| | `ND_CONFIGFILE` | Load configurations from an external config file | `"./navidrome.toml"` | +| MusicFolder | `ND_MUSICFOLDER` | Folder where your music library is stored. Can be read-only | `"./music"` | +| DataFolder | `ND_DATAFOLDER` | Folder to store application data (DB) | `"./data"` | +| CacheFolder | `ND_CACHEFOLDER` | Folder to store cache data (transcoding, images...) | `"/cache"` | +| LogLevel | `ND_LOGLEVEL` | Log level. Useful for troubleshooting. Possible values: `error`, `warn`, `info`, `debug`, `trace` | `"info"` | +| Address | `ND_ADDRESS` | Address the server will bind to. Can be an IPv4, IPv6 or a UNIX socket file (`unix:/path/to/file`) | `0.0.0.0` and `::` (all IPs) | +| BaseUrl | `ND_BASEURL` | Base URL to configure Navidrome behind a proxy (examples: `/music`, `https://music.example.com`) | _Empty_ | +| Port | `ND_PORT` | HTTP port Navidrome will use | `4533` | ### Advanced configuration @@ -171,7 +171,7 @@ make it all uppercase. Ex: `ND_LOGLEVEL=debug`. See below for all available opti | Prometheus.MetricsPath | `ND_PROMETHEUS_METRICSPATH` | Custom path for Prometheus metrics. Useful for blocking unauthorized metrics requests. | `"/metrics"` | | RecentlyAddedByModTime | `ND_RECENTLYADDEDBYMODTIME` | Uses music files' modification time when sorting by "Recently Added". Otherwise use import time | `false` | | ReverseProxyUserHeader[\*][reverse-proxy-auth] | `ND_REVERSEPROXYUSERHEADER` | HTTP header containing user name from authenticated proxy. Click [here][reverse-proxy-config] for details | `"Remote-User"` | -| ReverseProxyWhitelist[\*][reverse-proxy-auth] | `ND_REVERSEPROXYWHITELIST` | Comma separated list of IP CIDRs which are allowed to use reverse proxy authentication, empty means "deny all". Click [here][reverse-proxy-config] for details | _Empty_ | +| ReverseProxyWhitelist[\*][reverse-proxy-auth] | `ND_REVERSEPROXYWHITELIST` | Comma separated list of IP CIDRs (or when listening on a UNIX socket the special value `@`) which are allowed to use reverse proxy authentication. Empty means "deny all". Click [here][reverse-proxy-config] for details | _Empty_ | | Scanner.Extractor[\*][extractors] | `ND_SCANNER_EXTRACTOR` | Select metadata extractor implementation. Options: `taglib` or `ffmpeg` | `"taglib"` | | Scanner.GenreSeparators | `ND_SCANNER_GENRESEPARATORS` | List of separators to split genre tags | `";/,"` | | Scanner.GroupAlbumReleases | `ND_SCANNER_GROUPALBUMRELEASES` | "true" groups albums with the same Artist + Album Title as one album; "false" splits re-issues (=different Release Date) into separate albums | `false` | @@ -208,7 +208,7 @@ make it all uppercase. Ex: `ND_LOGLEVEL=debug`. See below for all available opti [spotify-integration]: /docs/usage/external-integrations/#spotify [lastfm-integration]: /docs/usage/external-integrations/#lastfm [encrypt-passwords]: /docs/usage/security/#encrypted-passwords -[reverse-proxy-auth]: /docs/usage/security/#reverse-proxy-authentication +[reverse-proxy-auth]: /docs/usage/security/#reverse-proxy-authentication "Reverse Proxy Authentication" [reverse-proxy-config]: /docs/usage/reverse-proxy [albumcoverart]: /docs/usage/artwork/#albums [artistcoverart]: /docs/usage/artwork/#artists diff --git a/content/en/docs/Usage/reverse-proxy.md b/content/en/docs/Usage/reverse-proxy.md index 1d5da5bc..ce2f7281 100644 --- a/content/en/docs/Usage/reverse-proxy.md +++ b/content/en/docs/Usage/reverse-proxy.md @@ -9,11 +9,11 @@ description: > ## Configuration -By default, reverse proxy authentication is disabled. To enable the feature, either: -* Configure a trusted reverse proxy with the `ReverseProxyWhitelist` configuration option. The option takes an IPv4 or IPv6 range in CIDR notation. -* Configure a UNIX socket with the `Address` option. +By default, reverse proxy authentication is disabled. To enable the feature, configure a trusted reverse proxy with the `ReverseProxyWhitelist` option. This option takes a comma-separated list of either: +* An IPv4 or IPv6 range in CIDR notation. +* An `@` (at sign) when listening on a UNIX socket (see the `Address` option). -When enabled via the `ReverseProxyWhitelist` option, Navidrome validates the requests' source IP address against the range configured in `ReverseProxyWhitelist`. If the address doesn't match, reverse proxy authentication is not used even if the reverse proxy user header is present (see below), and falls back to a standard authentication mechanism. +When enabled via the `ReverseProxyWhitelist` option, Navidrome validates the requests' source IP address against the ranges configured in `ReverseProxyWhitelist`. If the address doesn't match, reverse proxy authentication is not used even if the reverse proxy user header is present (see below), and falls back to a standard authentication mechanism. For requests received through a UNIX socket, IPs can't be validated and Navidrome will use the reverse proxy user header if and only if `ReverseProxyWhitelist` contains `@`. With reverse proxy authentication enabled, Navidrome gets the username of the authenticated user from incoming requests' `Remote-User` HTTP header. The header can be changed via the `ReverseProxyUserHeader` configuration option. diff --git a/content/en/docs/Usage/security.md b/content/en/docs/Usage/security.md index c1434e57..1b24c16a 100644 --- a/content/en/docs/Usage/security.md +++ b/content/en/docs/Usage/security.md @@ -36,9 +36,9 @@ In principle, the reverse proxy user header is ignored if requests don't come fr ### Listening on a UNIX socket -If you are listening on a UNIX socket (`Address` option), Navidrome will allow any connection to authenticate using the reverse proxy user header, as there is no remote IP exposed. +If you are listening on a UNIX socket (`Address` option) and enable reverse proxy authentication (`ReverseProxyWhitelist` configured with the special value `@`), any process able to write to the socket can forge authenticated requests. -Make sure to properly protect the socket with user access controls. +Make sure to properly protect the socket with user access controls (see the `UnixSocketPerm` option). ### Reverse proxy with a dynamic IP address From cb9fc1380d8b08a3ef508050df3b68ad8504a03c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jeremiah=20Men=C3=A9trey?= Date: Tue, 1 Oct 2024 00:15:33 +0200 Subject: [PATCH 10/11] Fix words in the wrong order --- content/en/docs/Usage/reverse-proxy.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/en/docs/Usage/reverse-proxy.md b/content/en/docs/Usage/reverse-proxy.md index ce2f7281..412b0618 100644 --- a/content/en/docs/Usage/reverse-proxy.md +++ b/content/en/docs/Usage/reverse-proxy.md @@ -13,7 +13,7 @@ By default, reverse proxy authentication is disabled. To enable the feature, con * An IPv4 or IPv6 range in CIDR notation. * An `@` (at sign) when listening on a UNIX socket (see the `Address` option). -When enabled via the `ReverseProxyWhitelist` option, Navidrome validates the requests' source IP address against the ranges configured in `ReverseProxyWhitelist`. If the address doesn't match, reverse proxy authentication is not used even if the reverse proxy user header is present (see below), and falls back to a standard authentication mechanism. For requests received through a UNIX socket, IPs can't be validated and Navidrome will use the reverse proxy user header if and only if `ReverseProxyWhitelist` contains `@`. +When enabled via the `ReverseProxyWhitelist` option, Navidrome validates the requests' source IP address against the ranges configured in `ReverseProxyWhitelist`. If no range matches the address, reverse proxy authentication is not used even if the reverse proxy user header is present (see below), and falls back to a standard authentication mechanism. For requests received through a UNIX socket, IPs can't be validated and Navidrome will use the reverse proxy user header if and only if `ReverseProxyWhitelist` contains `@`. With reverse proxy authentication enabled, Navidrome gets the username of the authenticated user from incoming requests' `Remote-User` HTTP header. The header can be changed via the `ReverseProxyUserHeader` configuration option. From 7ca909375f0ff65ce5185cddf7b482288881bef6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jeremiah=20Men=C3=A9trey?= Date: Sat, 23 Nov 2024 16:07:21 +0100 Subject: [PATCH 11/11] Clarify use-case for ReverseProxyWhitelist option I have seen several people on reddit using this option with a non-authenticating proxy setup, mostly when the proxy is only used to route traffic or handle SSL termination, which can easily lead to an insecure setup (e.g. the proxy might not remove by default the user header set by a malicious client). The option's name is a bit unfortunate, as it suggests that it should be used for all proxy setups, while it is actually usefull only for authenticating proxies. --- .../en/docs/Usage/configuration-options.md | 138 +++++++++--------- 1 file changed, 69 insertions(+), 69 deletions(-) diff --git a/content/en/docs/Usage/configuration-options.md b/content/en/docs/Usage/configuration-options.md index c9395787..12b07247 100644 --- a/content/en/docs/Usage/configuration-options.md +++ b/content/en/docs/Usage/configuration-options.md @@ -120,75 +120,75 @@ make it all uppercase. Ex: `ND_LOGLEVEL=debug`. See below for all available opti -| In config file | As an environment variable | Description | Default Value | -|------------------------------------------------|--------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------| -| AlbumPlayCountMode | `ND_ALBUMPLAYCOUNTMODE` | Change how album play count is computed. When set to `"normalized"`, album play count will be divided by the number of album tracks | `"absolute"` | -| AuthRequestLimit[\*][limit-login-attempts] | `ND_AUTHREQUESTLIMIT` | How many login requests can be processed from a single IP during the `AuthWindowLength`. Set to `0` to disable the limit rater | `5` | -| AuthWindowLength[\*][limit-login-attempts] | `ND_AUTHWINDOWLENGTH` | Window Length for the authentication rate limit | `"20s"` | -| AutoImportPlaylists | `ND_AUTOIMPORTPLAYLISTS` | Enable/disable `.m3u` playlist auto-import | `true` | -| DefaultPlaylistPublicVisibility | `ND_DEFAULTPLAYLISTPUBLICVISIBILITY` | Set imported playlists as public by default | `false` | -| ArtistArtPriority[\*][artistcoverart] | `ND_ARTISTARTPRIORITY` | Configure the order to look for artist images. | `artist.*, album/artist.*, external` | -| CoverArtPriority[\*][albumcoverart] | `ND_COVERARTPRIORITY` | Configure the order to look for cover art images. Use special `embedded` value to get embedded images from the audio files | `cover.*, folder.*, front.*, embedded, external` | -| CoverJpegQuality | `ND_COVERJPEGQUALITY` | Set JPEG quality percentage for resized cover art images | `75` | -| DefaultDownsamplingFormat | `ND_DEFAULTDOWNSAMPLINGFORMAT` | Format to transcode to when client requests downsampling (specify maxBitrate without a format) | `opus` | -| DefaultLanguage | `ND_DEFAULTLANGUAGE` | Sets the default language used by the UI when logging in from a new browser. This value must match one of the file names in the [resources/i18n][i18n]. Ex: for Chinese Simplified it has to be `zh-Hans` (case sensitive) | `"en"` | -| DefaultTheme | `ND_DEFAULTTHEME` | Sets the default theme used by the UI when logging in from a new browser. This value must match one of the options in the UI | `Dark` | -| EnableArtworkPrecache | `ND_ENABLEARTWORKPRECACHE` | Enable image pre-caching of new added music | `true` | -| EnableCoverAnimation | `ND_ENABLECOVERANIMATION` | Controls whether the player in the UI will animate the album cover (rotation) | `true` | -| EnableDownloads | `ND_ENABLEDOWNLOADS` | Enable the option in the UI to download music/albums/artists/playlists from the server | `true` | -| EnableExternalServices | `ND_ENABLEEXTERNALSERVICES` | Set this to `false` to completely disable ALL external integrations | `true` | -| EnableFavourites | `ND_ENABLEFAVOURITES` | Enable toggling "Heart"/"Loved" for songs/albums/artists in the UI (maps to "Star"/"Starred" in Subsonic Clients) | `true` | -| EnableGravatar | `ND_ENABLEGRAVATAR` | Use [Gravatar](https://gravatar.com/) images as the user profile image. Needs the user's email to be filled | `false` | -| EnableLogRedacting | `ND_ENABLELOGREDACTING` | Whether or not sensitive information (like tokens and passwords) should be redacted (hidden) in the logs | `true` | -| EnableMediaFileCoverArt[\*][mediafilecoverart] | `ND_ENABLEMEDIAFILECOVERART` | If set to false, it will return the album CoverArt when a song CoverArt is requested | `true` | -| EnableReplayGain | `ND_ENABLEREPLAYGAIN` | Enable ReplayGain options in the UI | `true` | -| EnableSharing | `ND_ENABLESHARING` | Enable the Sharing feature | `false` | -| EnableStarRating | `ND_ENABLESTARRATING` | Enable 5-star ratings in the UI | `true` | -| EnableTranscodingConfig[\*][transcoding] | `ND_ENABLETRANSCODINGCONFIG` | Enables transcoding configuration in the UI | `false` | -| EnableUserEditing | `ND_ENABLEUSEREDITING` | Enable regular users to edit their details and change their password | `true` | -| FFmpegPath | `ND_FFMPEGPATH` | Path to `ffmpeg` executable. Use it when Navidrome cannot find it, or you want to use a specific version | _Empty_ (search in the PATH) | -| GATrackingID | `ND_GATRACKINGID` | Send basic info to your own Google Analytics account. Must be in the format `UA-XXXXXXXX` | _Empty_ (disabled) | -| HTTPSecurityHeaders.CustomFrameOptionsValue | `ND_HTTPSECURITYHEADERS_CUSTOMFRAMEOPTIONSVALUE` | Allows the `X-Frame-Options` header value to be set with a custom value. Ex: `"SAMEORIGIN"` | `"DENY"` | -| IgnoredArticles | `ND_IGNOREDARTICLES` | List of ignored articles when sorting/indexing artists | `"The El La Los Las Le Les Os As O A"` | -| ImageCacheSize | `ND_IMAGECACHESIZE` | Size of image (art work) cache. Set to `"0"` to disable cache | `"100MB"` | -| Jukebox.Enabled | `ND_JUKEBOX_ENABLED` | Enable Jukebox mode (play audio on server's hardware) Click [here][jukebox-mode] for details | `false` | -| Jukebox.AdminOnly | `ND_JUKEBOX_ADMINONLY` | By default, Jukebox mode is only available to Admins. Set this option to `false` to allow any valid user to control it | `true` | -| Jukebox.Devices | _(cannot be set as an environment variable)_ | List of devices that can be used by the Jukebox. Click [here][jukebox-config] for details | _Empty_ (auto detect) | -| Jukebox.Default | `ND_JUKEBOX_DEFAULT` | Device to use for Jukebox mode, if there are multiple Jukebox.Devices entries. Click [here][jukebox-config] for details | _Empty_ (auto detect) | -| LastFM.Enabled | `ND_LASTFM_ENABLED` | Set this to `false` to completely disable Last.fm integration | `true` | -| LastFM.ApiKey[\*][lastfm-integration] | `ND_LASTFM_APIKEY` | Last.fm API Key | _Empty_ | -| LastFM.Secret[\*][lastfm-integration] | `ND_LASTFM_SECRET` | Last.fm API Secret | _Empty_ | -| LastFM.Language | `ND_LASTFM_LANGUAGE` | [Two letter-code for language][language-codes] to be used to retrieve biographies from Last.fm | `"en"` | -| ListenBrainz.BaseURL | `ND_LISTENBRAINZ_BASEURL` | Set this to override the default ListenBrainz base URL (useful with self-hosted solutions like Maloja[\*][maloja] | `https://api.listenbrainz.org/1/` | -| ListenBrainz.Enabled | `ND_LISTENBRAINZ_ENABLED` | Set this to `false` to completely disable ListenBrainz integration | `true` | -| MaxSidebarPlaylists | `ND_MAXSIDEBARPLAYLISTS` | Set the maximum number of playlists shown in the UI's sidebar. Note that a very large number can cause UI performance issues. | `100` | -| MPVPath | `ND_MPVPATH` | Path to `mpv` executable. Used for [Jukebox mode][jukebox-mode] | _Empty_ (search in PATH) | -| MPVCmdTemplate | `ND_MPVCMDTEMPLATE` | Cmd template used to construct the call of the `mpv` executable. Used for [Jukebox mode][jukebox-cmd] | `mpv --audio-device=%d --no-audio-display --pause %f --input-ipc-server=%s` | -| PasswordEncryptionKey[\*][encrypt-passwords] | `ND_PASSWORDENCRYPTIONKEY` | Passphrase used to encrypt passwords in the DB. Click [here][encrypt-passwords] for details | - | -| PlaylistsPath | `ND_PLAYLISTSPATH` | Where to search for and import playlists from. Can be a list of folders/globs (separated by `:` (or `;` on Windows). Paths **MUST** be relative to `MusicFolder` | `".:**/**"` (meaning `MusicFolder` and all its subfolders) | -| PreferSortTags | `ND_PREFERSORTTAGS` | Use Sort_* tags to sort columns in the UI. | `false` | -| Prometheus.Enabled | `ND_PROMETHEUS_ENABLED` | Enable extra endpoint with [Prometheus](https://prometheus.io/docs/introduction/overview/) metrics. | `false` | -| Prometheus.MetricsPath | `ND_PROMETHEUS_METRICSPATH` | Custom path for Prometheus metrics. Useful for blocking unauthorized metrics requests. | `"/metrics"` | -| RecentlyAddedByModTime | `ND_RECENTLYADDEDBYMODTIME` | Uses music files' modification time when sorting by "Recently Added". Otherwise use import time | `false` | -| ReverseProxyUserHeader[\*][reverse-proxy-auth] | `ND_REVERSEPROXYUSERHEADER` | HTTP header containing user name from authenticated proxy. Click [here][reverse-proxy-config] for details | `"Remote-User"` | -| ReverseProxyWhitelist[\*][reverse-proxy-auth] | `ND_REVERSEPROXYWHITELIST` | Comma separated list of IP CIDRs (or when listening on a UNIX socket the special value `@`) which are allowed to use reverse proxy authentication. Empty means "deny all". Click [here][reverse-proxy-config] for details | _Empty_ | -| Scanner.Extractor[\*][extractors] | `ND_SCANNER_EXTRACTOR` | Select metadata extractor implementation. Options: `taglib` or `ffmpeg` | `"taglib"` | -| Scanner.GenreSeparators | `ND_SCANNER_GENRESEPARATORS` | List of separators to split genre tags | `";/,"` | -| Scanner.GroupAlbumReleases | `ND_SCANNER_GROUPALBUMRELEASES` | "true" groups albums with the same Artist + Album Title as one album; "false" splits re-issues (=different Release Date) into separate albums | `false` | -| ScanSchedule | `ND_SCANSCHEDULE` | Configure periodic scans using ["cron" syntax](https://crontab.guru). To disable it altogether, set it to `"0"` | `"@every 1m"` | -| SearchFullString | `ND_SEARCHFULLSTRING` | Match query strings anywhere in searchable fields, not only in word boundaries. Useful for languages where words are not space separated | `false` | -| SessionTimeout | `ND_SESSIONTIMEOUT` | How long Navidrome will wait before closing web ui idle sessions | `"24h"` | -| ShareURL | `ND_SHAREURL` | Base URL for shared links. Useful when your server address is not a public (ex: when using Tailscale). See discussion [here][share-url] | _Empty_ (use server address) | -| SmartPlaylistRefreshDelay | `ND_SMARTPLAYLISTREFRESHDELAY` | How often to refresh Smart Playlists. | `"5s"` | -| Spotify.ID[\*][spotify-integration] | `ND_SPOTIFY_ID` | Spotify Client ID. Required if you want Artist images | _Empty_ | -| Spotify.Secret[\*][spotify-integration] | `ND_SPOTIFY_SECRET` | Spotify Client Secret. Required if you want Artist images | _Empty_ | -| SubsonicArtistParticipations | `ND_SUBSONICARTISTPARTICIPATIONS` | When requesting artist's albums, include albums where the artist participates (ex: Various Artists compilations) | `false` | -| TLSCert | `ND_TLSCERT` | Path for the TLS certificate file, which should include the [signature chain](https://pkg.go.dev/net/http#Server.ServeTLS) if any | _Empty_ (disable TLS) | -| TLSKey | `ND_TLSKEY` | Path for the TLS key file | _Empty_ (disable TLS) | -| TranscodingCacheSize | `ND_TRANSCODINGCACHESIZE` | Size of transcoding cache. Set to `"0"` to disable cache | `"100MB"` | -| UILoginBackgroundUrl | `ND_UILOGINBACKGROUNDURL` | Change background image used in the Login page | _random music image from Unsplash.com_ | -| UIWelcomeMessage | `ND_UIWELCOMEMESSAGE` | Add a welcome message to the login screen | _Empty_ | -| UnixSocketPerm | `ND_UNIXSOCKETPERM` | Set file permissions for Unix Socket File.[\*][reverse-proxy-auth] | `"0660"` | +| In config file | As an environment variable | Description | Default Value | +|------------------------------------------------|--------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------| +| AlbumPlayCountMode | `ND_ALBUMPLAYCOUNTMODE` | Change how album play count is computed. When set to `"normalized"`, album play count will be divided by the number of album tracks | `"absolute"` | +| AuthRequestLimit[\*][limit-login-attempts] | `ND_AUTHREQUESTLIMIT` | How many login requests can be processed from a single IP during the `AuthWindowLength`. Set to `0` to disable the limit rater | `5` | +| AuthWindowLength[\*][limit-login-attempts] | `ND_AUTHWINDOWLENGTH` | Window Length for the authentication rate limit | `"20s"` | +| AutoImportPlaylists | `ND_AUTOIMPORTPLAYLISTS` | Enable/disable `.m3u` playlist auto-import | `true` | +| DefaultPlaylistPublicVisibility | `ND_DEFAULTPLAYLISTPUBLICVISIBILITY` | Set imported playlists as public by default | `false` | +| ArtistArtPriority[\*][artistcoverart] | `ND_ARTISTARTPRIORITY` | Configure the order to look for artist images. | `artist.*, album/artist.*, external` | +| CoverArtPriority[\*][albumcoverart] | `ND_COVERARTPRIORITY` | Configure the order to look for cover art images. Use special `embedded` value to get embedded images from the audio files | `cover.*, folder.*, front.*, embedded, external` | +| CoverJpegQuality | `ND_COVERJPEGQUALITY` | Set JPEG quality percentage for resized cover art images | `75` | +| DefaultDownsamplingFormat | `ND_DEFAULTDOWNSAMPLINGFORMAT` | Format to transcode to when client requests downsampling (specify maxBitrate without a format) | `opus` | +| DefaultLanguage | `ND_DEFAULTLANGUAGE` | Sets the default language used by the UI when logging in from a new browser. This value must match one of the file names in the [resources/i18n][i18n]. Ex: for Chinese Simplified it has to be `zh-Hans` (case sensitive) | `"en"` | +| DefaultTheme | `ND_DEFAULTTHEME` | Sets the default theme used by the UI when logging in from a new browser. This value must match one of the options in the UI | `Dark` | +| EnableArtworkPrecache | `ND_ENABLEARTWORKPRECACHE` | Enable image pre-caching of new added music | `true` | +| EnableCoverAnimation | `ND_ENABLECOVERANIMATION` | Controls whether the player in the UI will animate the album cover (rotation) | `true` | +| EnableDownloads | `ND_ENABLEDOWNLOADS` | Enable the option in the UI to download music/albums/artists/playlists from the server | `true` | +| EnableExternalServices | `ND_ENABLEEXTERNALSERVICES` | Set this to `false` to completely disable ALL external integrations | `true` | +| EnableFavourites | `ND_ENABLEFAVOURITES` | Enable toggling "Heart"/"Loved" for songs/albums/artists in the UI (maps to "Star"/"Starred" in Subsonic Clients) | `true` | +| EnableGravatar | `ND_ENABLEGRAVATAR` | Use [Gravatar](https://gravatar.com/) images as the user profile image. Needs the user's email to be filled | `false` | +| EnableLogRedacting | `ND_ENABLELOGREDACTING` | Whether or not sensitive information (like tokens and passwords) should be redacted (hidden) in the logs | `true` | +| EnableMediaFileCoverArt[\*][mediafilecoverart] | `ND_ENABLEMEDIAFILECOVERART` | If set to false, it will return the album CoverArt when a song CoverArt is requested | `true` | +| EnableReplayGain | `ND_ENABLEREPLAYGAIN` | Enable ReplayGain options in the UI | `true` | +| EnableSharing | `ND_ENABLESHARING` | Enable the Sharing feature | `false` | +| EnableStarRating | `ND_ENABLESTARRATING` | Enable 5-star ratings in the UI | `true` | +| EnableTranscodingConfig[\*][transcoding] | `ND_ENABLETRANSCODINGCONFIG` | Enables transcoding configuration in the UI | `false` | +| EnableUserEditing | `ND_ENABLEUSEREDITING` | Enable regular users to edit their details and change their password | `true` | +| FFmpegPath | `ND_FFMPEGPATH` | Path to `ffmpeg` executable. Use it when Navidrome cannot find it, or you want to use a specific version | _Empty_ (search in the PATH) | +| GATrackingID | `ND_GATRACKINGID` | Send basic info to your own Google Analytics account. Must be in the format `UA-XXXXXXXX` | _Empty_ (disabled) | +| HTTPSecurityHeaders.CustomFrameOptionsValue | `ND_HTTPSECURITYHEADERS_CUSTOMFRAMEOPTIONSVALUE` | Allows the `X-Frame-Options` header value to be set with a custom value. Ex: `"SAMEORIGIN"` | `"DENY"` | +| IgnoredArticles | `ND_IGNOREDARTICLES` | List of ignored articles when sorting/indexing artists | `"The El La Los Las Le Les Os As O A"` | +| ImageCacheSize | `ND_IMAGECACHESIZE` | Size of image (art work) cache. Set to `"0"` to disable cache | `"100MB"` | +| Jukebox.Enabled | `ND_JUKEBOX_ENABLED` | Enable Jukebox mode (play audio on server's hardware) Click [here][jukebox-mode] for details | `false` | +| Jukebox.AdminOnly | `ND_JUKEBOX_ADMINONLY` | By default, Jukebox mode is only available to Admins. Set this option to `false` to allow any valid user to control it | `true` | +| Jukebox.Devices | _(cannot be set as an environment variable)_ | List of devices that can be used by the Jukebox. Click [here][jukebox-config] for details | _Empty_ (auto detect) | +| Jukebox.Default | `ND_JUKEBOX_DEFAULT` | Device to use for Jukebox mode, if there are multiple Jukebox.Devices entries. Click [here][jukebox-config] for details | _Empty_ (auto detect) | +| LastFM.Enabled | `ND_LASTFM_ENABLED` | Set this to `false` to completely disable Last.fm integration | `true` | +| LastFM.ApiKey[\*][lastfm-integration] | `ND_LASTFM_APIKEY` | Last.fm API Key | _Empty_ | +| LastFM.Secret[\*][lastfm-integration] | `ND_LASTFM_SECRET` | Last.fm API Secret | _Empty_ | +| LastFM.Language | `ND_LASTFM_LANGUAGE` | [Two letter-code for language][language-codes] to be used to retrieve biographies from Last.fm | `"en"` | +| ListenBrainz.BaseURL | `ND_LISTENBRAINZ_BASEURL` | Set this to override the default ListenBrainz base URL (useful with self-hosted solutions like Maloja[\*][maloja] | `https://api.listenbrainz.org/1/` | +| ListenBrainz.Enabled | `ND_LISTENBRAINZ_ENABLED` | Set this to `false` to completely disable ListenBrainz integration | `true` | +| MaxSidebarPlaylists | `ND_MAXSIDEBARPLAYLISTS` | Set the maximum number of playlists shown in the UI's sidebar. Note that a very large number can cause UI performance issues. | `100` | +| MPVPath | `ND_MPVPATH` | Path to `mpv` executable. Used for [Jukebox mode][jukebox-mode] | _Empty_ (search in PATH) | +| MPVCmdTemplate | `ND_MPVCMDTEMPLATE` | Cmd template used to construct the call of the `mpv` executable. Used for [Jukebox mode][jukebox-cmd] | `mpv --audio-device=%d --no-audio-display --pause %f --input-ipc-server=%s` | +| PasswordEncryptionKey[\*][encrypt-passwords] | `ND_PASSWORDENCRYPTIONKEY` | Passphrase used to encrypt passwords in the DB. Click [here][encrypt-passwords] for details | - | +| PlaylistsPath | `ND_PLAYLISTSPATH` | Where to search for and import playlists from. Can be a list of folders/globs (separated by `:` (or `;` on Windows). Paths **MUST** be relative to `MusicFolder` | `".:**/**"` (meaning `MusicFolder` and all its subfolders) | +| PreferSortTags | `ND_PREFERSORTTAGS` | Use Sort_* tags to sort columns in the UI. | `false` | +| Prometheus.Enabled | `ND_PROMETHEUS_ENABLED` | Enable extra endpoint with [Prometheus](https://prometheus.io/docs/introduction/overview/) metrics. | `false` | +| Prometheus.MetricsPath | `ND_PROMETHEUS_METRICSPATH` | Custom path for Prometheus metrics. Useful for blocking unauthorized metrics requests. | `"/metrics"` | +| RecentlyAddedByModTime | `ND_RECENTLYADDEDBYMODTIME` | Uses music files' modification time when sorting by "Recently Added". Otherwise use import time | `false` | +| ReverseProxyUserHeader[\*][reverse-proxy-auth] | `ND_REVERSEPROXYUSERHEADER` | HTTP header containing the user name from an authenticating proxy. Click [here][reverse-proxy-config] for details. | `"Remote-User"` | +| ReverseProxyWhitelist[\*][reverse-proxy-auth] | `ND_REVERSEPROXYWHITELIST` | Comma separated list of IP CIDRs (or when listening on a UNIX socket the special value `@`) which are allowed to use reverse proxy authentication. Empty means "deny all". Click [here][reverse-proxy-config] for details. Note: This option is unnecessary for most reverse proxy setups, only for *authenticating* reverse proxies. | _Empty_ | +| Scanner.Extractor[\*][extractors] | `ND_SCANNER_EXTRACTOR` | Select metadata extractor implementation. Options: `taglib` or `ffmpeg` | `"taglib"` | +| Scanner.GenreSeparators | `ND_SCANNER_GENRESEPARATORS` | List of separators to split genre tags | `";/,"` | +| Scanner.GroupAlbumReleases | `ND_SCANNER_GROUPALBUMRELEASES` | "true" groups albums with the same Artist + Album Title as one album; "false" splits re-issues (=different Release Date) into separate albums | `false` | +| ScanSchedule | `ND_SCANSCHEDULE` | Configure periodic scans using ["cron" syntax](https://crontab.guru). To disable it altogether, set it to `"0"` | `"@every 1m"` | +| SearchFullString | `ND_SEARCHFULLSTRING` | Match query strings anywhere in searchable fields, not only in word boundaries. Useful for languages where words are not space separated | `false` | +| SessionTimeout | `ND_SESSIONTIMEOUT` | How long Navidrome will wait before closing web ui idle sessions | `"24h"` | +| ShareURL | `ND_SHAREURL` | Base URL for shared links. Useful when your server address is not a public (ex: when using Tailscale). See discussion [here][share-url] | _Empty_ (use server address) | +| SmartPlaylistRefreshDelay | `ND_SMARTPLAYLISTREFRESHDELAY` | How often to refresh Smart Playlists. | `"5s"` | +| Spotify.ID[\*][spotify-integration] | `ND_SPOTIFY_ID` | Spotify Client ID. Required if you want Artist images | _Empty_ | +| Spotify.Secret[\*][spotify-integration] | `ND_SPOTIFY_SECRET` | Spotify Client Secret. Required if you want Artist images | _Empty_ | +| SubsonicArtistParticipations | `ND_SUBSONICARTISTPARTICIPATIONS` | When requesting artist's albums, include albums where the artist participates (ex: Various Artists compilations) | `false` | +| TLSCert | `ND_TLSCERT` | Path for the TLS certificate file, which should include the [signature chain](https://pkg.go.dev/net/http#Server.ServeTLS) if any | _Empty_ (disable TLS) | +| TLSKey | `ND_TLSKEY` | Path for the TLS key file | _Empty_ (disable TLS) | +| TranscodingCacheSize | `ND_TRANSCODINGCACHESIZE` | Size of transcoding cache. Set to `"0"` to disable cache | `"100MB"` | +| UILoginBackgroundUrl | `ND_UILOGINBACKGROUNDURL` | Change background image used in the Login page | _random music image from Unsplash.com_ | +| UIWelcomeMessage | `ND_UIWELCOMEMESSAGE` | Add a welcome message to the login screen | _Empty_ | +| UnixSocketPerm | `ND_UNIXSOCKETPERM` | Set file permissions for Unix Socket File.[\*][reverse-proxy-auth] | `"0660"` | #### Notes