Skip to content

Latest commit

 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 

Repository files navigation

Jellyfin ARR Stack

Complete Docker Compose media stack for Jellyfin with request management, media automation, indexer management, downloads, and subtitles.

What Each Service Does

Service Role
Jellyfin Your personal media server. Streams movies and TV shows to any device on your network. Think of it as your self-hosted Netflix.
Seerr The request portal (the successor to Jellyseerr). This is where you search for and request movies or shows. It hands off approved requests to Radarr or Sonarr automatically.
Radarr Handles movie automation. It receives a movie request, searches Prowlarr for a suitable torrent, sends it to qBittorrent, and moves the finished file into your media library.
Sonarr Same as Radarr but for TV shows. Monitors for new episodes and downloads them automatically as they air.
Prowlarr Manages your torrent indexers (search sites) in one place. Radarr and Sonarr query Prowlarr instead of connecting to indexers individually.
qBittorrent The download client. Receives torrent jobs from Radarr and Sonarr and does the actual downloading.
Bazarr Subtitle automation. Connects to Radarr and Sonarr, watches your library, and automatically downloads subtitles for your media.
FlareSolverr A helper service for Prowlarr. Solves Cloudflare bot challenges so Prowlarr can access indexers that are protected by Cloudflare.

User Flow

You search in Seerr
        │
        ▼
Seerr sends request to Radarr (movies) or Sonarr (TV)
        │
        ▼
Radarr / Sonarr searches Prowlarr for a matching torrent
        │
        ▼
Prowlarr queries your configured indexers (via FlareSolverr if needed)
        │
        ▼
Radarr / Sonarr sends the best torrent to qBittorrent
        │
        ▼
qBittorrent downloads the file
        │
        ▼
Radarr / Sonarr moves the finished file to /movies or /tv
        │
        ▼
Jellyfin picks it up and it appears in your library
        │
        ▼
You watch it on any device running the Jellyfin app

Watching on Your Devices

Jellyfin has official apps for almost every platform:

Platform Where to get it
Android TV / Google TV Search "Jellyfin" on the Play Store
Android phone / tablet Search "Jellyfin" on the Play Store
iPhone / iPad Search "Jellyfin" on the App Store
Web browser http://<server-ip>:8096 directly
Roku Jellyfin channel in the Roku Channel Store
Kodi JellyCon add-on

When the app asks for a server address, enter http://<server-ip>:8096 using the local IP of the machine running this stack. Both devices need to be on the same network.

To find your server's local IP:

hostname -I | awk '{print $1}'

How to Request Content

  1. Open Jellyseerr at http://<server-ip>:5055
  2. Search for a movie or TV show
  3. Click Request
  4. For TV shows, select only the seasons you want — deselect the rest
  5. Submit — the request flows automatically through the stack

Radarr and Sonarr handle everything from here. Check qBittorrent at http://<server-ip>:8080 to watch downloads in progress. Once complete, the media appears in Jellyfin within a few minutes.

Services

Service URL Purpose
Jellyfin http://<server-ip>:8096 Media server and playback
Seerr http://<server-ip>:5055 Movie and TV request portal
Radarr http://<server-ip>:7878 Movie automation
Sonarr http://<server-ip>:8989 TV automation
Prowlarr http://<server-ip>:9696 Indexer management for Radarr and Sonarr
qBittorrent http://<server-ip>:8080 Torrent download client
Bazarr http://<server-ip>:6767 Subtitle automation

Replace <server-ip> with the IP address or hostname of the Docker host. On the same machine, use localhost.

This stack is intended for local network use only. Do not forward these ports on your router or expose them directly to the public internet.

Stack Layout

This compose file stores application config in the project directory and media/download data outside the repo under /mnt by default.

JellyFin/
|-- docker-compose.yaml
|-- Makefile
|-- jellyfin/config/
|-- jellyfin/cache/
|-- jellyseerr/config/
|-- radarr/config/
|-- sonarr/config/
|-- prowlarr/config/
|-- qbittorrent/config/
`-- bazarr/config/

/mnt/media/
|-- movies/
`-- tv/

/mnt/downloads/

Requirements

  • Docker Engine
  • Docker Compose plugin
  • Linux host recommended for /dev/dri hardware transcoding passthrough
  • Media mounted at /mnt/media, or set MEDIA_ROOT
  • Downloads mounted at /mnt/downloads, or set DOWNLOADS_ROOT

The compose file defaults to PUID=1000, PGID=1000, TZ=Africa/Johannesburg, MEDIA_ROOT=/mnt/media, and DOWNLOADS_ROOT=/mnt/downloads. Make sure the user and group IDs match the host user that should own the config, media, and download files.

If the target host will not use hardware transcoding, remove the Jellyfin devices entry for /dev/dri before starting the stack.

You can override these values when starting the stack:

PUID=1001 PGID=1001 TZ=Etc/UTC MEDIA_ROOT=/mnt/storage/media DOWNLOADS_ROOT=/mnt/storage/downloads docker compose up -d

Make Targets

If make is not installed on the host, install it first:

sudo apt-get install -y make

Install Docker Engine and the Docker Compose plugin on an Ubuntu-based host:

make deps

Create the default media and download folders:

make media-dirs

Prompt for the media and download folder locations:

make media-dirs-prompt

Create folders using explicit paths:

make media-dirs MEDIA_ROOT=/mnt/storage/media DOWNLOADS_ROOT=/mnt/storage/downloads

Prepare Folders

Create the media and download folders before starting the stack:

sudo mkdir -p /mnt/media/movies /mnt/media/tv /mnt/downloads
sudo chown -R 1000:1000 /mnt/media /mnt/downloads

Docker will create the local config folders automatically, but creating them up front is also fine:

mkdir -p jellyfin/config jellyfin/cache
mkdir -p jellyseerr/config radarr/config sonarr/config prowlarr/config
mkdir -p qbittorrent/config bazarr/config

Start the Stack

From this directory:

docker compose up -d

For an existing installation, use the backup-first update target instead. It archives every persistent application config directory before pulling images or recreating containers:

make update

Backups are written to backups/config-<UTC timestamp>.tar.gz. The update keeps all existing bind mounts unchanged and never deletes media or downloads. If any expected config directory is missing, it stops before changing containers. The stack is stopped briefly for a consistent config backup; if the pull or recreation fails, the previously available images are started again automatically.

Running make backup by itself also stops only the currently running stack services for the duration of the archive, then starts those same services again.

If you use non-default media paths, pass the same values to Compose:

MEDIA_ROOT=/mnt/storage/media DOWNLOADS_ROOT=/mnt/storage/downloads docker compose up -d

Check container status:

docker compose ps

View logs:

docker compose logs -f

View one service:

docker compose logs -f jellyfin

First Run Setup

Jellyfin

  1. Open http://<server-ip>:8096.
  2. Complete the setup wizard.
  3. Add media libraries:
    • Movies: /media/movies
    • TV Shows: /media/tv
  4. If the host supports Intel/AMD hardware acceleration through /dev/dri, enable hardware transcoding in the Jellyfin admin dashboard.

Jellyfin is configured with network_mode: host, so it uses the host network directly instead of a Docker port mapping.

qBittorrent

  1. Open http://<server-ip>:8080.
  2. Sign in using the initial credentials shown by the container logs if prompted.
  3. Set the default save path to /downloads.
  4. Keep the Web UI port as 8080.

Useful log command:

docker compose logs qbittorrent

Prowlarr

  1. Open http://<server-ip>:9696.
  2. Add your indexers.
  3. Connect Prowlarr to Radarr and Sonarr:
    • Radarr URL: http://radarr:7878
    • Sonarr URL: http://sonarr:8989
  4. Use each app's API key from its settings page.

Radarr

  1. Open http://<server-ip>:7878.
  2. Set the root folder to /movies.
  3. Add qBittorrent as the download client:
    • Host: qbittorrent
    • Port: 8080
    • Category: movies
  4. Confirm completed downloads import from /downloads.

Sonarr

  1. Open http://<server-ip>:8989.
  2. Set the root folder to /tv.
  3. Add qBittorrent as the download client:
    • Host: qbittorrent
    • Port: 8080
    • Category: tv
  4. Confirm completed downloads import from /downloads.

Bazarr

  1. Open http://<server-ip>:6767.
  2. Connect Bazarr to Radarr and Sonarr using their API keys.
  3. Confirm paths match:
    • Movies: /movies
    • TV: /tv

Seerr

  1. Open http://<server-ip>:5055.
  2. Connect Seerr to Jellyfin using http://host.docker.internal:8096.
  3. Connect Seerr to Radarr and Sonarr using their API keys.
  4. Send requests to the matching root folders and quality profiles.

Networking Notes

Most services are on the default Docker Compose network and can reach each other by service name:

radarr
sonarr
prowlarr
qbittorrent
bazarr
jellyseerr

Use those service names for app-to-app settings inside the stack. Use <server-ip> only when accessing the web interfaces from a browser.

Jellyfin is the exception because it runs in host network mode. Jellyseerr includes a host.docker.internal mapping so it can reach Jellyfin at http://host.docker.internal:8096.

For a LAN-only deployment:

  • Keep router port forwarding disabled for all stack ports.
  • Use the Linux host firewall to restrict access to the local subnet, especially for Jellyfin because it uses host networking and is not controlled by Docker port bindings.
  • Use a VPN such as WireGuard or Tailscale if remote access is needed later.

Volumes and Paths

Host Path Container Path Used By
./jellyfin/config /config Jellyfin
./jellyfin/cache /cache Jellyfin
${MEDIA_ROOT:-/mnt/media} /media:ro Jellyfin
./jellyseerr/config /app/config Jellyseerr
./radarr/config /config Radarr
${MEDIA_ROOT:-/mnt/media}/movies /movies Radarr, Bazarr
./sonarr/config /config Sonarr
${MEDIA_ROOT:-/mnt/media}/tv /tv Sonarr, Bazarr
./prowlarr/config /config Prowlarr
./qbittorrent/config /config qBittorrent
${DOWNLOADS_ROOT:-/mnt/downloads} /downloads Radarr, Sonarr, qBittorrent
./bazarr/config /config Bazarr

Jellyfin mounts the media root read-only. Radarr, Sonarr, and Bazarr mount their specific media folders with write access.

Maintenance

Back up config, pull current stable images, and recreate containers:

make update

The Seerr image automatically migrates an existing Jellyseerr database in ./jellyseerr/config. Keep this directory owned by UID/GID 1000:1000, which is the default user used by the Seerr container.

Restart one service:

docker compose restart jellyfin

Stop the stack without removing containers:

docker compose stop

Stop and remove containers without deleting config or media:

docker compose down

Remove unused Docker images:

docker image prune

Backups

Back up the local config folders regularly:

jellyfin/
jellyseerr/
radarr/
sonarr/
prowlarr/
qbittorrent/
bazarr/

The media and download folders live outside this repo under MEDIA_ROOT and DOWNLOADS_ROOT.

Troubleshooting

If a web UI does not load, check that the container is running:

docker compose ps

If imports fail, check permissions on MEDIA_ROOT and DOWNLOADS_ROOT, then confirm the same paths are configured inside Radarr, Sonarr, and qBittorrent.

If hardware transcoding does not work, confirm the host exposes /dev/dri:

ls -ld /dev/dri

If qBittorrent credentials are not known, inspect its logs:

docker compose logs qbittorrent

Current Compose Defaults

  • Timezone: Africa/Johannesburg
  • User/group IDs: 1000:1000 for LinuxServer.io services
  • qBittorrent Web UI port: 8080
  • Jellyfin host media path: ${MEDIA_ROOT:-/mnt/media}
  • Download path: ${DOWNLOADS_ROOT:-/mnt/downloads}
  • Jellyfin hardware device mount: /dev/dri

About

Complete Jellyfin + *Arr stack

Resources

Code of conduct

Contributing

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages