Create Personal Media Server
I stopped paying $15/month for streaming services the moment I realized I could host my entire media collection—movies, TV shows, music, photos—on hardware I already owned. A personal media server gives you complete control: no forced updates, no content licensing nonsense, no algorithmic recommendations you didn't ask for. You own the data, you own the experience. This guide walks you through building one with Jellyfin, Docker, and either local storage or a cheap VPS for remote access.
Why Self-Host Media Instead of Streaming?
The streaming economics are broken. Every service you subscribe to costs money, but none of them guarantee the content stays available. I had a film disappear from a platform mid-watchthrough because of licensing disputes. That won't happen on your own server.
Jellyfin is the open-source answer here. It's Plex's free cousin, with zero ads, no cloud account requirements, and full control over your library. Alternatively, you can run Plex if you prefer its polish and sharing features. Both work great in Docker, which is how I prefer to deploy anything on my homelab these days.
You'll also save money on storage. A 4TB drive costs $60–80. That's cheaper than two months of premium streaming services, and it's *yours* forever.
Hardware Requirements: Realistic Numbers
You don't need much. Here's what I recommend:
- CPU: An Intel i3 or AMD Ryzen 3 is fine for 2–3 concurrent streams. If you want to transcode video (convert on-the-fly for slower connections), jump to an i5 or Ryzen 5.
- RAM: 4GB minimum, 8GB if you're indexing a large library. My server runs on 6GB and handles everything.
- Storage: Depends entirely on your library. 1TB holds ~250 movies in 1080p. 4TB is my sweet spot—$70 and includes room to grow.
- Network: Gigabit Ethernet is ideal. Wi-Fi works but adds latency and bandwidth headaches.
I'm running mine on a refurbished Lenovo ThinkCentre micro PC with an i5, 8GB RAM, and an external 4TB drive. Total cost: $150. It's been rock-solid for 18 months.
Setting Up Jellyfin with Docker
Docker is the easiest way to deploy Jellyfin. No dependency hell, no version conflicts. I'll walk you through a Docker Compose setup that includes Jellyfin, automatic media organization with Radarr (for movies) and Sonarr (for TV), and Prowlarr to manage your indexers.
First, create a directory structure:
mkdir -p ~/media-server/{jellyfin,downloads,movies,tv,music}
cd ~/media-server
Next, create a Docker Compose file that pulls everything together:
version: '3.8'
services:
jellyfin:
image: jellyfin/jellyfin:latest
container_name: jellyfin
hostname: jellyfin
user: "1000:1000"
ports:
- "8096:8096"
volumes:
- ./jellyfin/config:/config
- ./jellyfin/cache:/cache
- ./movies:/media/movies:ro
- ./tv:/media/tv:ro
- ./music:/media/music:ro
restart: unless-stopped
environment:
- JELLYFIN_DATA_DIR=/config
- JELLYFIN_CACHE_DIR=/cache
radarr:
image: linuxserver/radarr:latest
container_name: radarr
hostname: radarr
ports:
- "7878:7878"
volumes:
- ./radarr/config:/config
- ./downloads:/downloads
- ./movies:/movies
restart: unless-stopped
environment:
- PUID=1000
- PGID=1000
- TZ=UTC
sonarr:
image: linuxserver/sonarr:latest
container_name: sonarr
hostname: sonarr
ports:
- "8989:8989"
volumes:
- ./sonarr/config:/config
- ./downloads:/downloads
- ./tv:/tv
restart: unless-stopped
environment:
- PUID=1000
- PGID=1000
- TZ=UTC
prowlarr:
image: linuxserver/prowlarr:latest
container_name: prowlarr
hostname: prowlarr
ports:
- "9696:9696"
volumes:
- ./prowlarr/config:/config
restart: unless-stopped
environment:
- PUID=1000
- PGID=1000
- TZ=UTC
Save that as `docker-compose.yml` in your `~/media-server` directory. Then spin everything up:
docker-compose up -d
Jellyfin will be available at `http://localhost:8096`. Go there, create an admin account, and point it to your media folders. Radarr (7878), Sonarr (8989), and Prowlarr (9696) need individual setup—that's out of scope here, but the web UIs walk you through it.
Storage Strategy: Local vs. External
I prefer external USB 3.0 drives over internal SATA because they're portable and easier to swap if one fails. A 4TB WD Red Pro is $80 and rated for NAS duty. Two of them in RAID 1 (mirrored) costs $160 but gives you real redundancy.
For *movie* content specifically, I don't need RAID because files are easily re-obtained. For *personal video archives*—old family footage, recordings of my kids—I run two drives. One as the live library, one as a nightly backup.
To mount an external drive on Linux, first identify it:
lsblk
Find your drive (e.g., `/dev/sdb1`), then create a mount point and add it to `/etc/fstab`:
sudo mkdir -p /mnt/media
sudo mount /dev/sdb1 /mnt/media
Then edit `/etc/fstab` to make it permanent. Get the UUID first:
sudo blkid /dev/sdb1
Add a line like this to `/etc/fstab`:
UUID=your-uuid-here /mnt/media ext4 defaults,nofail 0 2
Reboot to confirm it mounts automatically.
Remote Access with Jellyfin and Tailscale
The tricky part: accessing your media server from outside your home. Jellyfin supports UPnP and port forwarding, but I hate exposing services directly to the internet. Instead, I use Tailscale—a mesh VPN that's free, fast, and requires zero port forwarding.
Install Tailscale on your server:
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up
It'll give you a login URL. Authenticate, then check your Tailscale IP:
tailscale ip -4
On your phone or laptop, install Tailscale, authenticate with the same account, and you can reach Jellyfin at `http://your-tailscale-ip:8096`. No port forwarding. No exposed services. Just a private tunnel to your media server. This is how I've done it for two years—bulletproof.
Adding Your Media Library
The easiest path: download movies and TV shows you own legally. Sonarr and Radarr automate this if you connect them to indexers via Prowlarr, but that's a rabbit hole. For this guide, assume you're adding files you already have or own licenses to.
Copy them into your media folders:
cp /path/to/your/movies/* ~/media-server/movies/
cp /path/to/your/shows/* ~/media-server/tv/
Jellyfin will auto-scan and index these within a few minutes. Naming matters—use standard formats like `Movie Title (Year).mkv` for movies and `Show Name/Season 01/Episode 01 - Title.mkv` for TV.
Transcoding and Performance
By default, Jellyfin streams your files as-is. If your internet is slow or you're on mobile, that's painful. Transcoding converts the file in real-time to a lower bitrate.
In Jellyfin's Settings → Playback, enable "Allow Transcoding" and set a default bitrate for remote access (I use 3 Mbps for mobile, 8 Mbps for home). On an i5 or better, you can handle 2–3 simultaneous transcodes comfortably.
Transcoding eats CPU hard. If you plan heavy use, consider disabling it or getting better hardware. My i5 maxes out at about 40% utilization during a single transcode—plenty of headroom.
Backing Up Your Configuration
Jellyfin stores its database and settings in the `config` folder. Back it up weekly:
tar -czf ~/jellyfin-backup-$(date +%Y%m%d).tar.gz ~/media-server/jellyfin/config/
Push it to a cloud service (Backblaze, Wasabi, or Nextcloud). The entire config directory is maybe 100MB—cheap to backup and irreplaceable if something goes wrong.
Next Steps
Once your basic server is running, consider adding:
- Automatic backups of your Jellyfin config with Duplicati or Restic
- Monitoring with Uptime Kuma to catch crashes immediately
- Reverse proxy (Caddy or Nginx Proxy Manager) if you want HTTPS and cleaner URLs
- Separate download folder and automated media organization with Hardlinks to save disk space
A personal media server puts you back in control of what you watch, when you watch it, and who sees it. It's the antidote to the streaming-service treadmill.