dylanzickus.com / Self-Hosted Media Stack

Self-Hosted Media Stack

A full homelab media pipeline on a Raspberry Pi 5 — Jellyfin, automated library management via the arr stack, VPN-tunneled downloads, and cross-network hardware transcoding with Intel Quick Sync.

Raspberry Pi 5 Docker Jellyfin WireGuard / AirVPN Intel QSV Tailscale OpenMediaVault

A fully self-hosted media server, automated library management pipeline, and transcoding infrastructure — built on a Raspberry Pi 5, an old workstation, and a lot of troubleshooting.

What is this?

This is a writeup of a project I've been building and iterating on throughout 2026: a home media stack that replaces streaming services with a fully self-hosted setup. No subscriptions, no content disappearing, no algorithmic recommendations — just a local library I control, available on any device anywhere.

The stack handles everything from finding and downloading media, to organizing and cataloging it, to streaming it to any device with near-zero transcoding. There's also an automated transcoding pipeline that normalizes the library's codec mix for maximum compatibility.

It's the kind of project that started simple and kept growing. What began as "just run Jellyfin on a Pi" turned into a multi-machine system with VPN-tunneled downloads, cross-network hardware transcoding, and more docker-compose files than I'd like to admit.


Architecture Overview

┌─────────────────────────────────────────────────┐
│                   nas-pi (Pi 5)                  │
│                                                  │
│  Jellyfin (native)   ←── media library           │
│  Radarr / Sonarr / Lidarr / Bazarr              │
│  Prowlarr (indexer proxy)                        │
│  qBittorrent ──────────── Gluetun (AirVPN)      │
│  Tdarr Server (no local workers)                 │
│  Homarr · Jellystat · Beszel · Uptime-Kuma      │
└──────────────┬──────────────────────────────────┘
               │ Tailscale (Samba/SMB)
               │
┌──────────────▼──────────────────────────────────┐
│                  z240 (HP Workstation)            │
│                                                  │
│  Tdarr Node (Docker/Podman)                      │
│  Intel QSV hardware encode (HD P530)             │
└─────────────────────────────────────────────────┘

All download traffic routes through a WireGuard VPN tunnel (AirVPN via Gluetun). The arr stack containers share the VPN container's network namespace, so nothing leaks if the tunnel drops. Jellyfin streams directly to clients on the local network or via Tailscale from anywhere.

The transcoding node runs on a separate machine connected over Tailscale, using Intel Quick Sync for hardware-accelerated H.264 encoding. Files travel over SMB-on-Tailscale between machines.


The Stack at a Glance

Component Role Page
nas-pi (Pi 5 + OMV) NAS, host for everything Infrastructure
Jellyfin Media server, streaming Jellyfin
Radarr / Sonarr / Lidarr / Bazarr Automated library management The arr Stack
Prowlarr + qBittorrent + Gluetun Indexing, downloading, VPN routing VPN & Downloading
Tdarr + z240 QSV node Automated transcoding pipeline Tdarr Pipeline
Homarr, Beszel, Jellystat, Uptime-Kuma Dashboard & monitoring Infrastructure

Timeline

Q1 2026 — Foundation

Set up the Raspberry Pi 5 as a NAS running OpenMediaVault. Got Jellyfin running natively (not containerized — more on why). Figured out storage layout, permissions, and remote access via Tailscale. This phase was mostly infrastructure groundwork: getting a stable, remotely accessible machine that could serve media reliably.

Q2 2026 — Automation

Deployed the full arr stack: Radarr, Sonarr, Lidarr, Bazarr, Prowlarr, and qBittorrent — all containerized and routed through a Gluetun VPN tunnel. Spent significant time on hardlink configuration (critical for keeping a clean library without duplicating storage), quality profiles, and custom format scoring in Radarr/Sonarr. Also dealt with a security incident involving disguised malware in torrent files — documented in the arr stack page.

Summer 2026 — Transcoding & Monitoring

Built the Tdarr transcoding pipeline to normalize the library to H.264 for direct play everywhere. This turned into a deep rabbit hole: NFS failures on a memory-constrained Pi, a custom Docker image to get Intel QSV working, cross-network SMB mounts over Tailscale, and a lot of vainfo output. Also set up the full monitoring stack (Beszel, Jellystat, Uptime-Kuma) and a Homarr dashboard to tie everything together.


Why Self-Host?

Honestly, a mix of practical and philosophical reasons:

The tradeoff is real though: you become your own ops team. When something breaks at 11pm, that's on you to fix.


Pages in This Section

⚙️
The arr Stack
Radarr, Sonarr, Lidarr, Bazarr, and Prowlarr automating the full library lifecycle. Hardlink setup, custom format scoring, and a security incident with malware-disguised torrents.
RadarrSonarrProwlarrHardlinks
View page →
🖥️
Infrastructure
The Raspberry Pi 5 NAS running OpenMediaVault, remote access via Tailscale, and the full monitoring stack — Beszel, Jellystat, Homarr, Uptime-Kuma.
Pi 5OpenMediaVaultTailscaleBeszel
View page →
📺
Jellyfin
Open-source media server handling library cataloging, metadata, and streaming. Why it runs natively instead of containerized, and the crash-debugging saga.
JellyfinDirect playStreaming
View page →
🎬
Tdarr Pipeline
Automated transcoding to normalize 117 files to H.264 for direct play. Cross-network QSV encoding, a custom Docker image to get VA-API working, the NFS failure, and the OMV/Samba debugging rabbit hole.
TdarrIntel QSVH.264FFmpeg
View page →
🔐
VPN & Downloading
How Gluetun creates a container-level WireGuard tunnel that the entire download stack shares. AirVPN, port forwarding, kill switch behavior, and Docker network namespaces.
GluetunWireGuardAirVPNDocker
View page →