Building My Self-Hosted Home Media Server with Docker

A complete walkthrough of my home server — TrueNAS for backups, Proxmox for virtualization, and a fully automated Docker media stack with the *Arr apps and Jellyfin.

5 min read

Sabin Shrestha

Full-Stack Developer — Next.js, React & React Native

Summary

How my home server is put together end to end: a TrueNAS box handling backups and photos, a Proxmox box running my VMs and media stack, and a fully automated Docker pipeline that turns "search for a movie" into a watchable file with zero manual steps in between.

Why I built a home server #

I've always wanted a system where I could search for a movie or TV show, click Request, and let everything else happen automatically — no manually hunting for torrents, no manually downloading files, no organizing folders by hand, no trying to remember what I've already watched.

After experimenting with a bunch of different tools, I ended up with a fully self-hosted setup split across two machines, each doing one job well.

The hardware: two machines, two jobs #

Setup one — TrueNAS (storage & backup) #

This box exists for one reason: don't lose my data. It runs two 1TB hard drives mirrored together (RAID1-style), so if one drive dies, the other still has everything — photos, documents, all of it.

On top of that storage, two apps handle the actual backup workflows:

  • Immich — photo backup and management, essentially my self-hosted alternative to Google Photos.
  • Nextcloud — general file storage and sync, for everything that isn't a photo.

Setup two — Proxmox (virtualization & media) #

This box is the workhorse. It runs Proxmox as a hypervisor, hosting multiple VMs side by side — an Ubuntu VM and a Windows 10 VM — on a 2TB hard drive for media storage plus a 256GB SSD for the OS and the apps themselves, keeping fast storage separate from bulk media storage.

The Ubuntu VM is where the entire Docker-based media stack lives — which is the part of this setup I actually want to talk about in detail.

The overall architecture #

The media stack is built around one idea: requesting something should be the only manual step. Everything after that — finding it, downloading it, importing it, organizing it — happens on its own.

User
 │
 ▼ (homeserver.com via Traefik)
Jellyseerr ── Req: gets movie/series details,
 │            requests the file from the right service
 ├── Sonarr   (TV)
 ├── Radarr   (Movies)
 └── Lidarr   (Music)
       │
       ▼
   Prowlarr ── searches configured indexers
       │
       ▼
   qBittorrent ── downloads the torrent
       │
       ▼
Sonarr / Radarr / Lidarr ── import & organize into the library
       │
       ▼
     Data (Movies, TV shows, Music, Books)
       │              │
       ▼              ▼
   Jellyfin       Maintainerr
 (streams it)   (cleans up old/
       │          unwatched media)
       ▼
     Watch (via Traefik → homeserver.com) → User

Walking through the components #

ComponentRole
TraefikReverse proxy — maps every service to a subdomain under homeserver.com so nothing needs a raw IP:port to access.
JellyseerrThe front door. A user picks a movie or show, Jellyseerr pulls the metadata and sends a request to the right service.
Sonarr / Radarr / LidarrOne manager per media type — TV, movies, and music respectively. Each tracks what's wanted, what's already downloaded, and hands searches off to Prowlarr.
ProwlarrA single indexer manager shared by Sonarr, Radarr, and Lidarr, so indexers only need to be configured once instead of three times.
qBittorrentThe download client. Once Prowlarr finds a matching release, qBittorrent grabs it.
JellyfinThe media server — organizes the library and streams everything to any device.
MaintainerrWatches the library and automatically flags/removes old or unwatched movies and shows based on rules I've set, so storage doesn't just grow forever.

The request flow, step by step #

  1. I open Jellyseerr (through Traefik, at homeserver.com) and search for something.
  2. Jellyseerr fetches the details and sends a request to Sonarr, Radarr, or Lidarr depending on the media type.
  3. That service asks Prowlarr to search its configured indexers for a matching release.
  4. Prowlarr returns candidate torrent files, and the best match gets sent to qBittorrent.
  5. qBittorrent downloads it, then hands it back to Sonarr/Radarr/Lidarr to import, rename, and file it into the library correctly.
  6. The finished file lands in the shared media library (movies, TV shows, music, books).
  7. Jellyfin picks it up automatically and it's ready to stream — no manual folder work, ever.
  8. In the background, Maintainerr keeps an eye on the library and clears out old or unwatched titles on a schedule, so the 2TB drive doesn't quietly fill up.

Key takeaways #

  • Splitting the home server into two purpose-built machines (TrueNAS for "don't lose this data," Proxmox for "run everything else") kept each box simple and easy to reason about.
  • Mirrored drives on TrueNAS mean a single hard drive failure doesn't turn into a data-loss event.
  • Centralizing indexers in Prowlarr instead of configuring them separately in Sonarr, Radarr, and Lidarr saved a lot of repeated setup.
  • Automating cleanup with Maintainerr was as important as automating downloads — without it, storage just fills up silently.
  • Traefik in front of everything means every service gets a clean subdomain instead of a bookmark full of ip:port addresses.

Conclusion #

The end result is a home server where requesting a movie is genuinely the only thing I ever do by hand. Everything else — searching, downloading, importing, organizing, streaming, and even cleaning up old media — runs on its own. It's been a fun project to build piece by piece, and there's still room to grow: more storage, more automation, maybe a second Proxmox node down the line.

© 2026 Sabin Shrestha