--- title: Automation description: Automate media downloads with the Servarr stack, Radarr, Sonarr, Bazarr, Prowlarr, and Seerr, for movies and TV shows. --- :ellipsis{left=0px width=40rem top=10rem blur=140px zIndex=60} [Servarr](https://wiki.servarr.com/) is a suite of applications developed to automate the downloading, updating, and management of media. Here, we'll focus on movies and TV shows with the goal of: - Selecting a movie from a catalog through a web interface. - Sitting back and enjoying it on Jellyfin a few minutes later. Simple. ![arr](/img/serveex/arr.svg) We’ll start by deploying the stack and then proceed to configure each app and understand how they work. ## Install the Apps ::file-tree --- tree: /: - docker: - jellyfin: - compose.yml - .env - config/ - sonarr: - config/ - radarr: - config/ - bazarr: - config/ - prowlarr: - config/ - seerr: - config/ - media: - downloads/ - tvseries/ - movies/ - library/ --- :: ::warning __Warning:__ Make sure to follow this file structure carefully, especially the `media` folder. This folder must be mounted **exactly the same way** in both the _Qbittorrent_ compose file (`/your/path/media:/media`) and the _arr_ applications. If not, the _arr_ apps may not recognize the path provided by Qbittorrent and will fail to create _hardlinks_. Without hardlinks, the _arr_ apps will copy the files instead, **doubling the space used** on your storage. :: ::steps{level="3"} ### Deploy the stack Open Docker and your `jellyfin` stack. Modify the compose file as follows: ```yaml [compose.yaml] --- services: jellyfin: image: lscr.io/linuxserver/jellyfin:latest container_name: jellyfin environment: - PUID=${PUID} - PGID=${PGID} - TZ=Europe/Paris volumes: - /docker/jellyfin/config:/config - ${MEDIA_PATH}:/media restart: unless-stopped devices: - /dev/dri:/dev/dri ports: - 8096:8096 sonarr: image: lscr.io/linuxserver/sonarr:latest container_name: sonarr environment: - PUID=${PUID} - PGID=${PGID} - TZ=Europe/Paris volumes: - /docker/sonarr/config:/config - ${MEDIA_PATH}:/media ports: - 8989:8989 restart: unless-stopped radarr: image: lscr.io/linuxserver/radarr:latest container_name: radarr environment: - PUID=${PUID} - PGID=${PGID} - TZ=Europe/Paris volumes: - /docker/radarr/config:/config - ${MEDIA_PATH}:/media ports: - 7878:7878 restart: unless-stopped prowlarr: image: lscr.io/linuxserver/prowlarr:latest container_name: prowlarr environment: - PUID=${PUID} - PGID=${PGID} - TZ=Europe/Paris volumes: - /docker/prowlarr/data:/config ports: - 9696:9696 restart: unless-stopped seerr: image: ghcr.io/seerr-team/seerr:latest container_name: seerr environment: - LOG_LEVEL=info - TZ=Europe/Paris volumes: - /docker/seerr/config:/app/config ports: - 5055:5055 restart: unless-stopped bazarr: image: lscr.io/linuxserver/bazarr:latest container_name: bazarr restart: unless-stopped environment: - PUID=1000 - PGID=1000 - TZ=Europe/Paris volumes: - /docker/bazarr/config:/config - ${MEDIA_PATH}:/media ports: - 6767:6767 ``` ::tip ✨ Add the Watchtower label to each container to automate updates ```yaml [compose.yaml] --- services: jellyfin: #... labels: - com.centurylinklabs.watchtower.enable=true ``` :: ### Set your environment variables Set your `.env` file with the variables below: ```properties [.env] PUID= GUID= MEDIA_PATH= ``` | Variable | Description | Example | |----------------|-------------------------------------------------------------------------------------------------|-------------| | `PUID` | Set using your user info (check with `id yourusername`) | `1000` | | `GUID` | Same as above | `1000` | | `MEDIA_PATH` | Path to your media folder, here: `/media`. It must match the one used by Qbittorrent. | `/media` | ::note Unlike the other containers here, Seerr's image doesn't use `PUID`/`PGID`; it always runs as UID `1000`. Make sure `/docker/seerr/config` is owned by that user, or Seerr won't be able to write to it: ```bash [Terminal] sudo chown -R 1000:1000 /docker/seerr/config ``` :: Deploy the stack. ### Done ! :: ### Configure Radarr Radarr queries your torrent sources and lets you define the type of releases to prioritize. It can also upgrade your movies if a better version is available. Once deployed, visit `http://yourserverip:7878`. ::caution __If it fails:__ check your firewall rules. :: Create an account and choose *forms login*. ::steps{level="4"} #### Add a *root folder* - Go to *Settings > Media Management*. - Add a root folder and select `/media/movies`. ::warning __Warning:__ If you already have movies in `movies` from Qbittorrent, do not let Radarr add them. Radarr might modify them, which could stop seeding in Qbittorrent. :: #### Configure Profiles Go to *Settings > Profiles*. These are your default quality profiles. When you make a request, you're selecting one of these. For example, configure the “any” profile by unchecking everything except what is shown in the image and ordering them accordingly. This makes Radarr search for 4K REMUX first, then go down the list if unavailable. ![profiles_radarr](/img/serveex/radarr1.png) #### Add Qbittorrent In *Settings > Download Clients*, add Qbittorrent. - Use your server IP as *Host* and port `5695` if following this guide. - Provide your Qbittorrent *Username* and *Password*. - Click *Test*. - If successful, click *Save*. #### Connect to Jellyfin First, get an API key from Jellyfin: log in as admin, go to *Dashboard > Advanced > API Keys*, and add a new one. Then, in Radarr, go to *Settings > Connect*, add a new connection and choose *Jellyfin*. - Use `jellyfin` or your server IP for *Host*. - Port: `8096` - Paste the API key you generated. - Press *Test*, then *Save* if successful. #### Get API Key for Prowlarr and Seerr - Go to *Settings > General* and copy your *API Key* for later use. #### Done ! :: ### Configure Sonarr Sonarr queries torrent sources and defines what kind of TV series releases to prioritize. It also upgrades series when better versions are available. - Visit `http://yourserverip:8989`. - Follow the same steps as for Radarr, but use `/media/tvseries` as the root folder. ::caution __If it fails:__ check your firewall rules. :: ### Configure Prowlarr Prowlarr acts as a proxy to manage your torrent indexers and link them to Radarr and Sonarr. Go to `http://yourserverip:9696` and create an account, using *forms login*. ::caution __If it fails:__ check your firewall rules. :: ::steps{level="4"} #### Add an Indexer - Go to the *Indexers* section and add your torrent indexer. #### Add Radarr and Sonarr In *Settings > Apps*, add Radarr and Sonarr with the following details: - Prowlarr Server: `http://prowlarr:9696` (or use server IP) - Sonarr / Radarr Server: `http://sonarr:8989` or `http://radarr:7878` - API Key: use the one copied from Radarr and Sonarr. - Click *Test*, then *Save* if all goes well. #### Done ! :: ### Configuring Bazarr Bazarr is an app that automatically searches for the correct subtitles in your preferred languages for all the movies and TV shows added by Radarr and Sonarr. Go to `http://yourserverip:6767`. ::caution __If it fails:__ check your firewall rules. :: Go to *Settings > General* and create a username and password using *forms login*. ::steps{level="4"} #### Add a Language Profile - In *Settings > Languages*, click the pink *Add new profile* button and name it. - Click the pink *Add Languages* button and add your preferred languages, e.g., *French* and *English*. - Save and exit. - At the bottom of the screen under *Default Language For Newly Added Show*, check both boxes and select the profile you just created. ![Bazarr](/img/serveex/bazarr2.png) - Save using the button at the top of the screen. #### Add Subtitle Providers - In *Settings > Providers*, add your preferred providers, for example: ![Bazarr](/img/serveex/bazarr.png) - Save using the button at the top of the screen. #### Add Radarr and Sonarr - Go to *Settings > Sonarr* - In *Address*, enter `sonarr` or your server's IP address. - In *Port*, enter `8989`. - In *API Key*, enter Sonarr’s API key. - Click *Test*. - Save using the button at the top of the screen. Repeat the same steps for Radarr. #### Done ! :: ### Configuring Seerr [Seerr](https://seerr.dev/) (the unified successor of Overseerr and Jellyseerr) is an app that lets you browse a movie catalog and send requests to Sonarr and Radarr. Just browse movies or series, click *Request*, and the media will automatically be downloaded according to your Radarr or Sonarr settings. If the title hasn’t been released yet, it will be downloaded automatically when available. This way, episodes of a series appear in Jellyfin without any manual intervention. Go to `http://yourserverip:5055`, select *Jellyfin* as your media server, and sign in with your Jellyfin admin account. ::caution __If it fails:__ check your firewall rules. :: ::steps{level="4"} #### Add Radarr When prompted, add a Radarr server: - Check *Default server*. - __Server name:__ Radarr - __Hostname or IP address:__ `radarr` or your server's IP - __Port:__ `7878` - __API Key:__ Radarr’s API key - Click *Test* at the bottom. If the test succeeds, continue filling in the fields: - __Quality Profile:__ the one you configured (e.g., `any`) - __Root Folder:__ the Jellyfin folder. In our examples: `/media/movies` - __Minimum Availability:__ `Announced`. This allows requesting unreleased content and downloads it upon release. - Check all 3 boxes at the bottom. - Save and continue. #### Add Sonarr Now do the same for Sonarr: - Check *Default server*. - __Server name:__ Sonarr - __Hostname or IP address:__ `sonarr` or your server's IP - __Port:__ `8989` - __API Key:__ Sonarr’s API key - Click *Test* at the bottom. If the test succeeds, continue filling in the fields: - __Quality Profile:__ the one you configured (e.g., `any`) - __Root Folder:__ the Jellyfin folder. In our examples: `/media/tvseries` - __Language Profile:__ `Deprecated` - Check all 4 boxes at the bottom. - Save and continue. #### Done ! :: And that’s it! Just request a movie or series, then check in qBittorrent or Radarr/Sonarr. Within a few minutes, your media will be available on Jellyfin! ## Exposing Seerr with SWAG It can be useful to expose Seerr if you want to send requests from outside your network without a VPN, or if you've shared your Jellyfin library with others and want them to have Seerr access. ::warning Seerr has no built-in two-factor authentication. Only expose it if you're using a secure authentication solution like [TinyAuth](/serveex/security/tinyauth) or [Authentik](/serveex/advanced/authentik). Otherwise, don't expose it with SWAG, use a VPN like [Wireguard](/serveex/security/wireguard) instead. :: ::note We assume you have the subdomain `films.mydomain.com` with a `CNAME` pointing to `films.fr` in your [DNS zone](/general/networking/dns). And that [unless you’re using Cloudflare Zero Trust](/serveex/security/cloudflare), port `443` on your router is forwarded to port `443` on your server via [NAT rules](/general/networking/nat). :: ::steps{level="3"} ### Add Seerr's network to SWAG Go to Dockge, edit the SWAG compose file, and add the Seerr network, which is the same as Jellyfin (since it’s in the Jellyfin stack): ```yaml [compose.yaml] --- services: swag: container_name: # ... # ... networks: # Connects the container to a custom network # ... - jellyfin # Name of the network declared in the stack networks: # Defines the custom network # ... jellyfin: # Name of the declared network name: jellyfin_default # Actual name of the external network external: true # Indicates it’s an external network ``` Restart the stack by clicking “Deploy” and wait until SWAG is fully operational. ::note Here we assume the Jellyfin network is named `jellyfin_default`. You can verify the connection works by visiting the SWAG dashboard at `http://yourserverip:81`. :: ### Create the subdomain.conf file Create and edit the file `films.subdomain.conf`: ::tip{icon=""} ✨ __Tip:__ you can use [File Browser Quantum](/serveex/files/file-browser-quantum) to browse and edit files instead of using terminal commands. :: ```bash [Terminal] sudo nano /docker/swag/config/nginx/proxy-confs/films.subdomain.conf ``` Paste the following: ```nginx [films.subdomain.conf] ## Version 2024/07/16 # make sure that your seerr container is named seerr # make sure that your dns has a cname set for seerr server { listen 443 ssl; listen [::]:443 ssl; server_name films.*; include /config/nginx/ssl.conf; client_max_body_size 0; # enable for ldap auth (requires ldap-location.conf in the location block) #include /config/nginx/ldap-server.conf; # enable for Authelia (requires authelia-location.conf in the location block) #include /config/nginx/authelia-server.conf; # enable for Authentik (requires authentik-location.conf in the location block) #include /config/nginx/authentik-server.conf; location / { # enable the next two lines for http auth #auth_basic "Restricted"; #auth_basic_user_file /config/nginx/.htpasswd; # enable for ldap auth (requires ldap-server.conf in the server block) #include /config/nginx/ldap-location.conf; # enable for Authelia (requires authelia-server.conf in the server block) #include /config/nginx/authelia-location.conf; # enable for Authentik (requires authentik-server.conf in the server block) #include /config/nginx/authentik-location.conf; include /config/nginx/proxy.conf; include /config/nginx/resolver.conf; set $upstream_app seerr; set $upstream_port 5055; set $upstream_proto http; proxy_pass $upstream_proto://$upstream_app:$upstream_port; } location ~ (/seerr)?/api { include /config/nginx/proxy.conf; include /config/nginx/resolver.conf; set $upstream_app seerr; set $upstream_port 5055; set $upstream_proto http; proxy_pass $upstream_proto://$upstream_app:$upstream_port; } } ``` Press :kbd{value="Ctrl+O"}, then :kbd{value="Enter"} to save, and :kbd{value="Ctrl+X"} to exit. Wait a few minutes, then visit `http://films.mydomain.com` in your browser. ### Done ! :: ::caution __If it fails:__ check your firewall rules. :: And there you go, Seerr is now publicly accessible! ## Protecting Seerr with TinyAuth Add [TinyAuth](/serveex/security/tinyauth)'s forward-auth check directly to `films.subdomain.conf`, the same way as [the TinyAuth guide](/serveex/security/tinyauth#protecting-an-app-via-reverse-proxy). The web UI (`/`) gets the check; `/api` is left out, since Seerr's own API calls (and anything integrating with it) can't do an interactive browser login: ```nginx [films.subdomain.conf]{24-36,39-40} ## Version 2024/07/16 # make sure that your seerr container is named seerr # make sure that your dns has a cname set for seerr server { listen 443 ssl; listen [::]:443 ssl; server_name films.*; include /config/nginx/ssl.conf; client_max_body_size 0; # enable for ldap auth (requires ldap-location.conf in the location block) #include /config/nginx/ldap-server.conf; # enable for Authelia (requires authelia-location.conf in the location block) #include /config/nginx/authelia-server.conf; # enable for Authentik (requires authentik-location.conf in the location block) #include /config/nginx/authentik-server.conf; location /tinyauth { internal; proxy_pass http://tinyauth:3000/api/auth/nginx; proxy_pass_request_body off; proxy_set_header Content-Length ""; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Host $http_host; proxy_set_header X-Forwarded-Uri $request_uri; } location @tinyauth_login { return 302 https://tinyauth.mydomain.com/login?redirect_uri=$scheme://$http_host$request_uri; } location / { auth_request /tinyauth; error_page 401 = @tinyauth_login; # enable the next two lines for http auth #auth_basic "Restricted"; #auth_basic_user_file /config/nginx/.htpasswd; # enable for ldap auth (requires ldap-server.conf in the server block) #include /config/nginx/ldap-location.conf; # enable for Authelia (requires authelia-server.conf in the server block) #include /config/nginx/authelia-location.conf; # enable for Authentik (requires authentik-server.conf in the server block) #include /config/nginx/authentik-location.conf; include /config/nginx/proxy.conf; include /config/nginx/resolver.conf; set $upstream_app seerr; set $upstream_port 5055; set $upstream_proto http; proxy_pass $upstream_proto://$upstream_app:$upstream_port; } location ~ (/seerr)?/api { include /config/nginx/proxy.conf; include /config/nginx/resolver.conf; set $upstream_app seerr; set $upstream_port 5055; set $upstream_proto http; proxy_pass $upstream_proto://$upstream_app:$upstream_port; } } ``` ::note The `location /tinyauth` block runs inside SWAG's own container, so SWAG needs to be on TinyAuth's Docker network to reach it by name (`tinyauth` here). This should already be set up from [exposing TinyAuth itself](/serveex/security/tinyauth#exposing-tinyauth-with-swag). If you run into an error, double-check SWAG's compose file still has that network attached. :: ::tip ✨ You can protect this app with [Authentik](/serveex/advanced/authentik) instead of TinyAuth by opening `films.subdomain.conf` and removing the `#` in front of `include /config/nginx/authentik-server.conf;`{lang=nginx} and `include /config/nginx/authentik-location.conf;`{lang=nginx}. Don't forget to [create an application and provider in Authentik](/serveex/advanced/authentik#protecting-an-app-via-reverse-proxy). ::