1.5.17 Arr Stack

In this chapter we follow roughly the guidelines from Techhut Instruction Video and the Trash Guides guide. However, there are other methods as well of course.

01. Architectural Overview

Screenshot From 2026-06-15 17-51-08.png

Movie/Show Request
  1. A user makes a request via Seerr, which is basically a catalogue of all the existing movies and tv shows and upcoming ones. This is where the end user will interact with for requests. Everything else from 2-4 is not publicly accessible. Only 1 and 5 are in the whole process.
  2. Then the request will end up in Radarr for movies and Sonarr for TV shows.
  3. Radarr and Sonarr are open-source applications designed for automating the downloading of movies and TV shows, respectively. They help users track their favorite media, automatically search for new episodes or films, and manage downloads through a user-friendly web interface.
Overview of the Request Process

Radarr/Sonarr  and Prowlarr work in tandem to automate the downloading of movies. Here’s how the process unfolds:

  1. Search Request: Radarr/Sonarr initiates a search request for a specific movie/show.
  2. Querying Indexers: Prowlarr receives this request and queries all its configured indexers.
  3. Returning Results: The results from the indexers are sent back to Prowlarr.
  4. Final Decision: Prowlarr then forwards these results back to Radarr/Sonarr, which makes the final decision on which movie/show/episode to download.
Download clients
  1. After the correct movie/show has been confirmed depending on if its a usenet or torrent file is then send to one of the download clients they are connected to.
  2. Examples of these download clients are nzbget for usenet and qbittorrent for torrents. 
  3. They go out and download the movies/shows to your hard drives
Front end Jellyfin Clients

List of all Jellyfin clients

Then finally you have multiple front ends that users can interact with to actually watch their movies and shows. Basically Jellyfin sits in the backend and any application that can speak to the Jellyfin API can represent this media how they seem fit. Famous ones I like are

  1. Fladder for Android Mobile  and Laptops (It allows Seerr to be integrated into one application)
  2. Jellyfin for TV
  3. Kodi with a sweet theme for the TV
  4. For iOS devices I would recommend 

03. Mount NFS Share inside Arr VM

Now, that we have created an NFS share we should mount it inside the VM. But before we can mount it we need to install the NFS tools such that it can talk the NFS langauge. This is fairly straightforward with the following commands

1. Within the VM install cifs-utils

sudo apt install cifs-utils

2. Now, edit the fstab file and add the following lines editing them to match your information:

sudo nano /etc/fstab
3. Then in here you will specify your NFS share. It is fairly simple 
 
IP Address arr VM:/mnt/pool/dataset_name /mnt/data  nfs defaults 0 0

4. Once that is saved we restart the daemon and mount the file share

sudo systemctl daemon-reload
sudo mount -a

5. 

02. Creating a NFS Share

Since this stack will save lots of big files i.e movies and tv shows we will create an NFS share for this on our TrueNas VM. You don't need to use TrueNas obviously to create an NFS share but this guide uses TrueNas and hence we do that ;)

1. First we will create a new dataset in TrueNas

2. Go to Datasets -> Click on Add Dataset

3. Give it a name you like

4. Leave the Dataset Preset to Generi

5. Create the dataset ;)

6. Once that is done we click on the dataset and we need to change its permissions

7. Edit the permissions and make sure that the User 1000 has the read write and Execute permissions on both the User and Group section. Leave all the other boxes for Other unchecked. 

8. Sweet! Then finally we will make an NFS share that our Arr Stack will utilize to download and store content on.

9. Click on Shares -> NFS -> Add

10. Then give it a name and choose the dataset for your Arr Stack.

11. For now you can leave the networks and hosts as it is. We can later restrict it by only allowing the Arr stack access to it but that's for later.

12. Cheers!! you made the Arr Stack NFS share !

Awesome, Let's now look at the folder structure ;) 

04. Folder Structure

It's good practice to give all containers the same access to the same root directory or share. This is why all containers in the compose file have the bind volume mount /data:/data. It makes everything easier, plus passing in two volumes such as the commonly suggested /tv, /movies, and /downloads makes them look like two different file systems, even if they are a single file system outside the container. See my current setup below.

data
├── books
├── downloads
│   ├── qbittorrent
│   │   ├── completed
│   │   ├── incomplete
│   │   └── torrents
│   └── nzbget
│       ├── completed
│       ├── intermediate
│       ├── nzb
│       ├── queue
│       └── tmp
├── movies
├── music
├── shows
└── youtube

1. Now, to implement this we will move into our NFS share inside our VM and create the above folder structure with the command

mkdir -p downloads/qbittorrent/{completed,incomplete,torrents} && mkdir -p downloads/nzbget/{completed,intermediate,nzb,queue,tmp}

2. Perfect! You can check with "ls" if the folder structure was actually created correctly.

3. Now, to get the permissions right we need to move back into TrueNas to have the ownership of the folders recursively owned by user 1000 and group 1000. 

4. Go to TrueNas -> Datasets -> DATASET_NAME -> Click on Permissions

5. In here make sure that the 6 top blocks are all set and that you check the boxes

6. Then accept the Warning and save the permission. Sweet! now you are ready to start setting up the docker compose file and can be sure that all the containers have the proper permissions to all the folders. 

 

05. Creating the Docker Compose file

Now, that the NFS share and folder structure  is created and added to the Virtual machine with /etc/fstab we can start creating the docker compose file and its environment ".env" file. It must be said that this docker compose file is basically a copy paste from the compose file created by home lab teacher Techhut. You can find his compose file here. In this docker page I will first explain all the different components and what they do. However, you can also directly copy and paste docker compose and environment file if you want of course. 

Docker Compose File
networks:
  servarrnetwork:
    name: servarrnetwork
    ipam:
      config:
        - subnet: 172.39.0.0/24
services:
  gluetun:
    image: qmcgaw/gluetun
    container_name: gluetun
    cap_add:
      - NET_ADMIN
    devices:
      - /dev/net/tun:/dev/net/tun # If running on an LXC see readme for more info.
    networks:
      servarrnetwork:
        ipv4_address: ${SET_IP_GLUETUN}
    ports:
      - 8080:8080 # qbittorrent web interface
      - 6881:6881 # qbittorrent torrent port
      - 6789:6789 # nzbget
      - 9696:9696 # prowlarr
      - 8191:8191 # flaresolverr
    volumes:
      - ./gluetun:/gluetun
    # Make a '.env' file in the same directory.
    env_file:
      - .env
    healthcheck:
      test: ping -c 1 www.google.com || exit 1
      interval: 20s
      timeout: 10s
      retries: 5
    restart: unless-stopped
  qbittorrent:
    image: lscr.io/linuxserver/qbittorrent:latest
    container_name: qbittorrent
    restart: unless-stopped
    labels:
      - deunhealth.restart.on.unhealthy=true
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
      - WEBUI_PORT=8080 # must match "qbittorrent web interface" port number in gluetun's service above
      - TORRENTING_PORT=${FIREWALL_VPN_INPUT_PORTS} # airvpn forwarded port, pulled from .env
    volumes:
      - ./qbittorrent:/config
      - ${ROOT_DIR}:/data
    depends_on:
      gluetun:
        condition: service_healthy
        restart: true
    network_mode: service:gluetun
    healthcheck:
      test: ping -c 1 www.google.com || exit 1
      interval: 60s
      retries: 3
      start_period: 20s
      timeout: 10s
  # See the 'qBittorrent Stalls with VPN Timeout' section for more information.
  deunhealth:
    image: qmcgaw/deunhealth
    container_name: deunhealth
    network_mode: none
    environment:
      - LOG_LEVEL=info
      - HEALTH_SERVER_ADDRESS=127.0.0.1:9999
      - TZ=${TZ}
    restart: always
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
  nzbget:
    image: lscr.io/linuxserver/nzbget:latest
    container_name: nzbget
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - ./nzbget:/config
      - ${ROOT_DIR}:/data
    depends_on:
      gluetun:
        condition: service_healthy
        restart: true
    restart: unless-stopped
    network_mode: service:gluetun
  prowlarr:
    image: lscr.io/linuxserver/prowlarr:latest
    container_name: prowlarr
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - ./prowlarr:/config
    restart: unless-stopped
    depends_on:
      gluetun:
        condition: service_healthy
        restart: true
    network_mode: service:gluetun
  flaresolverr:
    image: ghcr.io/flaresolverr/flaresolverr:latest
    container_name: flaresolverr
    environment:
      - LOG_LEVEL=${LOG_LEVEL:-info}
      - LOG_HTML=${LOG_HTML:-false}
      - CAPTCHA_SOLVER=${CAPTCHA_SOLVER:-none}
      - TZ=${TZ}
    depends_on:
      gluetun:
        condition: service_healthy
        restart: true
    network_mode: service:gluetun
    restart: unless-stopped
  sonarr:
    image: lscr.io/linuxserver/sonarr:latest
    container_name: sonarr
    restart: unless-stopped
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - ./sonarr:/config
      - ${ROOT_DIR}:/data
    ports:
      - 8989:8989
    networks:
      servarrnetwork:
        ipv4_address: ${SET_IP_SONARR}
  radarr:
    image: lscr.io/linuxserver/radarr:latest
    container_name: radarr
    restart: unless-stopped
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - ./radarr:/config
      - ${ROOT_DIR}:/data
    ports:
      - 7878:7878
    networks:
      servarrnetwork:
        ipv4_address: ${SET_IP_RADARR}
  lidarr:
    container_name: lidarr
    image: lscr.io/linuxserver/lidarr:latest
    restart: unless-stopped
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - ./lidarr:/config
      - ${ROOT_DIR}:/data
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
    ports:
      - 8686:8686
    networks:
      servarrnetwork:
        ipv4_address: ${SET_IP_LIDARR}
  bazarr:
    image: lscr.io/linuxserver/bazarr:latest
    container_name: bazarr
    restart: unless-stopped
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - ./bazarr:/config
      - ${ROOT_DIR}:/data
    ports:
      - 6767:6767
    networks:
      servarrnetwork:
        ipv4_address: ${SET_IP_BAZARR}
  seerr:
    container_name: seerr
    image: ghcr.io/seerr-team/seerr:latest
    environment:
      - LOG_LEVEL=debug
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
    healthcheck:
      test: wget --no-verbose --tries=1 --spider http://localhost:5055/api/v1/status
        || exit 1
      start_period: 20s
      timeout: 3s
      interval: 15s
      retries: 3
    restart: unless-stopped
    volumes:
      - ./seerr:/app/config
    ports:
      - 5055:5055
    networks:
      servarrnetwork:
        ipv4_address: ${SET_IP_SEERR}
  # jellystat-db:
  #   image: postgres:18.1
  #   container_name: jellystat-db
  #   restart: unless-stopped
  #   shm_size: '1gb'
  #   environment:
  #     - POSTGRES_USER=${JELLYSTAT_POSTGRES_USER}
  #     - POSTGRES_PASSWORD=${JELLYSTAT_POSTGRES_PASSWORD}
  #   volumes:
  #     - ./jellystat/postgres-data:/var/lib/postgresql/data
  #   healthcheck:
  #     test: ["CMD-SHELL", "pg_isready --dbname=postgres --username=${JELLYSTAT_POSTGRES_USER}"]
  #     interval: 10s
  #     timeout: 5s
  #     retries: 5
  #   networks:
  #     servarrnetwork:
  #       ipv4_address: ${SET_IP_JELLYSTAT_DB}
  #
  # jellystat:
  #   image: cyfershepard/jellystat:latest
  #   container_name: jellystat
  #   restart: unless-stopped
  #   environment:
  #     - POSTGRES_USER=${JELLYSTAT_POSTGRES_USER}
  #     - POSTGRES_PASSWORD=${JELLYSTAT_POSTGRES_PASSWORD}
  #     - POSTGRES_IP=jellystat-db
  #     - POSTGRES_PORT=5432
  #     - JWT_SECRET=${JELLYSTAT_JWT_SECRET}
  #     - TZ=${TZ}
  #   volumes:
  #     - ./jellystat/backup-data:/app/backend/backup-data
  #   ports:
  #     - 3000:3000
  #   depends_on:
  #     jellystat-db:
  #       condition: service_healthy
  #   healthcheck:
  #     test: wget --no-verbose --tries=1 --spider http://localhost:3000/auth/isConfigured || exit 1
  #     interval: 60s
  #     timeout: 30s
  #     retries: 5
  #     start_period: 30s
  #   networks:
  #     servarrnetwork:
  #       ipv4_address: ${SET_IP_JELLYSTAT}

 

Environment Variables
# General UID/GID and Timezone
TZ=America/Los_Angeles
PUID=1000
PGID=1000

# Input your VPN provider and type here
VPN_SERVICE_PROVIDER=airvpn
VPN_TYPE=wireguard

# Mandatory, airvpn forwarded port
FIREWALL_VPN_INPUT_PORTS=port

# Copy all these variables from your generated configuration file
WIREGUARD_PUBLIC_KEY=key
WIREGUARD_PRIVATE_KEY=key
WIREGUARD_PRESHARED_KEY=key
WIREGUARD_ADDRESSES=ip

# Optional location variables, comma separated list, no spaces after commas, make sure it matches the config you created
# NOTE: These can cause connection failures with some providers. Remove or comment out if Gluetun won't connect.
#SERVER_COUNTRIES=country
#SERVER_CITIES=city

# Health check duration
HEALTH_VPN_DURATION_INITIAL=120s

# Static IPs for services on servarrnetwork
SET_IP_GLUETUN=172.39.0.2
SET_IP_SONARR=172.39.0.3
SET_IP_RADARR=172.39.0.4
SET_IP_LIDARR=172.39.0.5
SET_IP_BAZARR=172.39.0.6
SET_IP_SEERR=172.39.0.7
SET_IP_JELLYSTAT_DB=172.39.0.8
SET_IP_JELLYSTAT=172.39.0.9

# Jellystat (uncomment service block in compose.yaml to enable)
JELLYSTAT_POSTGRES_USER=postgres
JELLYSTAT_POSTGRES_PASSWORD=changeme
JELLYSTAT_JWT_SECRET=changeme

 

Network
  1. First of all an internal docker network is created called "servarrnetwork"
  2. Then we give this network as well a subnet in a /24. This can be any private subnet you please since it is only internal

Gluetun

So what does this docker compose file represent ? What is the workflow here ?

06. qBittorent

In this section we will setup our qBittorrent downloading client.

1.  First get your temporary password that is provided to login which you can find in the logs. Use the command

sudo docker logs qbittorrent
Example output

[migrations] started
[migrations] no migrations found
───────────────────────────────────────

      ██╗     ███████╗██╗ ██████╗
      ██║     ██╔════╝██║██╔═══██╗
      ██║     ███████╗██║██║   ██║
      ██║     ╚════██║██║██║   ██║
      ███████╗███████║██║╚██████╔╝
      ╚══════╝╚══════╝╚═╝ ╚═════╝

   Brought to you by linuxserver.io
───────────────────────────────────────

To support LSIO projects visit:
https://www.linuxserver.io/donate/

───────────────────────────────────────
GID/UID
───────────────────────────────────────

User UID:    1000
User GID:    1000
───────────────────────────────────────
Linuxserver.io version: 5.2.1_v2.0.13-ls460
Build-date: 2026-06-08T23:02:32+00:00
───────────────────────────────────────
    
[custom-init] No custom files found, skipping...
WebUI will be started shortly after internal preparations. Please wait...

******** Information ********
To control qBittorrent, access the WebUI at: http://localhost:8080
The WebUI administrator username is: admin
The WebUI administrator password was not set. A temporary password is provided for this session: yfUHUIHFX
You should set your own password in program preferences.
Connection to localhost (::1) 8080 port [tcp/http-alt] succeeded!

2.  Then go to IP address:8080 and login with "admin" and your temporary password
3.  Once logged in you can change your password and username by going to Settings > WebUI

4. 

 


5.  What's next is setting up the directory scheme for the torrent files
6.  Go to Settings > Downloads
7.  Then Look for

Default save path: /data/torrents/completed  
Keep incomplete torrents in: /data/torrents/incomplete  
Copy torrent files to: /data/torrents/torrents

8.  Congratz now your qBittorent client is all set

07. NZBGet


For a Usenet downloading client we choose NZBget. Yes this is not the only one out there but it is leightweight and efficient. If your container is up and running you can find your NZB instance at

IP address VM:6789

  1. Now, the first time that you will login you will need the standard login credentials which are

Default credentials:

Username: nzbget
Password: tegbzn6789

  1. As with any platform we first change the user credentials. Go to Settings > Security > Change username and Password

Download Folders

  1. Next we will setup up the download folders nzbget will use for its downloads. We already configured them in our folder structure so that will be a piece of cake
  2. For this go to Settings > Paths

In here we will specify

Main Dir: /data/usenet/
DestDir: /data/usenet/completed
InterDir: /data/usenet/incompleted

  1. This is again according to the Trash Guide folder structure we created in the beginning. If you then hit Save and Apply it should give you no errors. If nzbget cannot reach the folders for writing permissions or they don't exist then it will tell you with a red banner.

News-Server

  1. Now, we will setup our new server. It is up to you which news server you choose however regardless you will need 3 items. Your username, password and the host URL. If you have obtained these credentials by login in to you news reader then you can go to Settings > News-Server
  1. By hitting save and apply everything should be good if you did not receive any errors.
  2. Aweseom then your downloading clients are set and we can move on

Categories

Now, we have created the folders movies, tv, books and music inside the completed usenet folder. We now need to tell nzbget about these locations through the means of categories.

  1. Go to Settings > Categories
  2. Add the Categories movies, tv, books and music. Make sure it is all in lower case ;)
NZBGET Health

Health
A decreasing health for a movie in NZBGet typically indicates that the files are becoming less available or are missing parts, making it difficult to download them successfully. This can happen due to content takedowns or the age of the files, leading to failed downloads

Extraction
Files need to be extracted from .rar archives in NZBGet because they are compressed to save space and facilitate faster downloads. Extracting them allows you to access the original files contained within the archive

08. Radarr


1. Create Account

Now, that we have setup our Download clients i.e qBittorent and NZBGet we will configure Radarr, Sonarr, Lidarr, Bazaarr. However, we will only demonstrate one of the 4 since the configuration is exactly the same

  1. Go to your Radarr's IP address :7878
  2. Once, there you will start making an account. For this you can again use Bitwarden to create random login credentials for your instance

2. Media Management

  1. in this step we will assign the folders in which the radarr files will reside
  2. Go to Settings > Media Management > Add root folder
  3. Here you will choose the movie folder you have created in your docker compose file. If you follow this guide this would be at /data/media/Movies
  4. Congratulations, now you have told Radarr where to store all the movies.

3. Downloading Clients

Now we will connect the downloading clients qBittorent and nzbget to Radarr for it to use.

  1. Go to Settings > Downloading Clients > + add
  2. Select qBittorent and fill in the credentials of your qBittorent downloading client
  3. Once done, add another client but this time choose for nzbget.
  4. Also fill in here the credentials of your nzbget client with the category movies
  5. Awesome you are all set !

4. Indexers

The final thing we need to setup for our Radarr instance are indexers. However, we will use Prowlarr for this as a centralised indexer for all ARR apps. The only thing we need for Prowlarr to
connect to Radarr is it's API key.

  1. Go to Settings > General
  2. Copy paste the API key

09. Sonarr


1. Create Account

For Sonarr it will be quite similar as for Radarr

  1. Go to your Radarr's IP address:8989
  2. Once, there you will start making an account. For this you can again use Bitwarden to create random login credentials for your instance

2. Media Management

  1. in this step we will assign the folders in which the radarr files will reside
  2. Go to Settings > Media Management > Add root folder
  3. Here you will choose the movie folder you have created in your docker compose file. If you follow this guide this would be at /data/media/tvshows
  4. Congratulations, now you have told Radarr where to store all the movies.

3. Downloading Clients

Now we will connect the downloading clients qBittorent and nzbget to Radarr for it to use.

  1. Go to Settings > Downloading Clients > + add
  2. Select qBittorent and fill in the credentials of your qBittorent downloading client
  3. Once done, add another client but this time choose for nzbget.
  4. Also fill in here the credentials of your nzbget client with the category "tv"
  5. Awesome you are all set !

4. Indexers

The final thing we need to setup for our Radarr instance are indexers. However, we will use Prowlarr for this as a centralised indexer for all ARR apps. The only thing we need for Prowlarr to
connect to Radarr is it's API key.

  1. Go to Settings > General
  2. Copy paste the API key

10. Prowlarr

So Prowlarr is an indexer manager and proxy that integrates with various PVR (Personal Video Recorder) applications, allowing users to manage both Torrent Trackers and Usenet Indexers seamlessly. It works with applications like Radarr, Sonarr, and Lidarr to automate the process of finding and downloading media content. In other words it basically tells all the other ARR applications about the indexers that are available to use to find media content.

Prowlarr Apps

  1. Go to Radarr and obtain its API key at Settings > General > API key
  2. Then open up Prowlarr at VMIP:9696
  3. Go to Settings > Apps > + Icon
  4. Then make sure you fill in the subnet IP you created for the servarrnetwork. For instance if your servarrnetwork is 172.44.0.1/24 then your subnet IP will be 172.44.0.1

Prowlar Indexers

Setting up the nzbgeek indexer in Prowlarr

11. Profillar

The next ARR app we will install is profillar. This one, is just really important since it allow you to filter what type and size of content you want all don automatically. If you don't have that much storage space you would not want to download 4K content all the time for instance. On top of that it is hard to see the difference between 4K and 1080p anwyays, even 720p does well on smaller screens. Personally I download everything in 1080p or 720p if I don't care about it to much. The 4K is really not visible on my TV anyways. It gives you just great control over your quality and storage space you have access to.

  1. Go to VMIP:6868
  2. Create an account
  3. The first thing we will do just as with Prowlarr is connect it to Radarr and Sonarr.
  4. Grab your API keys from both apps again
  5. Go to Settings > External Apps > Add Radar and then add Sonarr. The IP address for both Sonarr and Radarr is your VMIP

Quality Profiles

  1. After this we need to add a quality profile repository to our profillar app. There are many different repositories but the one that seems used most often is the following
    https://github.com/Dictionarry-Hub/database
  2. Then go to

Media Management

  1. Go back to Radarr and Sonarr
  2. Go to General > Media Management > Click on Advanced in the left top corner
  3. Then scroll down to Propers and Repacks and select "DO NOT PREFER"

12. Seerr

13. Bazaarr

Jellyfin Clients

🌎 Browser-Based

Name OSS Free Paid Downloads
ampcast ⚒️ 🎵 ✅ ✅ ❎ github
Aperture ⚒️ ✅ ✅ ❎ github
Feishin ⚒️ 🎵 ✅ ✅ ❎ github
Finetic ✅ ✅ ❎ github
Fladder ✅ ✅ ❎ github Google Play flathub
Jelly Music App 🎵 ✅ ✅ ❎ github
Jellyfin Vue 🔹 ⚒️ ✅ ✅ ❎ github Demo
Jellyfin Web 🔹 ✅ ✅ ❎ github
Jellyflix ✅ ✅ ❎ Demo App Store github
Moonfin ✅ ✅ ❎ github github github Google Play App Store
Pelagica ✅ ✅ ❎ github Demo
Preserve ⚒️ 🎵 ✅ ✅ ❎ GitLab Demo
Shadfin ⚒️ ✅ ✅ ❎ github Demo
sonixd ⚒️ 🎵 ✅ ✅ ❎ github

💻 Desktop

Windows

Name OSS Free Paid Downloads
ampcast ⚒️ 🎵 ✅ ✅ ❎ github
Blink ⚒️ ✅ ✅ ❎ github
Bloodin ⚒️ ✅ ✅ ❎
Feishin ⚒️ 🎵 ✅ ✅ ❎ github
Fladder ✅ ✅ ❎ github Google Play flathub
FluentFin ⚒️ ✅ ✅ ❎ github
Foxy 🎵 ✅ ✅ ❎ github
Hills ❌ ✅ ☑️ Google Play Microsoft Store
iPlay ✅ ✅ ❎ github App Store Amazon Microsoft Store
Jelly Music App 🎵 ✅ ✅ ❎ github
Jellyamp 🎵 ✅ ✅ ❎ github
Jellyfin Media Player 🔹 ✅ ✅ ❎ github flathub
Jellyfin MPV Shim 🔹 ✅ ✅ ❎ github flathub
Jellyflix ✅ ✅ ❎ Demo App Store github
Moonfin ✅ ✅ ❎ github github github Google Play App Store
Playtorrio ✅ ✅ ❎ github
Preserve ⚒️ 🎵 ✅ ✅ ❎ GitLab Demo
Rodel Player ❌ ✅ ❎ Microsoft Store
Sonixd ⚒️ 🎵 ✅ ✅ ❎ github
Supersonic ⚒️ 🎵 ✅ ✅ ❎ github flathub
Switchfin ⚒️ ✅ ✅ ❎ github
Tauon Music Box 🎵 ✅ ✅ ❎ github flathub
tsukimi ⚒️ ✅ ✅ ❎ github

macOS

Name OSS Free Paid Downloads
ampcast ⚒️ 🎵 ✅ ✅ ❎ github
Blink ⚒️ ✅ ✅ ❎ github
Bloodin ⚒️ ✅ ✅ ❎
Coppelia ⚒️ 🎵 ✅ ✅ ❎ github
Dee Jellie 🎵 ❌ ❌ ☑️ App Store
Discrete 🎵 ❌ ✅ ☑️ App Store
Feishin ⚒️ 🎵 ✅ ✅ ❎ github
Finer 🎵 ❌ ✅ ❎ App Store
Fladder ✅ ✅ ❎ github Google Play flathub
Foxy 🎵 ✅ ✅ ❎ github
HamHub ❌ ✅ ❎ App Store
Infuse ❌ ✅ ☑️ App Store
iPlay ✅ ✅ ❎ github App Store Amazon Microsoft Store
Jelly Music App 🎵 ✅ ✅ ❎ github
Jellyfin Media Player 🔹 ✅ ✅ ❎ github flathub
Jellyfin MPV Shim 🔹 ✅ ✅ ❎ github flathub
Jellyflix ✅ ✅ ❎ Demo App Store github
Moonfin ✅ ✅ ❎ github github github Google Play App Store
Phyn ❌ ✅ ☑️ Google Play App Store
Playtorrio ✅ ✅ ❎ github
SenPlayer ❌ ✅ ☑️ App Store
Sonixd ⚒️ 🎵 ✅ ✅ ❎ github
Supersonic ⚒️ 🎵 ✅ ✅ ❎ github flathub
Switchfin ⚒️ ✅ ✅ ❎ github
VidHub ❌ ✅ ☑️ Google Play App Store

Linux

Name OSS Free Paid Downloads
ampcast ⚒️ 🎵 ✅ ✅ ❎ github
Blink ⚒️ ✅ ✅ ❎ github
Bloodin ⚒️ ✅ ✅ ❎
Coppelia ⚒️ 🎵 ✅ ✅ ❎ github
Delfin ⚒️ ✅ ✅ ❎ flathub
Feishin ⚒️ 🎵 ✅ ✅ ❎ github
Fladder ✅ ✅ ❎ github Google Play flathub
Foxy 🎵 ✅ ✅ ❎ github
Gelly ⚒️ 🎵 ✅ ✅ ❎ github flathub
Jelly Music App 🎵 ✅ ✅ ❎ github
Jellyamp 🎵 ✅ ✅ ❎ github
Jellyfin Media Player 🔹 ✅ ✅ ❎ github flathub
Jellyfin MPV Shim 🔹 ✅ ✅ ❎ github flathub
Jellyflix ✅ ✅ ❎ Demo App Store github
Moonfin ✅ ✅ ❎ github github github Google Play App Store
Playtorrio ✅ ✅ ❎ github
Preserve ⚒️ 🎵 ✅ ✅ ❎ GitLab Demo
Sonixd ⚒️ 🎵 ✅ ✅ ❎ github
Supersonic ⚒️ 🎵 ✅ ✅ ❎ github flathub
Switchfin ⚒️ ✅ ✅ ❎ github
Tauon Music Box 🎵 ✅ ✅ ❎ github flathub
tsukimi ⚒️ ✅ ✅ ❎ github

📱 Mobile

iOS

Name OSS Free Paid Downloads
Coppelia ⚒️ 🎵 ✅ ✅ ❎ github
Dee Jellie 🎵 ❌ ❌ ☑️ App Store
Discrete 🎵 ❌ ✅ ☑️ App Store
Filebar ❌ ✅ ☑️ App Store
Finamp 🎵 ✅ ✅ ❎ Google Play App Store
Finer 🎵 ❌ ✅ ❎ App Store
Fintunes 🎵 ✅ ✅ ❎ github F-Droid Google Play App Store
Fladder ✅ ✅ ❎ github Google Play flathub
HamHub ❌ ✅ ❎ App Store
Infuse ❌ ✅ ☑️ App Store
iPlay ✅ ✅ ❎ github App Store Amazon Microsoft Store
Jellify 🎵 ✅ ✅ ❎ github TestFlight
JellyBook 📖 ✅ ✅ ❎ github Izzysoft TestFlight
Jellyfin Mobile for iOS 🔹 ✅ ✅ ❎ App Store
Jellyflix ✅ ✅ ❎ Demo App Store github
JellyTV ❌ ❌ ☑️ App Store
Manet 🎵 ❌ ✅ ❎ App Store
Moonfin ✅ ✅ ❎ github github github Google Play App Store
Phyn ❌ ✅ ☑️ Google Play App Store
Plappa 🎵 ✅ ✅ ❎ App Store
SenPlayer ❌ ✅ ☑️ App Store
Streamyfin ✅ ✅ ❎ App Store Google Play github
Sunkfin ✅ ✅ ❎ App Store
Swiftfin 🔹 ⚒️ ✅ ✅ ❎ App Store
VidHub ❌ ✅ ☑️ Google Play App Store
yybx ❌ ❌ ☑️ App Store

Android

Name OSS Free Paid Downloads
AFinity ⚒️ ✅ ✅ ❎ github
AfuseKt ❌ ✅ ☑️ github
Coppelia ⚒️ 🎵 ✅ ✅ ❎ github
Finamp 🎵 ✅ ✅ ❎ Google Play App Store
Findroid ⚒️ ✅ ✅ ❎ Izzysoft Google Play F-Droid
Fintunes 🎵 ✅ ✅ ❎ github F-Droid Google Play App Store
Fladder ✅ ✅ ❎ github Google Play flathub
Gelli 🎵 ✅ ✅ ❎ github F-Droid
Ghosten-Player ✅ ✅ ❎ github
Hills ❌ ✅ ☑️ Google Play Microsoft Store
Jellify 🎵 ✅ ✅ ❎ github TestFlight
JellyBook 📖 ✅ ✅ ❎ github Izzysoft TestFlight
JellyCine ✅ ✅ ❎ github
Jellyfin for Android 🔹 ✅ ✅ ❎ F-Droid Amazon Google Play
Jellyflix ✅ ✅ ❎ Demo App Store github
Moonfin ✅ ✅ ❎ github github github Google Play App Store
Phyn ❌ ✅ ☑️ Google Play App Store
Playtorrio ✅ ✅ ❎ github
Reefin ❌ ❌ ❎ Google Play github
Streamyfin ✅ ✅ ❎ App Store Google Play github
Symfonium ⚒️ 🎵 ❌ ❌ ☑️ Google Play
VidHub ❌ ✅ ☑️ Google Play App Store
Void ⚒️ ✅ ✅ ❎ github github
Yamby ❌ ✅ ☑️ Google Play

Sailfish OS

Name OSS Free Paid Downloads
Sailfin ✅ ✅ ❎ OpenRepos

HarmonyOS

Name OSS Free Paid Downloads
FinMusic 🎵 ✅ ✅ ❎ AppGallery github
FinVideo ✅ ✅ ❎ github AppGallery

Nintendo Switch

Name OSS Free Paid Downloads
Switchfin ⚒️ ✅ ✅ ❎ github

📺 TV

Apple TV

Name OSS Free Paid Downloads
Dee Jellie 🎵 ❌ ❌ ☑️ App Store
Filebar ❌ ✅ ☑️ App Store
HamHub ❌ ✅ ❎ App Store
Infuse ❌ ✅ ☑️ App Store
JellySee ❌ ❌ ☑️ App Store
Mediora ✅ ✅ ❎ App Store
Moonfin ✅ ✅ ❎ github github github Google Play App Store
MrMC ✅ ✅ ☑️ Amazon App Store Google Play
SenPlayer ❌ ✅ ☑️ App Store
Swiftfin 🔹 ⚒️ ✅ ✅ ❎ App Store
VidHub ❌ ✅ ☑️ Google Play App Store
yybx ❌ ❌ ☑️ App Store

Android TV

Name OSS Free Paid Downloads
AfuseKt TV ❌ ❌ ☑️ github
DUNE ⚒️ ✅ ✅ ❎ github
Elefin ✅ ✅ ❎ github
Fladder ✅ ✅ ❎ github Google Play flathub
Ghosten-Player ✅ ✅ ❎ github
Jellyfin for Android TV 🔹 ✅ ✅ ❎ Amazon Google Play
Moonfin ✅ ✅ ❎ github github github Google Play App Store
Reefin ❌ ❌ ❎ Google Play github
VidHub ❌ ✅ ☑️ Google Play App Store
Void ⚒️ ✅ ✅ ❎ github github
Wholphin ✅ ✅ ❎ Google Play github
Yamby ❌ ✅ ☑️ Google Play

Kodi

Name OSS Free Paid Downloads
JellyCon 🔹 ✅ ✅ ❎ github
Jellyfin for Kodi 🔹 ✅ ✅ ❎ github

Roku

Name OSS Free Paid Downloads
Jellyfin for Roku 🔹 ✅ ✅ ❎ Roku
JellyRock ✅ ✅ ❎ Roku github
Moonfin ✅ ✅ ❎ github github github Google Play App Store

Tizen

Name OSS Free Paid Downloads
Jellyfin for Tizen 🔹 ✅ ✅ ❎ Build It Yourself
Litefin ✅ ✅ ❎ github
Moonfin ✅ ✅ ❎ github github github Google Play App Store

webOS

Name OSS Free Paid Downloads
Breezyfin ⚒️ ✅ ✅ ❎ github
Jellyfin for WebOS 🔹 ✅ ✅ ❎ LG
Litefin ✅ ✅ ❎ github
Moonfin ✅ ✅ ❎ github github github Google Play App Store

By Type

🎵 Music Client

Name OSS Free Paid Downloads
ampcast ⚒️ 🎵 ✅ ✅ ❎ github
Coppelia ⚒️ 🎵 ✅ ✅ ❎ github
Dee Jellie 🎵 ❌ ❌ ☑️ App Store
Discrete 🎵 ❌ ✅ ☑️ App Store
Feishin ⚒️ 🎵 ✅ ✅ ❎ github
Finamp 🎵 ✅ ✅ ❎ Google Play App Store
Finer 🎵 ❌ ✅ ❎ App Store
FinMusic 🎵 ✅ ✅ ❎ AppGallery github
Fintunes 🎵 ✅ ✅ ❎ github F-Droid Google Play App Store
Foxy 🎵 ✅ ✅ ❎ github
Gelli 🎵 ✅ ✅ ❎ github F-Droid
Gelly ⚒️ 🎵 ✅ ✅ ❎ github flathub
Jellify 🎵 ✅ ✅ ❎ github TestFlight
Jelly Music App 🎵 ✅ ✅ ❎ github
Jellyamp 🎵 ✅ ✅ ❎ github
Manet 🎵 ❌ ✅ ❎ App Store
Plappa 🎵 ✅ ✅ ❎ App Store
Preserve ⚒️ 🎵 ✅ ✅ ❎ GitLab Demo
Sonixd ⚒️ 🎵 ✅ ✅ ❎ github
sonixd ⚒️ 🎵 ✅ ✅ ❎ github
Supersonic ⚒️ 🎵 ✅ ✅ ❎ github flathub
Symfonium ⚒️ 🎵 ❌ ❌ ☑️ Google Play
Tauon Music Box 🎵 ✅ ✅ ❎ github flathub

📖 Reader

Name OSS Free Paid Downloads
JellyBook 📖 ✅ ✅ ❎ github Izzysoft TestFlight


[!NOTE] Please note that this Markdown file is automatically generated from the clients.yaml file. Contributions should only be made by updating the clients.yaml file. Any updates to the .yaml file will result in this Markdown file being re-generated to reflect those changes.

14. Jellyfin Themes

List of Jellyfin Themes'

ElegantFin: https://lscambo13.github.io/ElegantFin/

CSS: 

@import url("https://cdn.jsdelivr.net/gh/lscambo13/ElegantFin@main/Theme/ElegantFin-jellyfin-theme-build-latest-minified.css");

15. Jellyfin Plugins

banner.png
A List of Awesome Jellyfin Themes and Plugins

[ Plugins • Companion Apps & Tools • Guides • Snippets • Related • Contribute ]

🖌️ Themes

Browse the collection of community themes

📺 Clients

Browse available clients for all platforms

🧩 Plugins

🎨 UI & Customization

📂 Collections & Playlists

▶️ Playback

🔗 Integration & Sync

🔔 Notifications

🔐 Authentication

📚 Library Management

🏷️ Metadata Providers

👾 Companion Apps & Tools

🖼️ Artwork & Posters

🔍 Media Requests & Discovery

📊 Statistics & Watch History

👥 User Management

📁 Media Organization

💬 Subtitles

🎵 Music

📥 Content Import

🔧 Server Administration

🧰 Miscellaneous

📜 Snippets

📖 Guides

This section includes software, guides and tools that are not specifically designed to work with Jellyfin, but can be useful for tasks related to media management or to enhance Jellyfin's functionality.

Communities

This section contains links to communities which focus on Jellyfin or related topics.

Contribute

Contributions welcome! But please read the contribution guidelines first. You can also create a new issue.

16. Jellyfin Enhanced

 

 

Reboot: It is important that after installing Jellyfin Enhanced that you reboot the whole Jellyfin stack. Just a simple reboot from the dashboard screen won't work. Hence, go to Dockhand and reboot the whole stack, from the cli or any other docker configuration software that you are using. After the reboot you will notice that at least a random item button will appear in the right top corner