Skip to content

🎬 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/renderD128 to 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).