Personal Media Server Setup

Install Personal Media Server

I got tired of juggling Netflix, Disney+, and three other streaming subscriptions while still not finding what I wanted to watch. So I built a personal media server using Jellyfin and Docker, and honestly, it's been one of the most satisfying homelab projects I've completed. In this tutorial, I'll walk you through everything: hardware considerations, Docker Compose setup, library organization, and how to access your server remotely without exposing yourself to security nightmares.

Why Build Your Own Media Server?

Look, I'm not here to preach about "sticking it to big tech." The honest truth is this: a personal media server gives you control over your media collection, zero licensing drama, and the ability to stream anything from anywhere—your living room, your parents' house, or your office. You own your setup. No algorithm deciding what you should watch. No ads. No surprise subscription hikes.

The hardware bar is incredibly low in 2026. I'm running my media server on a refurbished Intel NUC from 2018 that cost me $120. It handles 4K transcoding for remote users and serves 8 concurrent streams without breaking a sweat. If you've got an old laptop, a Raspberry Pi 4, or a spare computer in your closet, you can start today.

Hardware and Network Requirements

Before diving into software, you need to think about your media library size and concurrent users. Here's my honest breakdown:

Minimum setup: Raspberry Pi 4 (8GB RAM), 2TB external drive, 1 Gbps home network. This works fine for a single user or couple streaming locally without transcoding.

Comfortable setup (what I run): Intel NUC or equivalent x86 box with 8GB+ RAM, 8TB+ storage (mix of SSD and HDD), 1 Gbps network. Handles 2-3 concurrent streams with transcoding.

Heavy-duty setup: Actual server hardware (used Lenovo ThinkCentre or Dell Optiplex), 16GB+ RAM, 20TB+ storage, 10 Gbps if possible. For families or shared homelabs with 5+ concurrent streams.

For storage, I prefer a mix: 2-4TB SSD for the OS and Jellyfin database, then 4-8TB HDD for actual media. Storage doesn't need to be fast—it needs to be reliable and cheap. Don't skimp on power supplies or cooling.

Tip: If you're considering a VPS instead of local hardware, check RackNerd's KVM VPS options. Their plans start at great prices and include enough bandwidth for media streaming. Just note: storage-heavy setups are better suited to home hardware due to bandwidth costs on cloud VPS.

Installing Jellyfin with Docker Compose

I prefer Docker Compose for media servers because it keeps everything isolated, makes backups trivial, and lets me update Jellyfin without breaking anything else. Here's my production setup:

mkdir -p ~/media-server/{jellyfin,media}
cd ~/media-server
cat > docker-compose.yml << 'EOF'
version: '3.8'
services:
  jellyfin:
    image: jellyfin/jellyfin:latest
    container_name: jellyfin
    user: 1000:1000
    ports:
      - "8096:8096"
      - "8920:8920"
    environment:
      - JELLYFIN_CACHE_DIR=/var/cache/jellyfin
      - JELLYFIN_DATA_DIR=/var/lib/jellyfin
      - JELLYFIN_LOG_DIR=/var/log/jellyfin
      - JELLYFIN_CONFIG_DIR=/etc/jellyfin
    volumes:
      - ./jellyfin/config:/etc/jellyfin
      - ./jellyfin/cache:/var/cache/jellyfin
      - ./jellyfin/log:/var/log/jellyfin
      - ./media/movies:/media/movies:ro
      - ./media/tv:/media/tv:ro
      - ./media/music:/media/music:ro
    restart: unless-stopped
    networks:
      - media-net
    devices:
      - /dev/dri:/dev/dri

networks:
  media-net:
    driver: bridge
EOF

A few things I've learned the hard way:

User permissions matter. That `user: 1000:1000` line is crucial. Make sure your media files have matching ownership: `chown -R 1000:1000 ~/media-server/media`. Otherwise you'll get permission errors when Jellyfin tries to read your files.

GPU acceleration saves CPU. The `/dev/dri` device line passes your GPU to Docker. On Intel, this handles H.264 and H.265 transcoding efficiently. On NVIDIA, you'll need a different image (`jellyfin/jellyfin:latest-nvidia`), but it's worth it if you have lots of concurrent streams.

Read-only mounts. Notice the `:ro` flags on media volumes. This prevents Jellyfin from accidentally modifying your media files—a small safeguard that's saved me from mistakes.

Start the stack:

docker-compose up -d
docker-compose logs -f jellyfin

Wait 30 seconds for startup. You'll see it bind to port 8096. Navigate to `http://localhost:8096` and you'll hit the initial setup wizard.

Initial Configuration and Library Setup

The Jellyfin wizard is straightforward. Set your username, password, and preferred language. Skip the remote access setup for now—we'll come back to that securely.

The crucial part is adding your media libraries. In the web UI, go to Admin > Libraries > Add Media Library. Create separate libraries for:

Movies: Point to `/media/movies`. Use the default naming scheme (this matters for metadata matching).

TV Shows: Point to `/media/tv`. Jellyfin expects shows organized as `Show Name/Season 01/Episode.mkv`.

Music: Point to `/media/music`. Artist/Album/Track structure works best.

File naming is critical. For movies, use `Movie Name (Year).mkv`. For TV, use `Show Name S01E01 - Episode Title.mkv`. Jellyfin's metadata scraper will find artwork, descriptions, and ratings automatically if you follow these conventions.

Watch out: The metadata refresh can hammer your CPU. On my system, scanning a 2TB library with 500+ items takes 20-30 minutes. Don't schedule library scans during peak viewing hours. I run mine at 2 AM via a cron job.

Remote Access with Reverse Proxy

Here's where most people mess up security. They open Jellyfin directly to the internet on port 8096, which is a vulnerability waiting to happen. Instead, I use Caddy as a reverse proxy with automatic HTTPS and Tailscale for encrypted remote access.

If you're using Tailscale (which I strongly recommend for homelabs), your Caddyfile looks like this:

media.{your-tailscale-domain} {
    reverse_proxy http://jellyfin:8096 {
        header_upstream Host {host}
        header_upstream X-Real-IP {remote_host}
        header_upstream X-Forwarded-For {remote_host}
        header_upstream X-Forwarded-Proto https
    }
}

Install Tailscale on your homelab machine and all your clients. Then you access Jellyfin via your Tailscale network—encrypted, no port forwarding, no firewall rules. It's elegant and secure.

If you absolutely need public internet access (not on Tailscale), use a domain you own, point it to Caddy with Let's Encrypt, and keep Jellyfin updated religiously. Even better: use Cloudflare Tunnel to avoid opening ports at all. But honestly, Tailscale is the move for homelabs.

Performance Tuning and Transcoding

By default, Jellyfin transcodes everything, which destroys CPU performance. I've optimized mine by being selective about when transcoding happens.

In Admin > Transcoding, I set maximum bitrate limits per quality tier. For remote users on slower connections, I transcode to 720p at 3 Mbps. For local network users, I disable transcoding entirely and just use direct play.

Create user profiles with different transcoding rules. My parents' account automatically limits to 1080p@5Mbps because their rural connection can't handle more. My account on the home network? Direct play everything, no transcoding overhead.

Also, I set temporary transcode storage to my SSD (`/var/cache/jellyfin`) instead of the HDD. This reduces latency when multiple users are transcoding simultaneously.

Backup Strategy

Your Jellyfin config lives in `./jellyfin/config`. Backup this directory weekly. If something breaks, you can restore your entire server—all libraries, users, playback state—in minutes. I use Restic with a daily automated backup to cold storage.

Your actual media files? Those are important but recoverable. I keep two copies: one on my local server, one on a networked backup drive using rsync. If the server fails, I've still got my media and can restore within an hour.

Next Steps and Expansion

Once you've got Jellyfin running smoothly, the natural next step is adding companion services. Many people add:

Sonarr and Radarr for automated episode and movie management

Prowlarr for indexer management

SABnzbd or qBittorrent for downloading

These create a complete home media ecosystem, but that's a separate (complex) tutorial. For now, focus on getting Jellyfin stable and your library organized. That's 90% of the value.

If you're running this on a VPS instead of local hardware, scaling up becomes easier than you think. A RackNerd KVM VPS with 8GB RAM and 500GB storage can absolutely run a Jellyfin server for personal use—just budget for bandwidth costs if your friends are streaming from you constantly.

The key is starting somewhere. Your old laptop can become a media server. Your spare Pi 4 can handle this. Even a cheap VPS can work. Build it, organize your library, and enjoy streaming without the subscription treadmill.

```