Automation
Lidarr logo

How to install Lidarr with Docker

Lidarr Docker install guide cover
Difficulty: BeginnerTime: 20 minutesTested with: Lidarr 3.1 (linuxserver.io image)

Lidarr is a free, open-source music collection manager. Follow the artists you like and it watches your indexers for new albums, sends them to your download client, then tags, renames and files them in your library, upgrading quality as better releases appear. There is no subscription, and everything stays on your own server.

In this guide we will run Lidarr in Docker using the linuxserver.io image, set up a shared /data folder so imports are instant hardlinks instead of slow copies, connect it to a download client, and get it ready to sit behind a reverse proxy.

πŸ’‘
Note: This guide works with the current Lidarr 3.1 release (3.1.0.4875 at the time of writing) from the linuxserver.io image.

βœ… Before you start

  • A Linux host with Docker and Docker Compose v2 installed (docker compose version should work).
  • A download client such as qBittorrent or Transmission, ideally set up with the same /data layout (both have their own Nerdy Guides).
  • At least one indexer. The easiest way to manage these is Prowlarr, which pushes indexers to every *arr app for you.
  • Enough space on one disk or pool for your downloads and your music library.
  • Optional: a reverse proxy such as Traefik or Nginx Proxy Manager if you want to reach Lidarr from outside your LAN.

STEP 1: Find your user and group IDs

Lidarr should run as a normal user, not as root. Log in to your Docker host over SSH and run:

id

You will see something like uid=1000(you) gid=1000(you). Make a note of the two numbers; they become PUID and PGID below.

πŸ‘
Tip: One user for the whole stack
Use the same PUID and PGID for Sonarr, Radarr, Lidarr, qBittorrent and Transmission. They all read and write the same files, so they need to agree on who owns them.

STEP 2: Create the folders

Every app in my media stack shares one data folder, with downloads and the finished library side by side. Create the app's own config folder and the shared layout (skip the second block if you already made it for another *arr app or your download client):

mkdir -p /path/to/appdata/lidarr/config

mkdir -p /path/to/data/{torrents/{movies,tv,music},media/{movies,tv,music}}
sudo chown -R 1000:1000 /path/to/data
sudo chmod -R u=rwX,g=rwX,o=rX /path/to/data

Swap 1000:1000 for your own IDs from STEP 1. When you are done, the shared folder should look like this:

/path/to/data/
    torrents/                     # the download client saves here
        movies/
        tv/
        music/
    media/                        # your finished library (Jellyfin reads this)
        movies/
        tv/
        music/

Shared data layout

πŸ’‘
Note: Why one /data folder?
Hardlinks and instant (atomic) moves only work inside a single file system, and Docker treats every volume you mount as a separate one. If downloads and the library are mounted separately (the classic /downloads and /tv), Lidarr has to copy each file and then delete the original: slow, and while a torrent is still seeding it uses twice the disk space. Mount the one /data folder in every container instead and the paths match everywhere, so an import becomes an instant hardlink: the file appears in your library and keeps seeding from the same blocks on disk. This is the layout the TRaSH Guides recommend.
⚠️
Warning: /path/to/data must live on one disk or pool. Hardlinks cannot cross from one disk to another, so do not split torrents and media across drives.

Finally, I put all my media apps on one shared Docker network so they can reach each other by name (for example, Lidarr reaching http://qbittorrent:8080). If you followed the Jellyfin guide you already have it; otherwise create it once:

docker network create media

STEP 3: The compose file

Create /path/to/appdata/lidarr/docker-compose.yml and paste in the following. Use the copy button in the top right corner of the block.

services:
  lidarr:
    image: lscr.io/linuxserver/lidarr:latest
    container_name: lidarr
    hostname: lidarr
    restart: unless-stopped
    environment:
      - PUID=1000            # your user ID from STEP 1
      - PGID=1000            # your group ID from STEP 1
      - TZ=Europe/London     # your time zone
      - UMASK=002            # new files are group-writable
    volumes:
      - /path/to/appdata/lidarr/config:/config
      - /path/to/data:/data  # ONE mount for downloads and library
    ports:
      - 8686:8686            # web UI
    networks:
      - media

networks:
  media:
    external: true

docker-compose.yml

⚠️
Warning: Do not add the separate /music and /downloads mounts from the image's example. They work, but they are exactly what breaks hardlinks. Everything lives under /data.

STEP 4: The settings explained

Setting What it does
image The linuxserver.io build of Lidarr. The latest tag follows stable releases.
PUID / PGID The user and group Lidarr runs as inside the container. Files it creates in /config and /data belong to this user.
TZ Time zone, so schedules, the calendar and logs use your local time. List of zones.
UMASK Optional. 002 makes new files and folders group-writable, handy when several apps share one group.
/config Lidarr's database, settings and logs. This is the folder to back up.
/data The shared folder from STEP 2: downloads in /data/torrents and your library in /data/media, on one file system so hardlinks work.
8686:8686 The web UI. Change the left-hand number if the port is already taken on your host.
networks Joins the shared media network so Lidarr can reach your download client, Prowlarr and Jellyfin by container name.

STEP 5: Start Lidarr

From the folder containing your compose file:

cd /path/to/appdata/lidarr
docker compose up -d
docker compose logs -f

Wait until the logs settle down (press Ctrl+C to stop following them; the container keeps running), then check it is up:

docker ps --filter name=lidarr

After a few seconds the status should read Up.

STEP 6: First-run setup

Open http://192.168.1.20:8686 in your browser, replacing the IP with your Docker host's address.

  1. Set up a login. Lidarr asks you to choose an authentication method straight away. Pick Forms (Login Page), leave Authentication Required on Enabled, and choose a username and a strong password such as CHANGE_ME_STRONG_PASSWORD (please do change it).
  2. Add your root folder. Go to Settings β†’ Media Management, click Add Root Folder and choose /data/media/music. Lidarr will also ask for a default quality and metadata profile; the defaults are fine to start with.
  3. Check hardlinks are on. On the same page, click Show Advanced and make sure Use Hardlinks instead of Copy is ticked (it is by default). Click Save Changes.
  4. Add your download client. Go to Settings β†’ Download Clients, click + and pick qBittorrent (or Transmission). Set Host to qbittorrent (the container name, thanks to the shared network) and Port to 8080 (Transmission: transmission and 9091), enter the client's username and password, and change Category from lidarr to music so downloads land in /data/torrents/music. Click Test, then Save.
  5. Add indexers. Either add them under Settings β†’ Indexers, or (much easier with several *arr apps) add them once in Prowlarr and let it sync them to Lidarr.
  6. Grab your API key. Settings β†’ General shows the API key that Prowlarr, Jellyseerr, JellyGlance and Homarr widgets use to talk to Lidarr.

That's the core setup done. Add your first few artists from the search bar and watch them appear under Activity.

πŸ‘
Tip: No Remote Path Mappings needed
Because Lidarr and your download client both see the same /data path, you do not need any Remote Path Mappings. If a guide tells you to add one, your paths do not match; fix the mounts instead.

STEP 7: Put Lidarr behind a reverse proxy

Never forward port 8686 straight from your router. Put Lidarr behind a reverse proxy with HTTPS, keep the login from STEP 6 enabled, or keep it private and use a VPN such as WireGuard or Tailscale.

Option A: Traefik (Docker labels)

If Traefik runs on the same Docker host and is attached to the media network, add these labels to the lidarr service. They assume your HTTPS entry point is called websecure and your certificate resolver is called cloudflare; change them to match your Traefik config.

    labels:
      - traefik.enable=true
      - traefik.http.routers.lidarr.rule=Host(`lidarr.example.com`)
      - traefik.http.routers.lidarr.entrypoints=websecure
      - traefik.http.routers.lidarr.tls.certresolver=cloudflare
      - traefik.http.services.lidarr.loadbalancer.server.port=8686

docker-compose.yml (extra lines)

Option B: Traefik (file provider)

If Traefik runs on a different machine, add a router and service to your dynamic config file instead:

http:
  routers:
    lidarr:
      rule: Host(`lidarr.example.com`)
      entryPoints:
        - websecure
      tls:
        certResolver: cloudflare
      service: lidarr
  services:
    lidarr:
      loadBalancer:
        servers:
          - url: http://192.168.1.20:8686

dynamic.yml

Option C: Nginx Proxy Manager

Add a Proxy Host for lidarr.example.com with scheme http, forward hostname lidarr (if NPM is on the media network) or 192.168.1.20, and forward port 8686. Request a certificate on the SSL tab and tick Force SSL.

Lidarr needs no special headers on its own subdomain. If you would rather serve it on a path such as https://example.com/lidarr, set Settings β†’ General β†’ URL Base to /lidarr first and restart the container.

Updating Lidarr

The latest tag always follows the newest stable release. To update:

cd /path/to/appdata/lidarr
docker compose pull
docker compose up -d
docker image prune -f
πŸ‘
Tip: Never update from inside the app
The Lidarr team are clear that Docker users should update the container image, not use the built-in updater. linuxserver.io also publishes version tags (see the Tags list on the image page) if you would rather pin one and bump it after reading the release notes. Back up /path/to/appdata/lidarr/config first.

Troubleshooting

Imports are slow or files are copied, not hardlinked. The download client and Lidarr are not seeing the same file system. Check both containers mount /path/to/data:/data (not separate download and library folders), and that torrents and media are on the same disk. ls -li on a file in both places should show the same inode number.

"Path does not exist" or "access denied" on the root folder. This is almost always permissions. Run docker exec -it lidarr ls -ln /data/media: the owner should match your PUID/PGID. Fix it on the host with the chown/chmod commands from STEP 2.

The download client test fails. Make sure both containers are on the media network (docker network inspect media) and that you used the container name, not localhost. Inside a container, localhost is the container itself.

Downloads finish but never import. Look at Activity β†’ Queue and hover over the warning icon. A category mismatch (the client saving outside /data/torrents/music) or a file still being written are the usual causes.

port is already allocated when starting. Something else is using 8686. Change the left-hand side of the port mapping, for example 8687:8686.

That's it! Lidarr is now quietly looking after your music for you. Put the kettle on and let it do the hunting. 🎡