🎬 Media Stack
Architecture Overview
| Service | Type | Zone | Role |
|---|---|---|---|
| Gluetun | VPN Gateway | Zone 2 | AirVPN Tunnel. All download traffic routes through here. |
| qBittorrent | Downloader | Zone 2 | Primary torrent client. No direct internet access. |
| Radarr/Sonarr | Managers | Zone 1 | Library management. Talks to Zone 2 via local gateway. |
| Jellyfin | Player | Zone 1 | Hardware Accelerated (AMD GPU) media streaming. |
| Seerr | Requester | Zone 1 | The "Netflix-style" frontend for users to request content. |
📚 Documentation Map
Before diving into the code, here is what each guide covers:
The Automation Engine (VPN + Arrs + Indexers)
Read this to better understand how the "back-end" works
- The VPN Bubble: How Gluetun isolates qBittorrent from the internet.
- The Hybrid Indexers: How to Setup Indexers (Prowlarr & Jackett working together).
- Atomic Moves: The exact folder structure required to make file moves instant (Hardlinks).
- Remote Path Mapping: The critical setting that prevents Radarr from "losing" files downloaded by the VPN client.
Media Core Setup (Jellyfin + Hardware Accel)
Read this to configure the "front-end" playback
- AMD GPU Passthrough: How to pass
/dev/dri/renderD128to Docker for transcoding, since I am using AMD GPU to help with the transcoding - Network Trust: Configuring Jellyfin to trust Caddy and identify local LAN devices (so it doesn't transcode locally).
- Seerr Integration: Connecting the request UI to the manager apps.
Bonus: "Story Mode" - The Lifecycle of a Request
A narrative walkthrough
- Traces a single packet from the moment a user clicks "Request" on their phone, through the Reverse Proxy, API calls, VPN Tunnel, BitTorrent swarm, and finally to the TV screen. Useful for visualizing the data flow.
Service Structure
The stack is split into two logical Compose files to manage dependencies and startup order effectively.
media-stack/
├── jellyfin/ # The "Front of House" (Playback & Requests)
| ├── jellyfin-config
| ├── seerr-config
├── vpn-arr-stack/ # The "Back of House" (Acquisition & Automation)
├── gluetun # VPN Configuration
├── profilarr # Custom Format Syncing
├── prowlarr # Indexer Management
└── ... # (Radarr, Sonarr, Bazarr, etc.)
Directory Preparation
We use Bind Mounts to persist data. To prevent permission errors (Docker creating root-owned folders), we must manually create the folder structure before starting the containers.
# Jellyfin & Jellyseerr
mkdir -p jellyfin/{jellyfin-cache,jellyfin-config,seerr-config}
# VPN & Automation Configs
# 1. Gluetun (the auth folder is where we will house the config.toml file)
mkdir -p vpn-arr-stack/gluetun/{config,auth}
# 2. Arr Stack & Indexers
# This creates a specific 'config' subfolder for each service
mkdir -p vpn-arr-stack/{bazarr,flaresolverr,jackett,profilarr,prowlarr,radarr,sonarr,transmission,qbittorrent}/config
mkdir -p vpn-arr-stack/speedtest-tracker
# Create empty .env files
touch jellyfin/.env vpn-arr-stack/.env
Prerequisites
- Gateway Stack deployed (for Reverse Proxy access).
- WireGuard Config & Paid VPN (AirVPN) Service (for Gluetun/AirVPN).