jellyfin-media/README.md

326 lines
11 KiB
Markdown

# 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
```bash
git clone https://gitea.jeffemmett.com/jeffemmett/jellyfin-media.git
cd jellyfin-media
cp .env.example .env
```
### 2. Deploy to Netcup
```bash
./scripts/deploy-to-netcup.sh
```
### 3. Add Cloudflare Tunnel Hostnames
Add these hostnames to your Cloudflare tunnel config (`/root/cloudflared/config.yml`):
```yaml
# Media Request System
- hostname: requests.jeffemmett.com
service: http://localhost:80
- hostname: invite.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
#### Step 7: Configure Wizarr (User Invitations)
1. Go to `https://invite.jeffemmett.com`
2. Create your admin account on first visit
3. Connect to Jellyfin:
- Server URL: `http://jellyfin:8096`
- API Key: Get from Jellyfin → Dashboard → API Keys → Create
4. Create invite links:
- Set expiration (1 day, 1 week, never, etc.)
- Set usage limit (1 use, unlimited, etc.)
- Share the generated link with friends
5. When friends use the link, they'll be guided through:
- Creating their Jellyfin account
- Downloading mobile apps
- Connecting to your server
## 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 |
| Wizarr | https://invite.jeffemmett.com | User invitation system |
| 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:
```bash
# 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:
```yaml
# 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
```bash
# 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.
#### Recommended: Symfonium (Android - ~$5)
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
```bash
# Check gluetun logs
docker logs gluetun
# Verify VPN is working
docker exec gluetun curl ifconfig.me
```
## License
MIT