jellyfin-media/README.md

9.1 KiB

Media Server on Netcup RS 8000

A self-hosted media server stack with automated request management, running on Netcup RS 8000 with Jellyfin for streaming.

Architecture

                    Users
                      │
                      ▼
┌─────────────────────────────────────────────────────────────┐
│              Cloudflare Tunnel → Traefik                    │
└─────────────────────────────────────────────────────────────┘
                      │
        ┌─────────────┼─────────────┐
        ▼             ▼             ▼
┌───────────┐  ┌───────────┐  ┌───────────┐
│ Jellyfin  │  │Jellyseerr │  │ Navidrome │
│ (Stream)  │  │(Requests) │  │  (Music)  │
└─────┬─────┘  └─────┬─────┘  └───────────┘
      │              │
      │              ▼
      │   ┌─────────────────────┐
      │   │    Request Flow     │
      │   │  ┌───────────────┐  │
      │   │  │    Sonarr     │  │  ← TV Shows
      │   │  │    Radarr     │  │  ← Movies
      │   │  │    Lidarr     │  │  ← Music
      │   │  └───────┬───────┘  │
      │   │          │          │
      │   │  ┌───────▼───────┐  │
      │   │  │   Prowlarr    │  │  ← Indexer Management
      │   │  └───────┬───────┘  │
      │   │          │          │
      │   │  ┌───────▼───────┐  │
      │   │  │  qBittorrent  │  │  ← Downloads (optional VPN)
      │   │  └───────┬───────┘  │
      │   └──────────┼──────────┘
      │              │
      ▼              ▼
┌─────────────────────────────────────────────────────────────┐
│                    Local NVMe Storage (3TB)                 │
│  /media/movies    /media/shows    /media/music              │
└─────────────────────────────────────────────────────────────┘

How It Works

  1. Users request media via Jellyseerr (requests.jeffemmett.com)
  2. Jellyseerr forwards requests to Sonarr/Radarr/Lidarr
  3. Prowlarr searches configured indexers for the content
  4. qBittorrent downloads the files (optionally through VPN)
  5. *arr apps organize files into proper folders
  6. Jellyfin detects new media and makes it available for streaming

Server Specs

  • Netcup RS 8000 G12 Pro: €45/month
  • 20 CPU cores for transcoding
  • 64GB RAM for caching
  • 3TB NVMe storage for media
  • 1Gbps bandwidth included

Quick Start

1. Clone and Configure

git clone https://gitea.jeffemmett.com/jeffemmett/jellyfin-media.git
cd jellyfin-media
cp .env.example .env

2. Deploy to Netcup

./scripts/deploy-to-netcup.sh

3. Add Cloudflare Tunnel Hostnames

Add these hostnames to your Cloudflare tunnel config (/root/cloudflared/config.yml):

# Media Request System
- hostname: requests.jeffemmett.com
  service: http://localhost:80
- hostname: sonarr.jeffemmett.com
  service: http://localhost:80
- hostname: radarr.jeffemmett.com
  service: http://localhost:80
- hostname: prowlarr.jeffemmett.com
  service: http://localhost:80
- hostname: lidarr.jeffemmett.com
  service: http://localhost:80
- hostname: downloads.jeffemmett.com
  service: http://localhost:80

Then restart cloudflared: docker restart cloudflared

4. Configure Services (First Time Setup)

Step 1: Configure Prowlarr (Indexers)

  1. Go to https://prowlarr.jeffemmett.com
  2. Add indexers (torrent sites you have access to)
  3. Go to Settings → Apps → Add Radarr, Sonarr, Lidarr

Step 2: Configure Download Client

  1. Go to https://downloads.jeffemmett.com
  2. Default login: admin / adminadmin (change immediately!)
  3. Settings → Downloads → Default Save Path: /downloads

Step 3: Configure Radarr (Movies)

  1. Go to https://radarr.jeffemmett.com
  2. Settings → Media Management → Root Folder: /movies
  3. Settings → Download Clients → Add qBittorrent:
    • Host: qbittorrent
    • Port: 8080

Step 4: Configure Sonarr (TV Shows)

  1. Go to https://sonarr.jeffemmett.com
  2. Settings → Media Management → Root Folder: /tv
  3. Settings → Download Clients → Add qBittorrent (same as above)

Step 5: Configure Lidarr (Music)

  1. Go to https://lidarr.jeffemmett.com
  2. Settings → Media Management → Root Folder: /music
  3. Settings → Download Clients → Add qBittorrent (same as above)

Step 6: Configure Jellyseerr (Requests)

  1. Go to https://requests.jeffemmett.com
  2. Sign in with Jellyfin (use your Jellyfin server URL: http://jellyfin:8096)
  3. Add Radarr/Sonarr servers:
    • Hostname: radarr or sonarr (internal Docker hostname)
    • Port: 7878 (Radarr) or 8989 (Sonarr)
    • API Key: Get from Radarr/Sonarr Settings → General

Services

Service URL Description
Jellyfin https://movies.jeffemmett.com Video streaming (movies & TV)
Navidrome https://music.jeffemmett.com Music streaming server
Jellyseerr https://requests.jeffemmett.com Media request interface
Sonarr https://sonarr.jeffemmett.com TV show management
Radarr https://radarr.jeffemmett.com Movie management
Lidarr https://lidarr.jeffemmett.com Music management
Prowlarr https://prowlarr.jeffemmett.com Indexer management
qBittorrent https://downloads.jeffemmett.com Download client

Security Recommendations

Important: The *arr admin interfaces should be protected. Options:

  1. Cloudflare Access (Recommended): Add authentication via Zero Trust dashboard
  2. SSH Tunnel: Access admin UIs only via ssh -L 8989:localhost:8989 netcup
  3. Basic Auth: Add Traefik middleware for HTTP basic auth

To add Cloudflare Access protection:

  1. Go to Cloudflare Zero Trust → Access → Applications
  2. Create application for each admin subdomain
  3. Add authentication policy (email, one-time PIN, etc.)

VPN Support

For download privacy, enable the VPN profile:

# Add to .env:
VPN_PROVIDER=mullvad
VPN_WIREGUARD_PRIVATE_KEY=your_private_key
VPN_WIREGUARD_ADDRESS=10.x.x.x/32

# Start with VPN:
docker compose --profile vpn up -d

Then modify qBittorrent to route through gluetun:

# In docker-compose-server.yml, uncomment:
network_mode: "service:gluetun"
# And comment out the networks/labels sections

Folder Structure

/opt/media-server/
├── media/
│   ├── movies/        # Movie files
│   ├── shows/         # TV show files
│   └── music/         # Music files
├── config/
│   ├── jellyfin/      # Jellyfin config
│   ├── jellyseerr/    # Jellyseerr config
│   ├── sonarr/        # Sonarr config
│   ├── radarr/        # Radarr config
│   ├── lidarr/        # Lidarr config
│   ├── prowlarr/      # Prowlarr config
│   └── qbittorrent/   # qBittorrent config
├── downloads/
│   └── complete/      # Completed downloads
└── cache/
    └── jellyfin/      # Transcoding cache

Upload Script Usage

# From local machine
./scripts/upload-to-netcup.sh <local-path> <media-type>

# Examples:
./scripts/upload-to-netcup.sh /home/jeffe/Shows shows
./scripts/upload-to-netcup.sh /home/jeffe/Movies movies
./scripts/upload-to-netcup.sh /home/jeffe/Music music

The script uses rsync for efficient incremental uploads.

Mobile Apps

Jellyfin (Video)

  • Android: Jellyfin for Android
  • iOS: Swiftfin, Jellyfin Mobile

Navidrome (Music)

Navidrome is Subsonic-compatible. Use any Subsonic client:

  • Android: Ultrasonic, Symfonium, DSub
  • iOS: play:Sub, Amperfy, SubStreamer
  • Desktop: Sonixd, Sublime Music

Troubleshooting

Downloads not starting

  1. Check Prowlarr has working indexers
  2. Verify qBittorrent is accessible: docker logs qbittorrent
  3. Check Radarr/Sonarr logs for errors

Media not appearing in Jellyfin

  1. Verify files are in correct folder (/media/movies, /media/shows)
  2. Trigger library scan in Jellyfin → Dashboard → Libraries
  3. Check file permissions: should be owned by PUID:PGID (1000:1000)

VPN connection issues

# Check gluetun logs
docker logs gluetun

# Verify VPN is working
docker exec gluetun curl ifconfig.me

License

MIT