A completely self-hosted media server running on local hardware, documented step-by-step so you can fork, replicate, and hack on it.
https://github.com/bunnyhp/HOmeLab/blob/main/cybersecurity%20125605.png?raw=true
- Architecture
- Hardware
- Host & VM Setup
- Storage Layout
- Applications
- Networking & Remote Access
- Back-ups & Maintenance
- Roadmap
- License
┌────────────────────────────┐
│ Proxmox VE (Host) │
│ • Intel i5-10400F │
│ • 32 GB DDR4 ECC │
│ • 1 × 1 TB NVMe (ZFS boot)│
└───────┬────────────────────┘
│ virt-IO (10 Gb)
┌───────▼────────────────────┐
│ VM — TrueNAS SCALE (24 GB)│
│ • tank ⇢ 4 × 4 TB HDD RAID-Z1 │
│ • apps ⇢ 1 × 1 TB SSD striped │
│ • Kubernetes + Docker │
│ │
│ ┌────────────────────────┐ │
│ │ Plex Media Server │ │
│ │ qBittorrent-nox │ │
│ │ Radarr / Sonarr │ │
│ │ Lidarr / Bazarr │ │
│ │ Jellyseerr │ │
│ └────────────────────────┘ │
└─────────────────────────────┘
Everything lives inside the TrueNAS SCALE VM. Apps are deployed via the official Apps catalogue (Kubernetes), but you can also reproduce them with Docker Compose.
| Part | Model | Purpose |
|---|---|---|
| Server | Dell OptiPlex 7080 SFF | Cheap, quiet, plenty of PCIe lanes |
| CPU | Intel Core i5-10400F | 6C/12T; quick Plex transcodes |
| RAM | 32 GB DDR4 ECC | ZFS ARC + containers |
| Boot | 1 TB PCIe NVMe (WD Black SN770) | Proxmox install & VMs |
| Pool | 4 × 4 TB Seagate IronWolf (RAID-Z1) | tank dataset (media) |
| App SSD | 1 TB Crucial MX500 SSD | apps dataset (containers) |
| Network | Intel X550-T2 (10 GbE) | Fast LAN transfers |
Swap in whatever hardware you have — just make sure TrueNAS sees direct-attached disks (pass-through or VirtIO SCSI).
# ISO installer → ‘ZFS (RAID-1) on NVMe’ for boot mirror if you have 2 drives
pveam updateSnapshot-friendly, hands-off backups (see Back-ups).
| Setting | Value |
|---|---|
| Cores | 6 (host-passthrough) |
| Memory | 24 GB static |
| Disks | Pass-through each HDD/SSD with qm set <id> -scsi<number> /dev/disk/by-id/… |
| NIC | VirtIO paravirtualised |
Install TrueNAS SCALE 24.04. Enable Applications (Kubernetes) under System Settings → Advanced.
tank/
├── media/
│ ├── movies/
│ ├── tv/
│ ├── music/
│ └── photos/
└── downloads/
├── incomplete/
└── complete/
media/*— readonly for Plexdownloads/incomplete— qBittorrent temp filesdownloads/complete— finished torrents/usenet; watched by the *arr stack
Permissions: create an
appsgroup, add each Kubernetes workload’s UID/GID, thenchown -R :apps tank/*andchmod 775so containers can write.
| App | Purpose | URL | Deployment | Notes |
|---|---|---|---|---|
| Plex | Streams local media to any device | http://truenas:32400 |
TrueNAS Chart → plex-official |
Grab claim token from https://plex.tv/claim |
| qBittorrent | Torrent client with Web UI | http://truenas:8080 |
Chart qbittorrent-nox |
Set DOWNLOAD_DIR=/downloads/incomplete |
| Radarr | Movie automation | http://truenas:7878 |
Chart radarr |
Connect to qBittorrent + Plex |
| Sonarr | TV automation | http://truenas:8989 |
Chart sonarr |
Same indexers as Radarr |
| Lidarr | Music automation | http://truenas:8686 |
Chart lidarr |
Warm-up MusicBrainz cache (first run is slow) |
| Bazarr | Subtitle management | http://truenas:6767 |
Chart bazarr |
Link Radarr/Sonarr paths |
| Jellyseerr | Media request portal | http://truenas:5055 |
Chart jellyseerr |
Auth via Plex OAuth |
Container images come from LinuxServer.io where possible; tags pinned to known-good versions (see /charts/values).
apps=( plex radarr sonarr lidarr bazarr qbittorrent jellyseerr )
for chart in "${apps[@]}"; do
truenas scale chart ingress install "$chart" --values "charts/$chart.yaml"
sleep 10
done- Local DNS —
media.localvia Pi-hole or Unbound - Reverse Proxy — Nginx Proxy Manager in an LXC (optional). SSL certs via Let’s Encrypt Wildcard.
- Secure tunnel — Tailscale for zero-trust access when away from home.
| Port | Service | Exposed? |
|---|---|---|
| 32400 | Plex | ✅ (WAN) |
| 7878/8989/8686/6767 | *arr apps | ❌ LAN only |
| 8080 | qBittorrent | ❌ LAN only |
| 5055 | Jellyseerr | ✅ via subdomain requests.media.example.com |
- ZFS Snapshots — hourly (24h), daily (7d), weekly (4w), monthly (6m).
- App Configs — Restic push to Backblaze B2 nightly.
- Media — not backed up (ripped discs can be re-encoded) but protected by RAID-Z1.
- Updates —
sudo kubectl-apps upgrade --allweekly via cron.
- Add Immich photo management
- Migrate RSS indexers to Prowlarr
- Deploy Glance dashboard as startpage
PRs welcome — open an issue or fork away!






