jellyfin-media/README.md

11 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 and provides a Spotify-like self-hosted music experience.

The best mobile experience for Navidrome. Features:

  • Spotify-like UI with gapless playback
  • Offline downloads with smart caching
  • Android Auto, Chromecast, Wear OS support
  • Synced lyrics display
  • Multiple server support

Setup:

  1. Install Symfonium from Google Play (~$5 one-time)
  2. Add Server → Subsonic/Navidrome
  3. Server URL: https://music.jeffemmett.com
  4. Enter your Navidrome username/password

Other Clients

Platform App Cost Notes
Android Symfonium ~$5 Best experience, recommended
Android Ultrasonic Free Solid open-source alternative
iOS Amperfy Free Clean UI, CarPlay support
iOS play:Sub ~$5 Polished experience
Desktop Sonixd Free Electron, cross-platform
Desktop Sublime Music Free GTK-based, Linux-native
Web Built-in Free https://music.jeffemmett.com

Music Features

Sharing

Share tracks/albums with anyone (no account needed):

  1. In Navidrome web UI, click any track/album
  2. Click ⋮ menu → Share
  3. Set expiration (or never)
  4. Copy the public link

Lyrics

Lyrics are automatically fetched from LRCLIB and displayed in Symfonium during playback.

Spotify Playlist Import

Lidarr syncs with your Spotify playlists:

  1. Go to https://lidarr.jeffemmett.com
  2. Settings → Import Lists → Add → Spotify Playlists
  3. Authenticate with Spotify
  4. Select playlists to monitor
  5. Lidarr downloads albums from artists in your playlists

Scrobbling (Optional)

Track your listening history with Last.fm or ListenBrainz:

  1. In Navidrome: Settings → Personal → Link account
  2. All plays from web UI and Symfonium will scrobble

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