SSD Nodes Learn Hosting plans →
Guides Matt ConnorBy Matt Connor · Updated 2026-09-27

Disable Sonarr and Radarr authentication

Every way to turn off Sonarr and Radarr login, what the local address option really means on a VPS, and the three setups that are actually safe.

How to disable Sonarr and Radarr authentication

To disable Sonarr and Radarr authentication, open Settings, then General, then the Security block, and change Authentication Required from Enabled to Disabled for Local Addresses. There is no None method any more. Authentication became mandatory in Sonarr v4, so the only setting that removes the app's own login outright is the External method, which hands the job to whatever sits in front of the app.

That is the mechanical answer, and on a VPS it is usually the wrong one. Disabled for Local Addresses will probably not skip the login for you, because your browser is not local in the sense the app means. And once the login is off, the REST API (representational state transfer, the interface the web UI itself talks to) is open to anything that can reach the port, not just the web pages. This guide was checked against Sonarr 4.0.16 and Radarr 6.x in September 2026.

If you landed here because the login is rejecting you rather than because you want it gone, that is a different job: there is no default Sonarr or Radarr password, and you reset it by editing config.xml.

The two dropdowns, and what each option costs you

Settings > General > Security holds two separate settings. Confusing them is how people end up with an open box.

Authentication picks the method, meaning how a user proves who they are. Forms (Login Page) shows a normal login page, and it is the recommended choice. Basic (Browser pop-up) uses the browser's own credential dialog instead of a page. Basic is on its way out: Radarr removed it in v6, and Sonarr still lists it while planning to drop it. That difference is version-dependent, so read your own dropdown rather than trusting a screenshot. External disables the app's own login completely, and the app then accepts every request that reaches it.

Authentication Required picks when the method applies. Enabled always asks. Disabled for Local Addresses asks only when the app decides the request did not come from a local address.

The same values live in config.xml, in the app's data directory:

<AuthenticationMethod>Forms</AuthenticationMethod>
<AuthenticationRequired>DisabledForLocalAddresses</AuthenticationRequired>

Stop the service before you edit that file. A running Sonarr or Radarr holds its own copy of the configuration and writes it back out, so an edit made while the app is up is overwritten the next time it saves.

sudo systemctl stop sonarr
sudo systemctl start sonarr

Under Docker the equivalents are docker compose stop sonarr and docker compose start sonarr, and config.xml sits inside the volume you mapped to /config.

What Sonarr and Radarr actually count as a local address

This is the part that surprises people, so be precise about it.

The check runs against the source IP address of the incoming connection, and it matches that address against a fixed list of unroutable and link-local ranges. Loopback (127.0.0.0/8 and ::1) counts. The RFC 1918 private ranges count: 10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16. Link-local counts. That is the whole definition of local. It is not a check for "the same machine", and it is not a check for "the network my laptop is on". A request to make the app compare the client address against the addresses actually assigned to its own interfaces was filed as Sonarr issue 6534 and closed as not planned, so the fixed range list is what you get.

On a VPS that list works against you. You browse to your server from your home or office connection, so the source address the app sees is a public internet address. A public address is not in any of those ranges, so the request is not local, so you get the login page anyway. Turning on Disabled for Local Addresses and still being asked to log in is the expected result, not a bug.

Where the check does fire on a VPS. A request arriving through an SSH tunnel comes from 127.0.0.1, so it is local. A request from another container on a Docker bridge network comes from a 172.x address inside 172.16.0.0/12, so it is local too: this is why Prowlarr pushing indexers into Sonarr and Radarr from a sibling container never meets a login page. A private overlay network built on RFC 1918 addresses, such as a WireGuard tunnel numbered out of 10.0.0.0/8, is local as well.

Tailscale is the exception people trip over. Tailnet addresses come out of 100.64.0.0/10, which is carrier-grade NAT (network address translation) space and not RFC 1918, so a tailnet peer is not local by default. Sonarr has a separate option to trust CGNAT addresses for exactly this case. It is set through config.xml or an environment variable rather than in the web UI, so check the Security section of the Servarr wiki for the current spelling before you type it.

Behind a reverse proxy, the local check gets a sharp edge

If a proxy sits in front of the app, the source address of every request is the proxy, and the proxy is almost always local. So every request through the proxy looks local, and Disabled for Local Addresses skips the login for the entire internet.

The apps work around this by reading the X-Forwarded-For header, which a proxy uses to report the real client address. That header is only text, and a client can send it too. This was CVE-2026-30975, published in March 2026 with a CVSS score of 8.1: a remote caller could set X-Forwarded-For to a private address by hand, be treated as local, and skip authentication. The fix shipped in Sonarr 4.0.16.2942 (nightly) and 4.0.16.2944 (stable). Patched builds trust that header only from addresses you list under Trusted Networks, and ignore it from everyone else.

So if you run Disabled for Local Addresses behind a proxy, stay on a patched build and put the proxy's own address or subnet in Trusted Networks. Leave Trusted Networks empty and the header is ignored, which means every proxied request is judged by the proxy's local address and the login is skipped for everyone who reaches the proxy.

With the login off, the API is open too

The web UI is a client of the app's own REST API. Every button you click is an HTTP call under /api/v3/. From outside a browser session, that API is normally reached with the key from Settings > General > Security > API Key, sent in an X-Api-Key header. When a request is treated as authenticated by default, the API answers it with no key at all.

You can watch this happen. Run it on the server:

curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8989/api/v3/system/status

401 means the API still demands credentials. 200 means it does not, and every host that can open a TCP connection to that port gets the same 200. Radarr answers the same way on port 7878.

The consequence stated plainly: anything the web UI can change, the API can change, because they are the same interface. That includes the root folder paths that decide where your files get written, and the endpoints that delete a series or a movie together with its files on disk. The API key does not save you here. It is still printed in Settings and other apps still use it, but it stops being the only way in.

Which makes the real question "who can reach the port", not "is the login on". Sonarr listens on 8989 and Radarr on 7878 by default, and each app in the stack has its own port. Check what is exposed:

ss -tlnp | grep -E '8989|7878'
sudo ufw status

0.0.0.0:8989 in that output means the app is listening on every interface, including your public one. One warning if you run under Docker: a ports: mapping installs its own firewall rules and is not filtered by ufw, so ufw status showing a port closed does not mean it is closed. Test from a different machine instead of trusting the local firewall list.

Option one: bind to localhost and use an SSH tunnel

This is the configuration that gives you what "turn off the login" usually means, which is not typing a password every time, without putting anything on the internet.

Make the app listen on loopback only. For a native install, set Bind Address to 127.0.0.1 under Settings > General > Host, or set <BindAddress>127.0.0.1</BindAddress> in config.xml. Under Docker, publish the port on loopback instead of on everything:

services:
  sonarr:
    image: lscr.io/linuxserver/sonarr:latest
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Etc/UTC
    volumes:
      - ./sonarr:/config
    ports:
      - "127.0.0.1:8989:8989"
    restart: unless-stopped

The 127.0.0.1: prefix is the whole trick, so keep it when you build the rest of the stack in one compose file, and get PUID and PGID right at the same time or the container writes files nothing else can read.

Then forward the port from your own machine:

ssh -N -L 8989:127.0.0.1:8989 you@your-vps-address

-N means "no remote command", so the session only carries the tunnel. Leave it running and open http://127.0.0.1:8989 in your browser. With Authentication Required set to Disabled for Local Addresses, the request reaches the app from 127.0.0.1, which is in the local list, so there is no login page. Nothing else can reach the port, because the port is not published anywhere else.

Verify from a second machine that is not tunnelled:

curl --max-time 5 -sv http://your-vps-address:8989/

A healthy result here is a failure: Connection refused, or a timeout. Getting the login page or a redirect instead means the app is still bound to a public interface and your loopback change did not take effect.

Option two: put it on a private network

Run Tailscale, NetBird or a plain WireGuard tunnel on the VPS, then reach the app over that network only. The app still binds to loopback or to the tunnel interface address, never to 0.0.0.0. This suits more than one person or device, which an SSH tunnel handles badly.

The local-address rule decides how much typing you save. A WireGuard tunnel numbered from 10.0.0.0/8 or 192.168.0.0/16 reads as local, so Disabled for Local Addresses skips the login. A tailnet address does not, unless you turn on the CGNAT trust option described above. Plenty of people leave the login enabled here and lose nothing, because the port is already unreachable from the internet.

If you use Tailscale's own publishing commands, read the difference between serve and funnel before you run either. serve keeps the app inside your tailnet. funnel publishes it to the public internet, which undoes this entire section if you have also removed the login.

Option three: let a reverse proxy do the login

Set Authentication to External and put a proxy in front that authenticates for you. The app stops asking, and the proxy asks instead. This is the right answer when other people need access, or when you want one login across several apps.

One rule makes or breaks it. The app's own port must be unreachable except from the proxy. If you set External and leave 8989 open to the internet, you have no authentication at all, because an attacker types the port number and walks past the proxy. Bind the app to 127.0.0.1 and run the proxy on the same host, or restrict the port to the proxy's address at the firewall.

A minimal nginx block with a password file:

location / {
    auth_basic "Sonarr";
    auth_basic_user_file /etc/nginx/.htpasswd;
    proxy_pass http://127.0.0.1:8989;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $http_connection;
}

Create the password file with sudo apt install -y apache2-utils and then sudo htpasswd -c /etc/nginx/.htpasswd yourname. Check the config with sudo nginx -t before reloading, and expect syntax is ok followed by test is successful. The Upgrade and Connection headers are not optional: Sonarr and Radarr push live updates over a websocket, so without them the page loads but the queue and activity views never move. If those directives are unfamiliar, every line in a proxy block has a specific job and guessing at them produces exactly this kind of half-working page.

For a real login rather than a browser password box, put an authentication proxy in that position instead. oauth2-proxy puts a provider login in front of an app that has none, and Authentik forward auth does the same job through Traefik if you already run Traefik for the rest of the stack.

Which one suits a single-user box

Use the SSH tunnel. You already run the SSH daemon and you already hold a key for it, and binding to loopback removes the port from the internet instead of defending it. Nothing new is exposed, and nothing new has to be patched.

Move to a private network when more than one person or device needs in, or when you want the app reachable from a phone without starting a tunnel by hand. Move to a reverse proxy when you need a shared login across several apps, or a URL you can hand to someone who will not install a VPN client. Do not set External and then leave the port open, which is the mistake that turns "I disabled the login" into an unauthenticated API on the public internet.

Check your work

ss -tlnp | grep -E '8989|7878'
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8989/api/v3/system/status

The first command should print 127.0.0.1:8989 and not 0.0.0.0:8989 if you chose the tunnel or the proxy. The second tells you whether an unauthenticated API call succeeds from the server itself, which is acceptable when only the server and your tunnel can reach the port. Then run that same curl from a machine outside the tunnel, against the public address. A refused connection or a timeout is the result you want. A 200 from outside means the API is answering strangers.

FAQ

Can I set authentication to None in Sonarr or Radarr?

No. Authentication became mandatory in Sonarr v4, and None is no longer a valid AuthenticationMethod. The closest options are Authentication Required set to Disabled for Local Addresses, which keeps the login but skips it for requests from private and loopback addresses, or the External method, which turns the app's own login off completely and expects something in front of the app to authenticate instead. Deleting the <AuthenticationMethod> line from config.xml does not disable the login either. It makes the app prompt you to set a new user and password at next start, which is the password reset procedure rather than a way to remove the login.

Why does "Disabled for Local Addresses" still ask me to log in on my VPS?

Because the app compares the source IP address of your request against loopback, the RFC 1918 private ranges and link-local, and your browser arrives from a public internet address. A public address is not in that list, so the request is not local and the login is enforced. The setting works when the request really does come from a private address: through an SSH tunnel from 127.0.0.1, from another Docker container inside 172.16.0.0/12, or over a VPN numbered from 10.0.0.0/8. Tailscale is a special case, because tailnet addresses sit in 100.64.0.0/10 and need the separate CGNAT trust option.

If I turn off the login, is my API key still protecting anything?

No. The web UI and the REST API are the same interface, so a rule that lets a request through without a login lets that request call /api/v3/ without the X-Api-Key header too. Anything the UI can do, an unauthenticated caller can do, including changing root folder paths and deleting a series or movie along with its files. Test it with curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8989/api/v3/system/status and read the status code: 401 means the key is still required, 200 means it is not.

Is "Disabled for Local Addresses" safe behind a reverse proxy?

Only on a patched build with Trusted Networks filled in. The proxy's own address is local, so without extra care every proxied request looks local and the login is skipped for the whole internet. The apps read X-Forwarded-For to recover the real client address, and CVE-2026-30975 was the case where a remote caller could forge that header and be treated as local. Sonarr 4.0.16.2942 nightly and 4.0.16.2944 stable fixed it by trusting the header only from addresses listed in Trusted Networks. List your proxy there, and keep the app updated.