9.1 KiB
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
- Users request media via Jellyseerr (
requests.jeffemmett.com) - Jellyseerr forwards requests to Sonarr/Radarr/Lidarr
- Prowlarr searches configured indexers for the content
- qBittorrent downloads the files (optionally through VPN)
- *arr apps organize files into proper folders
- 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)
- Go to
https://prowlarr.jeffemmett.com - Add indexers (torrent sites you have access to)
- Go to Settings → Apps → Add Radarr, Sonarr, Lidarr
Step 2: Configure Download Client
- Go to
https://downloads.jeffemmett.com - Default login:
admin/adminadmin(change immediately!) - Settings → Downloads → Default Save Path:
/downloads
Step 3: Configure Radarr (Movies)
- Go to
https://radarr.jeffemmett.com - Settings → Media Management → Root Folder:
/movies - Settings → Download Clients → Add qBittorrent:
- Host:
qbittorrent - Port:
8080
- Host:
Step 4: Configure Sonarr (TV Shows)
- Go to
https://sonarr.jeffemmett.com - Settings → Media Management → Root Folder:
/tv - Settings → Download Clients → Add qBittorrent (same as above)
Step 5: Configure Lidarr (Music)
- Go to
https://lidarr.jeffemmett.com - Settings → Media Management → Root Folder:
/music - Settings → Download Clients → Add qBittorrent (same as above)
Step 6: Configure Jellyseerr (Requests)
- Go to
https://requests.jeffemmett.com - Sign in with Jellyfin (use your Jellyfin server URL:
http://jellyfin:8096) - Add Radarr/Sonarr servers:
- Hostname:
radarrorsonarr(internal Docker hostname) - Port:
7878(Radarr) or8989(Sonarr) - API Key: Get from Radarr/Sonarr Settings → General
- Hostname:
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:
- Cloudflare Access (Recommended): Add authentication via Zero Trust dashboard
- SSH Tunnel: Access admin UIs only via
ssh -L 8989:localhost:8989 netcup - Basic Auth: Add Traefik middleware for HTTP basic auth
To add Cloudflare Access protection:
- Go to Cloudflare Zero Trust → Access → Applications
- Create application for each admin subdomain
- 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
- Check Prowlarr has working indexers
- Verify qBittorrent is accessible:
docker logs qbittorrent - Check Radarr/Sonarr logs for errors
Media not appearing in Jellyfin
- Verify files are in correct folder (
/media/movies,/media/shows) - Trigger library scan in Jellyfin → Dashboard → Libraries
- 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