The Self-Hosted Media Server Stack: Jellyfin, the *arr Apps, and Full Automation
There is a specific kind of frustration that comes from opening Netflix to watch a film you remember being there, only to find it’s gone. Or opening HBO Max — sorry, Max — to finish a series, then discovering the app has been rebranded, your watchlist has vanished, and the show was quietly removed because of a tax write-down. Or splitting a streaming bill seven ways across family members and still not having access to everything you want to watch.
The self-hosted media server stack is the answer. Done right, it gives you a streaming interface that looks and feels like Netflix, a library that never loses content, hardware-accelerated transcoding to any device in your house, automatic subtitle downloads, and a request portal where family members can ask for movies they want — and have them appear automatically. All running on hardware you own, with no monthly subscription, no ads, and no DRM.
This guide walks through the complete stack: every service, how they connect, the full Docker Compose configuration, and the step-by-step setup for each component. By the end, you will have a fully automated media pipeline.
Part 1: Why Self-Host Your Media?
Streaming Service Fatigue Is Real
The economics of streaming have fundamentally changed. The subscriber acquisition era — where every platform competed on price and content breadth — is over. What replaced it is a fragmented, increasingly expensive landscape where:
- Libraries shrink constantly as licensing deals expire or studios pull content for their own platforms
- Prices increase every 6-12 months, with ad-supported tiers becoming the de facto free tier
- Content you want is spread across 4-6 different subscriptions
- Shows get cancelled mid-season; original content disappears in tax restructuring write-downs
- Password sharing, once tolerated, is now actively policed
The cost of maintaining access to a reasonable cross-platform library now regularly exceeds $80-100/month for a household. And you still don’t own any of it.
Owning Your Media
When you manage your own library, you control what is in it. You rip Blu-rays you own, you archive content before it disappears, and you organize it to your standards. The files sit on your hard drives. Nothing expires, nothing gets removed, and there is no buffering driven by server load on a CDN you share with millions of users.
The self-hosted stack also gives you things no streaming service offers:
- Transcoding to any device: Old tablet that only plays H.264? The server transcodes H.265 files on the fly. Slow connection? Transcode to a lower bitrate.
- Offline access: Download to a phone or laptop before a flight, no subscription needed.
- Family sharing with user accounts: Everyone gets their own profile, watch history, and recommendations. Set content age restrictions per account.
- Complete metadata control: Movie posters, trailers, director filmographies — all pulled from TheMovieDB and cached locally.
Jellyfin vs Plex vs Emby
The three main media server platforms occupy different positions on the open source / commercial spectrum:
Jellyfin is fully open source under the GPL. There is no account requirement, no phone-home telemetry, no “premium” tier, no ads, and no paywall on any feature. Hardware transcoding, sync, and multi-user support are all free. It is the most aligned with the self-hosting ethos and the recommendation in this guide.
Plex has a polished, consumer-friendly UI and broad client support. The free tier works for basic streaming but restricts hardware transcoding, offline sync, and some mobile clients behind Plex Pass (~$5/month or $120 lifetime). It requires a Plex account for server setup, and the application phones home to Plex’s servers to function. It is a reasonable choice if you prioritize UI polish and have budget for Plex Pass.
Emby sits in the middle. It is partially open source (the server is open, clients are proprietary) and requires Emby Premiere for features like hardware transcoding and mobile downloads. Less community momentum than Jellyfin.
For a new setup, Jellyfin is the clear recommendation: zero cost, fully open, no account required, and the feature gap with Plex has largely closed.
A note on legality: This guide covers managing media files you legally own — ripped Blu-rays, digital purchases, personal recordings. How you acquire your media is your responsibility.
Part 2: The Full Stack — Every Service and Its Role
Before diving into configuration, it helps to understand exactly what each service does and how they connect.
┌─────────────────────────────────────────────────────────────────┐
│ USER LAYER │
│ Jellyseerr (requests) Jellyfin (streaming) │
│ │ ▲ │
│ │ request movie/show │ scans /data/media │
│ ▼ │ │
├────────────────────────┬──────────────┴──────────────────────── │
│ MANAGEMENT LAYER │ │
│ Radarr (movies) │ Sonarr (TV shows) │
│ │ │ │ │
│ └────────────────┤ │ │
│ ▼ ▼ │
│ Prowlarr (indexer hub) │
│ │ │
│ │ search indexers │
│ ▼ │
│ Indexers (1337x, private trackers, etc.) │
│ │ │
│ Flaresolverr (Cloudflare bypass) │
├────────────────────────────────────────────────────────────────┤
│ DOWNLOAD LAYER │
│ qBittorrent (behind gluetun VPN) │
│ │ │
│ writes to /data/torrents/ │
├────────────────────────────────────────────────────────────────┤
│ SUBTITLE LAYER │
│ Bazarr (auto subtitle download) │
│ monitors /data/media/, fetches from OpenSubtitles │
├────────────────────────────────────────────────────────────────┤
│ STORAGE LAYER │
│ /data/torrents/movies /data/torrents/tv │
│ /data/media/movies /data/media/tv │
└────────────────────────────────────────────────────────────────┘
The data flow in plain English:
- A user opens Jellyseerr and requests a movie
- Jellyseerr sends the request to Radarr
- Radarr searches Prowlarr for available releases
- Prowlarr queries all configured indexers and returns results
- Radarr picks the best match per your quality profile and sends it to qBittorrent
- qBittorrent downloads to
/data/torrents/movies/ - When complete, Radarr hardlinks (not copies) the file to
/data/media/movies/ - Jellyfin sees the new file during its library scan and picks it up
- Bazarr notices the new file and downloads matching subtitles
All of this happens automatically. A user makes a request; 20-60 minutes later it appears in Jellyfin ready to stream.
Part 3: Directory Structure and Storage Planning
Why the Layout Matters
The single most important architectural decision in this stack is the directory layout. Get it right and file management is instant and storage-efficient. Get it wrong and you waste disk space copying gigabytes.
The key is hardlinks. When Radarr “moves” a downloaded file from the torrents directory to the media directory, it does not actually copy the file — it creates a hardlink. A hardlink is a second directory entry pointing to the same underlying data on disk. The result: the file appears in both locations simultaneously, takes up zero additional space, and can be deleted from either location independently.
This only works if both directories are on the same filesystem. This is why all containers must map the same /data path — if Radarr sees /torrents and /media as separate volumes from separate filesystems, hardlinks fail and it falls back to physically copying files (slow, doubles your disk usage while seeding).
Recommended Structure
/data/
├── torrents/
│ ├── movies/ ← qBittorrent writes here (category: movies)
│ ├── tv/ ← qBittorrent writes here (category: tv)
│ └── incomplete/ ← in-progress downloads
└── media/
├── movies/ ← Radarr hardlinks finished downloads here
└── tv/ ← Sonarr hardlinks finished downloads here
Create this structure before deploying:
|
|
Replace 1000:1000 with your actual UID/GID (id -u and id -g).
NAS Storage
If your media lives on a separate NAS device, mount it at /data/media before the containers start:
NFS mount in /etc/fstab:
nas.local:/volume1/media /data/media nfs defaults,nfsvers=4,soft,timeo=30 0 0
SMB mount in /etc/fstab:
//nas.local/media /data/media cifs credentials=/etc/nas-creds,uid=1000,gid=1000,iocharset=utf8 0 0
Keep torrent downloads on a local fast drive (/data/torrents) and media on the NAS. As long as both are on the same logical mount point visible to all containers, hardlinks work — but note that hardlinks across NFS/SMB boundaries do not work. In a NAS setup, you typically want to move (copy + delete) rather than hardlink between local and NAS. Radarr and Sonarr handle this gracefully; just be aware you temporarily double disk usage during the copy.
File Naming
Radarr and Sonarr enforce naming conventions automatically when they import files. You configure the template once and every file gets renamed on import. The defaults are Jellyfin/Plex-compatible, so metadata matching works out of the box.
Part 4: The Complete Docker Compose Setup
Create a project directory and drop in the following files:
|
|
.env file
|
|
docker-compose.yml
|
|
Create config directories and deploy:
|
|
NVIDIA GPU Transcoding
If you have an NVIDIA GPU instead of Intel, replace the jellyfin devices section with:
|
|
This requires nvidia-container-toolkit installed on the host (apt install nvidia-container-toolkit).
Part 5: Configuring qBittorrent
First Login
qBittorrent’s web UI is accessible at http://server-ip:8080. The default credentials are:
- Username:
admin - Password:
adminadmin
Change the password immediately in Settings → Web UI → Authentication.
Download Path Configuration
In Settings → Downloads:
- Default Save Path:
/data/torrents/incomplete - Keep incomplete torrents in:
/data/torrents/incomplete - Move completed downloads to: leave unchecked (Radarr/Sonarr manage placement via categories)
Category Setup
Radarr and Sonarr use qBittorrent categories to track their downloads. Create two categories:
In qBittorrent, right-click the left sidebar → Add Category:
| Category | Save Path |
|---|---|
movies |
/data/torrents/movies |
tv |
/data/torrents/tv |
When Radarr sends a download to qBittorrent, it automatically assigns the movies category, which routes the finished file to /data/torrents/movies. Radarr then picks it up from there and hardlinks it to /data/media/movies.
Speed Limits and Scheduling
In Settings → Speed:
- Set upload limits during peak hours to avoid saturating your connection
- Use the Alternative Speed Limits and schedule them under Settings → BitTorrent → Schedule to apply slower speeds during the day
VPN Kill Switch with gluetun
The Docker Compose above runs qBittorrent with network_mode: service:gluetun, which routes all qBittorrent traffic through the gluetun container’s VPN tunnel. If the VPN drops, gluetun kills the network interface — the kill switch. qBittorrent loses connectivity entirely rather than leaking your real IP.
To configure gluetun for different providers, adjust the environment variables:
Mullvad (WireGuard):
|
|
ProtonVPN (OpenVPN):
|
|
Private Internet Access:
|
|
Verify the VPN is working before proceeding: docker exec gluetun curl ifconfig.io should return a VPN IP, not your home IP.
Part 6: Configuring Prowlarr
What Prowlarr Does
Prowlarr is a single control plane for all your torrent and Usenet indexers. Instead of configuring each indexer separately in Radarr and Sonarr, you add them once in Prowlarr and it syncs them to all your *arr apps automatically. It also handles searching and returns standardized results regardless of whether the indexer is a torrent tracker or a Usenet provider.
Access Prowlarr at http://server-ip:9696.
Adding Indexers
Navigate to Indexers → Add Indexer. Prowlarr includes built-in support for hundreds of public and private trackers. Some useful public ones:
- 1337x — large general tracker
- YTS (YIFY) — high-quality movie encodes at smaller file sizes
- EZTV — TV shows
- Nyaa — anime
For private trackers, you’ll need your credentials from the respective tracker.
After adding an indexer, click Test to confirm connectivity.
Connecting Prowlarr to Radarr and Sonarr
Navigate to Settings → Apps → Add Application:
-
Add Radarr:
- Server:
http://radarr:7878 - API Key: (find in Radarr → Settings → General → API Key)
- Sync Level: Full Sync
- Server:
-
Add Sonarr:
- Server:
http://sonarr:8989 - API Key: (find in Sonarr → Settings → General → API Key)
- Sync Level: Full Sync
- Server:
Once configured, any indexer you add to Prowlarr automatically appears in both Radarr and Sonarr. No manual indexer configuration needed in either app.
Flaresolverr Integration
Some indexers are protected by Cloudflare’s bot detection. Flaresolverr solves these challenges by running a real browser session in the background.
In Prowlarr → Settings → Indexers → Add Proxy:
- Type: FlareSolverr
- URL:
http://flaresolverr:8191
Then, when adding a Cloudflare-protected indexer, select the FlareSolverr proxy in the indexer settings.
Part 7: Configuring Radarr
Access Radarr at http://server-ip:7878.
Root Folder
Settings → Media Management → Root Folders → Add Root Folder:
- Path:
/data/media/movies
Adding qBittorrent as a Download Client
Settings → Download Clients → Add:
- Client: qBittorrent
- Host:
gluetun(the container name — qBittorrent’s network lives in gluetun) - Port:
8080 - Username:
admin - Password: (your new password)
- Category:
movies
The category is critical — it ensures qBittorrent routes the download to /data/torrents/movies.
Quality Profiles
Settings → Quality Profiles. The default HD-1080p profile works well for most setups. Customize if you want:
Quality Profile: "1080p Preferred"
Upgrades allowed: Yes
Upgrade Until: Bluray-1080p
Quality order (best first):
1. Bluray-1080p (Remux)
2. Bluray-1080p
3. WEB-DL 1080p
4. WEBRip 1080p
5. HDTV-1080p
--- cutoff above ---
6. WEB-DL 720p
(lower qualities disabled)
Naming Format
Settings → Media Management → Movie Naming:
Standard Movie Format:
{Movie Title} ({Release Year}) {Quality Full}
Movie Folder Format:
{Movie Title} ({Release Year})
Example output: The Dark Knight (2008) Bluray-1080p
This format is fully compatible with Jellyfin and Plex metadata matching.
Custom Formats
Custom formats let you express preferences beyond quality resolution. In Settings → Custom Formats:
Create a Prefer x265 format:
Name: Prefer x265
Conditions:
- Release Title: x265|HEVC|H\.265 (regex)
Score: +10
Create an Avoid CAM format:
Name: Avoid CAM
Conditions:
- Release Title: CAM|TS\.|TELESYNC (regex)
Score: -10000 (hard block)
Radarr Lists
Settings → Import Lists lets you auto-populate your movie library from external lists. Options include:
- IMDb Watchlist (your personal list)
- Trakt.tv lists (popular lists, themed collections)
- StevenLu’s Popular Movies
- Radarr’s own discovery feeds
With a list configured, Radarr monitors it and automatically adds (and optionally searches for) new entries.
Adding a Movie Manually
Movies → Add New → search → select result → pick quality profile → Add Movie. Radarr searches all configured indexers, finds a matching release, and queues it in qBittorrent. The whole process takes seconds.
Part 8: Configuring Sonarr
Sonarr at http://server-ip:8989 is functionally identical to Radarr but for TV shows. The same root folder, download client, and quality profile setup applies.
Root Folder
Settings → Media Management → Root Folders:
- Path:
/data/media/tv
Download Client
Same as Radarr but set Category to tv.
Series Types
When adding a series, Sonarr asks for a type:
- Standard: Regular scripted TV with S01E01 naming (the default)
- Daily: News, talk shows, late night — episodes identified by air date
- Anime: Absolute episode numbering common in anime releases
Season Monitoring Options
When adding a show, you choose what to monitor:
- All Seasons: Grab everything, past and present
- Future Seasons: Only monitor upcoming seasons (useful for ongoing shows you just want to follow going forward)
- Latest Season: Just the most recent season
- Missing Episodes: Only grab episodes you’re missing from seasons you’ve watched
Rename Format for TV
Settings → Media Management → Episode Naming:
Standard Episode Format:
{Series Title} - S{season:00}E{episode:00} - {Episode Title}
Daily Episode Format:
{Series Title} - {Air-Date} - {Episode Title}
Series Folder Format:
{Series Title}
Season Folder Format:
Season {season:00}
This produces a clean hierarchy:
/data/media/tv/
└── Breaking Bad/
├── Season 01/
│ ├── Breaking Bad - S01E01 - Pilot.mkv
│ └── Breaking Bad - S01E02 - Cat's in the Bag.mkv
└── Season 02/
└── ...
Jellyfin and Plex both parse this format perfectly for metadata matching.
Part 9: Configuring Jellyfin
Jellyfin is available at http://server-ip:8096.
Initial Setup Wizard
On first launch, Jellyfin walks you through:
- Create admin account (use a strong password)
- Add media libraries (see below)
- Set preferred language for metadata
Library Setup
Dashboard → Libraries → Add Media Library:
Movies:
- Content type: Movies
- Folders:
/data/media/movies - Metadata downloader: TheMovieDB (enable, move to top)
- Image fetchers: TheMovieDB, FanArt (optional)
TV Shows:
- Content type: Shows
- Folders:
/data/media/tv - Metadata downloader: TheTVDB, TheMovieDB
- Image fetchers: TheTVDB, FanArt
Trigger a full library scan after setup: Dashboard → Libraries → (library name) → Scan All Libraries.
Hardware Transcoding
Hardware transcoding lets the server offload video encoding from the CPU to dedicated silicon, supporting many more simultaneous streams while using far less power.
Dashboard → Playback → Transcoding:
Intel Quick Sync (VAAPI) — covered by the /dev/dri device passthrough in Compose:
- Hardware acceleration: Video Acceleration API (VAAPI)
- VAAPI device:
/dev/dri/renderD128 - Enable hardware decoding for H.264, HEVC, VP9, AV1 (check all supported)
- Enable hardware encoding: yes
NVIDIA (with nvidia-container-toolkit Compose setup):
- Hardware acceleration: NVENC
- Enable hardware decoding: yes for all supported codecs
Verify transcoding is working by starting playback and checking the session in Dashboard → Dashboard (home). An active transcode shows the stream codec and whether it’s hardware-assisted.
Direct Play vs Transcode: When the client can play the file natively (same codec, right bitrate, matching audio), Jellyfin serves the file directly with zero server CPU overhead. Transcoding only happens when the client needs a different format or lower bitrate. Encourage direct play by using common codecs (H.264 MKV or MP4) and ensuring clients have capable hardware decoders.
User Management
Dashboard → Users → Add User. Create accounts for each family member. Per user you can:
- Set a PIN or password
- Restrict to specific libraries
- Set content rating limits (G, PG, PG-13, etc.)
- Enable/disable downloads
- Control playback permissions
Clients
Jellyfin has official clients for nearly every platform:
| Platform | Client |
|---|---|
| Web browser | Jellyfin Web (built-in) |
| Android | Jellyfin for Android (Play Store) |
| iOS / iPadOS | Jellyfin for iOS (App Store) |
| Apple TV | Infuse or Jellyfin for Apple TV |
| Roku | Jellyfin for Roku |
| Amazon Fire TV | Jellyfin for Fire TV |
| Android TV / Google TV | Jellyfin for Android TV |
| Kodi | Jellyfin for Kodi plugin |
| Desktop | Jellyfin Media Player |
Useful Plugins
Dashboard → Plugins → Catalog:
- Intro Skipper: Automatically detects and marks intro sequences; adds “Skip Intro” button à la Netflix
- Open Subtitles: Direct integration with OpenSubtitles.com for on-demand subtitle fetching within Jellyfin
- Playback Reporting: Usage analytics, watch time statistics
- Merge Versions: Deduplicate movies where you have multiple quality files
Part 10: Bazarr — Automatic Subtitles
Bazarr at http://server-ip:6767 monitors your media library and automatically downloads subtitles for every file.
Connecting to Radarr and Sonarr
Settings → Radarr:
- Address:
radarr - Port:
7878 - API Key: (from Radarr → Settings → General)
- Base URL: (leave empty)
Settings → Sonarr: same pattern with port 8989.
Once connected, Bazarr imports your full library from both services.
Subtitle Providers
Settings → Providers → Add Provider:
- OpenSubtitles.com (recommended): Create a free account at opensubtitles.com. Very large library, good language coverage.
- Subscene: Large library, no account required
- Podnapisi: Good for non-English content
Language Profiles
Settings → Languages → Add Profile:
Profile: "English + Spanish"
Languages:
- English (SDH preferred for hearing impaired)
- Spanish
Assign this profile to all movies and shows via Settings → Radarr → Default Settings.
Automatic Download Behavior
In Settings → Subtitles:
- Upgrade previously downloaded subtitles: Yes (replaces poor quality subs when better ones appear)
- Download hearing-impaired subtitles: depends on preference
- Score threshold: Only download if match score > 80 (avoids poor machine-translated subs)
Part 11: Jellyseerr — The Netflix-Like Request Interface
Jellyseerr at http://server-ip:5055 is the public face of your media server. It is where users go to request content — without needing access to Radarr, Sonarr, or any of the backend tooling.
Initial Setup
On first launch, Jellyseerr prompts you to:
-
Sign in with Jellyfin: Enter your Jellyfin URL (
http://jellyfin:8096), admin credentials. Jellyseerr then uses Jellyfin for all user authentication — your family logs into Jellyseerr with their Jellyfin usernames. -
Configure Radarr:
- Default Server: Yes
- Server Name: Main Radarr
- Hostname:
radarr - Port:
7878 - API Key: (from Radarr)
- Quality Profile: 1080p Preferred
- Root Folder:
/data/media/movies - Enable: Yes
-
Configure Sonarr: Same pattern with
sonarr:8989.
The Request Workflow
From a user’s perspective, Jellyseerr feels like a streaming service discovery interface:
- Search for a movie or show
- Click Request
- Done — Jellyseerr sends the request to Radarr or Sonarr in the background
Within minutes to an hour (depending on indexer speed and file size), the content appears in Jellyfin. Users get a notification when it’s ready.
Approval Workflows
Settings → General:
- Auto-Approve Requests: If enabled, all requests go straight to Radarr/Sonarr without admin review. Good for trusted family setups.
- Manual Approval: Requests queue for admin review. Good if you want to gatekeep or manage storage.
Per-user overrides are possible: Settings → Users → (user) → enable auto-approve for specific users.
Notifications
Settings → Notifications. Jellyseerr can notify you (and users) through:
- Discord (webhook): Post to a family Discord server when requests are approved and when media is available
- Email: Native SMTP support
- Slack: Webhook integration
- Telegram, Pushover, Ntfy: For push notifications to phones
Configure a Discord webhook to keep everyone informed without them polling the UI.
Part 12: Exposing Jellyfin Externally
Your internal services need to stay internal. Radarr, Sonarr, Prowlarr, qBittorrent, Bazarr — none of these should ever be accessible from the internet. They have no meaningful authentication and contain your full download history.
Jellyfin, however, is designed to be accessed remotely. There are three good approaches:
Option 1: Traefik Reverse Proxy with Let’s Encrypt
If you’re already running Traefik (see the Traefik Complete Guide), adding Jellyfin is just labels:
|
|
This gives you https://jellyfin.yourdomain.com with an auto-renewing Let’s Encrypt certificate. Requires port 443 forwarded to your server.
Option 2: Cloudflare Tunnel
If you can’t or don’t want to open ports on your router, Cloudflare Tunnel creates an outbound-only encrypted connection from your server to Cloudflare’s edge:
|
|
Or as a Compose service:
|
|
Configure the tunnel in the Cloudflare Zero Trust dashboard to route jellyfin.yourdomain.com to http://jellyfin:8096. Zero port forwarding required.
Option 3: Tailscale
For a family setup where everyone is technically proficient enough to install Tailscale on their devices, this is the cleanest option. Install Tailscale on your server and all client devices:
|
|
Family members install the Tailscale app on their phone or TV and connect to the same tailnet. They access Jellyfin via your server’s Tailscale IP — fully encrypted, no public exposure, no port forwarding. The Jellyfin app on Apple TV, Roku, and Android TV works seamlessly over Tailscale.
Security Reminder
Regardless of the external access method, apply these rules:
- Use a strong admin password on Jellyfin
- Enable two-factor authentication if your external proxy supports it
- Never expose Radarr, Sonarr, Prowlarr, Bazarr, Jellyseerr, or qBittorrent directly to the internet
- If using Traefik, put a middleware like
ipAllowListon all internal services to ensure they’re only accessible locally
Part 13: Maintenance and Long-Term Operations
Library Scans
Jellyfin runs a scheduled library scan by default (every 24 hours). For a more responsive experience — new content appears minutes after download — enable real-time monitoring:
Dashboard → Libraries → (library) → Display: Enable real-time monitoring.
Jellyfin watches the filesystem with inotify and picks up new files immediately. On large NAS-backed libraries over NFS, real-time monitoring can be unreliable; scheduled scans are more stable in that case.
Health Checks
Radarr and Sonarr both have a Health section (System → Status → Health). Check it weekly. Common issues it surfaces:
- Indexers returning no results (the tracker may be down or changed its URL)
- Download client unreachable (VPN dropped, container restarted)
- Root folder not writable (permissions issue)
- Disk nearly full
Storage Monitoring
Add a Prometheus + Grafana alert (see the Prometheus + Grafana Stack guide) to notify when /data exceeds 80% capacity:
|
|
A simpler option: Uptime Kuma has a disk space monitor built in that can send Telegram/Slack/Discord notifications.
Updating Containers
Keep all images current without manual work by tracking your update schedule. Pull and recreate:
|
|
Or use Watchtower for fully automatic updates:
|
|
Watchtower with WATCHTOWER_CLEANUP=true automatically removes old image layers after updating, keeping disk usage in check.
Seeding and Reclaiming Space
After a torrent completes and Radarr/Sonarr hardlink it to the media directory, the torrent continues seeding from /data/torrents/. You want to seed for a reasonable ratio (1.0 is the community norm for public trackers) before removing the torrent file.
In Radarr/Sonarr → Settings → Download Clients → (qBittorrent entry):
- Remove Completed: Enable
- Removal Delay:
0minutes (or set a delay to ensure adequate seeding time)
For ratio-based cleanup, configure it directly in qBittorrent: Settings → BitTorrent → Seeding Limits → set ratio to 1.0 and pause or remove torrent when met.
4K Setup
Running a 4K library alongside your 1080p library requires separate *arr instances, as each can only target one quality tier per instance cleanly.
The standard setup:
- Radarr4K — separate container on port
7879, root folder/data/media/movies4k - Sonarr4K — separate container on port
8990, root folder/data/media/tv4k - Jellyfin — add
/data/media/movies4kas a separate Movies library or subfolder
In Radarr4K’s quality profile, set the cutoff to Bluray-2160p and enable HDR custom format preferences. For hardware transcoding, 4K HDR tone-mapping to SDR for clients that don’t support HDR requires either:
- A GPU with HDR tone-mapping support (NVIDIA with recent drivers, or Intel Gen 12+)
- Or accepting that non-4K clients need significant CPU resources for tone-mapped transcodes
A practical rule: if more than half your viewers are on 4K HDR TVs, maintain a 4K library. Otherwise, a high-quality 1080p encode is often the better tradeoff for streaming flexibility.
Putting It All Together
The beauty of this stack is that once it is configured — a few hours of work — it runs itself indefinitely. Add a new show to Sonarr and every episode, past and future, is managed for you. A family member opens Jellyseerr, requests something they saw advertised, and finds it available in Jellyfin before the week is out. Subtitles appear automatically. Jellyfin serves the right format to every device without you thinking about it.
The full startup checklist:
[ ] /data directory structure created, permissions set
[ ] docker-compose.yml and .env deployed, all containers healthy
[ ] gluetun VPN verified: docker exec gluetun curl ifconfig.io
[ ] qBittorrent: default password changed, categories created
[ ] Prowlarr: indexers added and tested, Radarr + Sonarr connected
[ ] Radarr: root folder set, download client configured, quality profile set
[ ] Sonarr: root folder set, download client configured, naming format set
[ ] Jellyfin: admin account created, libraries scanned, hardware transcode enabled
[ ] Bazarr: providers configured, language profile set, Radarr/Sonarr connected
[ ] Jellyseerr: Jellyfin auth configured, Radarr + Sonarr connected
[ ] External access: Traefik / Cloudflare Tunnel / Tailscale configured for Jellyfin only
[ ] Storage monitoring alert configured
The first time you see a request come in through Jellyseerr, watch the download start in qBittorrent, see Radarr import the file, and then find it ready to stream in Jellyfin — all without touching anything — it clicks. This is what the automation was for.
Comments