feat(stack): add unified media stack with Sonarr, Radarr, Prowlarr, SABnzbd

Consolidates Jellyfin into a new media stack with full *arr automation:
- Sonarr (8989) - TV show management
- Radarr (7878) - Movie management
- Prowlarr (9696) - Indexer management
- SABnzbd (8880) - Usenet download client
- Jellyfin (8096) - Media streaming with GPU transcoding

Database: All *arr apps use PostgreSQL (postgres-shared) with media_user.
Databases created: sonarr, radarr, prowlarr

Also adds pg-connections.sh utility script for monitoring PostgreSQL connections.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-06 12:39:27 +01:00
co-authored by Claude Opus 4.5
parent dc1fb868fd
commit 6052f81ec1
4 changed files with 396 additions and 85 deletions
+128 -10
View File
@@ -1,7 +1,7 @@
# Container Reference - tower-of-joy Infrastructure
> **Last Updated:** 2026-01-04
> **Total Services:** 26 containers across 20 stacks
> **Last Updated:** 2026-01-06
> **Total Services:** 30 containers across 20 stacks
> **System:** Intel i7-6700, RTX 2080 Ti (11GB VRAM), 64GB RAM, Zorin OS 16.3
---
@@ -23,6 +23,10 @@
| **Scheduler** | 8090 | http://192.168.86.149:8090 | LAN | No | 3 | ✅ Running (external) |
| **SearXNG** | 8087 | http://192.168.86.149:8087 | LAN | No | 5 | ✅ Running |
| **Jellyfin** | 8096, 8920, 7359, 1900 | https://media.schweitz.net | Internet | Yes (RTX 2080 Ti) | - | ✅ Running |
| **Sonarr** | 8989 | http://192.168.86.149:8989 | LAN | No | - | ✅ Running |
| **Radarr** | 7878 | http://192.168.86.149:7878 | LAN | No | - | ✅ Running |
| **Prowlarr** | 9696 | http://192.168.86.149:9696 | LAN | No | - | ✅ Running |
| **SABnzbd** | 8880 | http://192.168.86.149:8880 | LAN | No | - | ✅ Running |
| **Nextcloud** | 8082 | https://cloud.schweitz.net | Internet | No | 7 | ⚠️ Stopped |
| **Samba** | 139, 445 | \\\\192.168.86.149 | LAN | No | - | ✅ Running |
| **Gitea** | 3002, 2222 (SSH) | https://git.schweitz.net | Internet | No | - | ✅ Running |
@@ -152,8 +156,8 @@ PostgreSQL Shared is a centralized PostgreSQL 17 database server providing isola
| **Resource Limits** | None |
| **GPU Required** | No |
| **Dependencies** | docker-dataplane network |
| **Databases** | `authentik` (Authentik SSO), `gitea` (Git hosting), `paperless` (Document management), `system_settings` (Central Tatlock settings), `postgres` (default/admin) |
| **Database Users** | `authentik_user`, `gitea_user`, `paperless_user`, `settings` (system_settings RW), `postgres` (superuser) |
| **Databases** | `authentik` (Authentik SSO), `gitea` (Git hosting), `paperless` (Document management), `system_settings` (Central Tatlock settings), `sonarr` (TV management), `radarr` (Movie management), `prowlarr` (Indexer management), `postgres` (default/admin) |
| **Database Users** | `authentik_user`, `gitea_user`, `paperless_user`, `settings` (system_settings RW), `media_user` (sonarr/radarr/prowlarr), `postgres` (superuser) |
| **Health Check** | `pg_isready -U postgres` (30s interval) |
| **Backup Strategy** | `/backups` volume for pg_dump exports |
@@ -409,26 +413,132 @@ Core API provides OpenAI-compatible HTTP functions for Open WebUI, extending LLM
### Jellyfin
Jellyfin is a GPU-accelerated media server that organizes, streams, and transcodes video, music, and photo libraries with hardware encoding via NVIDIA NVENC, enabling smooth 4K playback across multiple simultaneous clients without taxing the CPU. It provides a Netflix-like interface accessible through web browsers, mobile apps, and smart TV clients, with automatic metadata fetching, subtitle support, and user management for family sharing. The service stores configuration and cache on the SSD for responsive browsing while accessing massive media libraries on the 3.7TB HDD, supporting direct play when possible and GPU-accelerated transcoding when format conversion is needed.
Jellyfin is a GPU-accelerated media server that organizes, streams, and transcodes video, music, and photo libraries with hardware encoding via NVIDIA NVENC, enabling smooth 4K playback across multiple simultaneous clients without taxing the CPU. It provides a Netflix-like interface accessible through web browsers, mobile apps, and smart TV clients, with automatic metadata fetching, subtitle support, and user management for family sharing. The service stores configuration and cache on the SSD for responsive browsing while accessing massive media libraries on the 3.7TB HDD, supporting direct play when possible and GPU-accelerated transcoding when format conversion is needed. Part of the unified media stack with Sonarr, Radarr, Prowlarr, and SABnzbd.
| Property | Value |
|----------|-------|
| **Image** | `jellyfin/jellyfin:latest` |
| **Container Name** | `jellyfin` |
| **Stack** | `media` (unified media stack) |
| **Access URL** | http://192.168.86.149:8096, https://media.schweitz.net |
| **External Access** | LAN + Internet (via NPM reverse proxy) |
| **Port Mapping** | 8096:8096 (HTTP), 8920:8920 (HTTPS), 7359:7359/udp (Discovery), 1900:1900/udp (DLNA) |
| **Network Mode** | Bridge |
| **Network Mode** | Bridge (docker-dataplane) |
| **Restart Policy** | `unless-stopped` |
| **Volume Mounts** | `~/docker-data/jellyfin/config:/config`, `~/docker-data/jellyfin/cache:/cache`, `/mnt/media/jellyfin:/media:ro` |
| **Environment** | `NVIDIA_VISIBLE_DEVICES=all`, `NVIDIA_DRIVER_CAPABILITIES=all` |
| **Volume Mounts** | `~/docker-data/jellyfin/config:/config`, `~/docker-data/jellyfin/cache:/cache`, `/mnt/media/jellyfin/movies:/media/movies:ro`, `/mnt/media/jellyfin/series:/media/series:ro` |
| **Environment** | `NVIDIA_VISIBLE_DEVICES=all`, `NVIDIA_DRIVER_CAPABILITIES=all`, `TZ=Europe/Amsterdam` |
| **User** | `1000:1000` (UID:GID) |
| **Resource Limits** | Memory: 4GB, GPU: 11GB VRAM (shared) |
| **GPU Required** | Yes (NVIDIA RTX 2080 Ti) |
| **GPU Configuration** | NVENC hardware encoding, NVDEC hardware decoding |
| **Dependencies** | NVIDIA Container Toolkit, NPM (for external access) |
| **Dependencies** | NVIDIA Container Toolkit, NPM (for external access), Sonarr/Radarr (media automation) |
| **Media Storage** | /mnt/media/jellyfin (HDD) |
| **Transcoding** | Hardware-accelerated (H.264/H.265) |
| **Health Check** | `curl -fSs http://localhost:8096/health` (30s interval) |
---
### Sonarr
Sonarr is an automated TV show management and download tool that monitors for new episodes, searches indexers, and automatically downloads content via Usenet or BitTorrent clients. It integrates with Prowlarr for centralized indexer management and SABnzbd for Usenet downloads, automatically renaming and organizing files into Jellyfin's media library structure. The service provides a web interface for managing series, setting quality profiles, and monitoring download queues with calendar views for upcoming episodes.
| Property | Value |
|----------|-------|
| **Image** | `linuxserver/sonarr:latest` |
| **Container Name** | `sonarr` |
| **Stack** | `media` (unified media stack) |
| **Access URL (LAN)** | http://192.168.86.149:8989 |
| **External Access** | LAN only |
| **Port Mapping** | 8989:8989 (HTTP) |
| **Network Mode** | Bridge (docker-dataplane) |
| **Restart Policy** | `unless-stopped` |
| **Volume Mounts** | `~/docker-data/sonarr:/config` (SSD), `/mnt/media/jellyfin/series:/tv` (HDD), `/mnt/media/downloads:/downloads` (HDD) |
| **Environment** | `PUID=1000`, `PGID=1000`, `TZ=Europe/Amsterdam` |
| **Resource Limits** | None |
| **GPU Required** | No |
| **Database** | PostgreSQL `sonarr` on postgres-shared (user: media_user) |
| **Dependencies** | PostgreSQL Shared, SABnzbd (download client), Prowlarr (indexer management), Jellyfin (media server) |
| **Health Check** | `curl -fSs http://localhost:8989/ping` (30s interval) |
| **Features** | Episode tracking, quality profiles, automatic renaming, calendar view, API integration |
| **Inter-service URL** | `http://sonarr:8989` (from other containers) |
---
### Radarr
Radarr is an automated movie management and download tool that monitors for new releases, searches indexers, and automatically downloads content via Usenet or BitTorrent clients. It integrates with Prowlarr for centralized indexer management and SABnzbd for Usenet downloads, automatically renaming and organizing files into Jellyfin's media library structure. The service provides a web interface for managing movies, setting quality profiles, and monitoring download queues with discovery features for finding new content.
| Property | Value |
|----------|-------|
| **Image** | `linuxserver/radarr:latest` |
| **Container Name** | `radarr` |
| **Stack** | `media` (unified media stack) |
| **Access URL (LAN)** | http://192.168.86.149:7878 |
| **External Access** | LAN only |
| **Port Mapping** | 7878:7878 (HTTP) |
| **Network Mode** | Bridge (docker-dataplane) |
| **Restart Policy** | `unless-stopped` |
| **Volume Mounts** | `~/docker-data/radarr:/config` (SSD), `/mnt/media/jellyfin/movies:/movies` (HDD), `/mnt/media/downloads:/downloads` (HDD) |
| **Environment** | `PUID=1000`, `PGID=1000`, `TZ=Europe/Amsterdam` |
| **Resource Limits** | None |
| **GPU Required** | No |
| **Database** | PostgreSQL `radarr` on postgres-shared (user: media_user) |
| **Dependencies** | PostgreSQL Shared, SABnzbd (download client), Prowlarr (indexer management), Jellyfin (media server) |
| **Health Check** | `curl -fSs http://localhost:7878/ping` (30s interval) |
| **Features** | Movie tracking, quality profiles, automatic renaming, discovery lists, API integration |
| **Inter-service URL** | `http://radarr:7878` (from other containers) |
---
### Prowlarr
Prowlarr is a centralized indexer manager that syncs indexer configurations across all *arr applications (Sonarr, Radarr, Lidarr, Readarr), eliminating the need to configure the same indexers multiple times. It acts as a proxy between the *arr apps and indexers, providing unified search capabilities, indexer health monitoring, and automatic sync of indexer settings. The service simplifies management of Usenet and torrent indexers with support for both public and private trackers.
| Property | Value |
|----------|-------|
| **Image** | `linuxserver/prowlarr:latest` |
| **Container Name** | `prowlarr` |
| **Stack** | `media` (unified media stack) |
| **Access URL (LAN)** | http://192.168.86.149:9696 |
| **External Access** | LAN only |
| **Port Mapping** | 9696:9696 (HTTP) |
| **Network Mode** | Bridge (docker-dataplane) |
| **Restart Policy** | `unless-stopped` |
| **Volume Mounts** | `~/docker-data/prowlarr:/config` (SSD) |
| **Environment** | `PUID=1000`, `PGID=1000`, `TZ=Europe/Amsterdam` |
| **Resource Limits** | None |
| **GPU Required** | No |
| **Database** | PostgreSQL `prowlarr` on postgres-shared (user: media_user) |
| **Dependencies** | PostgreSQL Shared (other *arr apps depend on this) |
| **Health Check** | `curl -fSs http://localhost:9696/ping` (30s interval) |
| **Features** | Centralized indexer management, automatic sync to *arr apps, indexer health monitoring, Usenet + torrent support |
| **Inter-service URL** | `http://prowlarr:9696` (from other containers) |
---
### SABnzbd
SABnzbd is an automated Usenet binary downloader that handles NZB file processing, downloading, verification, repair, and extraction with minimal user interaction. It integrates with Sonarr and Radarr to automatically download requested content, organizing completed downloads into categories for easy import. The service provides a web interface for managing downloads, configuring Usenet servers, and monitoring queue status with support for multiple news servers and SSL connections.
| Property | Value |
|----------|-------|
| **Image** | `linuxserver/sabnzbd:latest` |
| **Container Name** | `sabnzbd` |
| **Stack** | `media` (unified media stack) |
| **Access URL (LAN)** | http://192.168.86.149:8880 |
| **External Access** | LAN only |
| **Port Mapping** | 8880:8080 (HTTP, remapped to avoid Portainer conflict) |
| **Network Mode** | Bridge (docker-dataplane) |
| **Restart Policy** | `unless-stopped` |
| **Volume Mounts** | `~/docker-data/sabnzbd:/config` (SSD), `/mnt/media/downloads:/downloads` (HDD), `/mnt/media/downloads/incomplete:/incomplete-downloads` (HDD) |
| **Environment** | `PUID=1000`, `PGID=1000`, `TZ=Europe/Amsterdam` |
| **Resource Limits** | None |
| **GPU Required** | No |
| **Database** | INI config files (no database) |
| **Dependencies** | None (Sonarr/Radarr depend on this) |
| **Health Check** | `curl -fSs http://localhost:8080/api?mode=version` (30s interval) |
| **Features** | NZB processing, par2 repair, unrar extraction, category sorting, multiple server support, SSL |
| **Inter-service URL** | `http://sabnzbd:8080` (from other containers, internal port) |
---
@@ -608,6 +718,10 @@ Gitea is a lightweight, self-hosted Git service providing repository hosting, is
| **Tatlock** | https://tatlock.schweitz.net | Yes (SSO) | AI orchestration API |
| **Core API** | http://192.168.86.149:8083 | No | API functions & infrastructure mgmt |
| **Jellyfin** | https://media.schweitz.net | Yes | Media streaming |
| **Sonarr** | http://192.168.86.149:8989 | No | TV show automation |
| **Radarr** | http://192.168.86.149:7878 | No | Movie automation |
| **Prowlarr** | http://192.168.86.149:9696 | No | Indexer management |
| **SABnzbd** | http://192.168.86.149:8880 | No | Usenet downloads |
| **Nextcloud** | https://cloud.schweitz.net | Yes | Cloud storage & sync |
| **Gitea** | https://git.schweitz.net | Yes | Git repository hosting |
| **Samba** | \\\\192.168.86.149 | No | Network file shares |
@@ -642,6 +756,10 @@ Gitea is a lightweight, self-hosted Git service providing repository hosting, is
| **Open WebUI** | `~/docker-data/open-webui/` | N/A | ~100MB |
| **Core API** | `~/docker-data/core-api/` | N/A | Logs: ~10MB |
| **Jellyfin** | `~/docker-data/jellyfin/` | `/mnt/media/jellyfin/` | Config: ~500MB, Media: ~2TB |
| **Sonarr** | `~/docker-data/sonarr/` | `/mnt/media/jellyfin/series/`, `/mnt/media/downloads/` | Config: ~50MB |
| **Radarr** | `~/docker-data/radarr/` | `/mnt/media/jellyfin/movies/`, `/mnt/media/downloads/` | Config: ~50MB |
| **Prowlarr** | `~/docker-data/prowlarr/` | N/A | Config: ~20MB |
| **SABnzbd** | `~/docker-data/sabnzbd/` | `/mnt/media/downloads/` | Config: ~50MB |
| **Nextcloud** | `~/docker-data/nextcloud/` | `/mnt/media/nextcloud/data/` | Config: ~200MB, DB: ~100MB, User data: variable |
| **Gitea** | `~/docker-data/gitea/` | N/A | Data: ~100MB, DB: ~50MB, Repos: variable |
| **Samba** | `~/docker-data/samba/` | Mounts: `/mnt/media/` (shares) | Config: ~5MB |
@@ -659,7 +777,7 @@ Gitea is a lightweight, self-hosted Git service providing repository hosting, is
| Network Name | Containers | Purpose |
|--------------|------------|---------|
| **docker-dataplane** | Ollama, Open WebUI, Core API, Qdrant, PostgreSQL Shared, Redis Shared, Headscale, Nextcloud, Gitea, Samba, Watchtower, Tatlock UI, Home Assistant | Unified service mesh for all containerized applications |
| **docker-dataplane** | Ollama, Open WebUI, Core API, Qdrant, PostgreSQL Shared, Redis Shared, Headscale, Nextcloud, Gitea, Samba, Watchtower, Tatlock UI, Home Assistant, Jellyfin, Sonarr, Radarr, Prowlarr, SABnzbd | Unified service mesh for all containerized applications |
| **host** | Portainer, NPM | Direct host port access for infrastructure management |
**Benefits of Consolidation**:
+8
View File
@@ -0,0 +1,8 @@
#!/bin/bash
# Check open connections on postgres-shared
echo "=== PostgreSQL Connection Summary ==="
docker exec postgres-shared psql -U postgres -c "SELECT count(*) AS total_connections FROM pg_stat_activity;"
echo "=== Connections by Database/User/State ==="
docker exec postgres-shared psql -U postgres -c "SELECT datname AS database, usename AS user, state, count(*) FROM pg_stat_activity GROUP BY datname, usename, state ORDER BY count DESC;"
-75
View File
@@ -1,75 +0,0 @@
version: '3.8'
# Jellyfin - Media Server with GPU Transcoding
# Backlog: Application Deployment
# Ports: 8096 (HTTP), 8920 (HTTPS), 7359 (Auto-discovery), 1900 (DLNA)
# GPU: YES - Requires NVIDIA Container Toolkit
# Storage: SSD (config/cache), HDD (media files)
services:
jellyfin:
image: jellyfin/jellyfin:latest
container_name: jellyfin
user: 1000:1000 # Replace with your UID:GID (run: id)
network_mode: host
restart: unless-stopped
volumes:
# Config and cache on SSD (performance-critical)
- /home/jpmschweitzer/docker-data/jellyfin/config:/config
- /home/jpmschweitzer/docker-data/jellyfin/cache:/cache
# Media files on HDD (read-only for safety)
- /mnt/media/jellyfin/movies:/media/movies:ro
- /mnt/media/jellyfin/series:/media/series:ro
environment:
- NVIDIA_VISIBLE_DEVICES=all
- NVIDIA_DRIVER_CAPABILITIES=all
- TZ=Europe/Amsterdam
healthcheck:
test: ["CMD-SHELL", "curl -fSs http://localhost:8096/health || exit 1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu, video, compute, utility]
# GPU Transcoding Setup:
# 1. Deploy stack
# 2. Verify GPU access: docker exec jellyfin nvidia-smi
# 3. Access http://localhost:8096
# 4. Complete initial setup wizard
# 5. Navigate to: Dashboard → Playback → Transcoding
# 6. Configure hardware acceleration:
# - Hardware acceleration: NVIDIA NVENC
# - Enable hardware decoding: Check all applicable formats
# - Enable hardware encoding: Enabled
# - Encoding preset: Auto or High Quality
# 7. Test with video playback
# 8. Monitor GPU: watch -n 1 nvidia-smi
#
# Expected Results:
# - Dashboard shows "(hw)" during transcoding
# - nvidia-smi shows Video Engine usage
# - CPU usage remains low during transcoding
# - RTX 2080 Ti can handle multiple 4K transcodes simultaneously
#
# Media Organization:
# /mnt/media/jellyfin/
# ├── movies/
# │ ├── Movie Title (Year)/
# │ │ └── Movie Title (Year).mkv
# ├── tv/
# │ ├── TV Show Name/
# │ │ ├── Season 01/
# │ │ │ ├── S01E01.mkv
# │ │ │ └── S01E02.mkv
# └── music/
# ├── Artist/
# │ ├── Album/
# │ │ └── Track.mp3
+260
View File
@@ -0,0 +1,260 @@
version: '3.8'
# Media Stack - Unified Media Management & Streaming
# Services: Jellyfin, Sonarr, Radarr, Prowlarr, SABnzbd
# Ports: 8096 (Jellyfin), 8989 (Sonarr), 7878 (Radarr), 9696 (Prowlarr), 8880 (SABnzbd)
# GPU: YES (Jellyfin only) - Requires NVIDIA Container Toolkit
# Storage: SSD (configs), HDD (media, downloads)
# Database: PostgreSQL (postgres-shared) for Sonarr, Radarr, Prowlarr
services:
# ============================================================
# JELLYFIN - Media Server with GPU Transcoding
# ============================================================
jellyfin:
image: jellyfin/jellyfin:latest
container_name: jellyfin
user: 1000:1000
restart: unless-stopped
ports:
- "8096:8096" # HTTP web interface
- "8920:8920" # HTTPS web interface
- "7359:7359/udp" # Auto-discovery
- "1900:1900/udp" # DLNA
volumes:
# Config and cache on SSD (performance-critical)
- /home/jpmschweitzer/docker-data/jellyfin/config:/config
- /home/jpmschweitzer/docker-data/jellyfin/cache:/cache
# Media files on HDD (read-only for safety)
- /mnt/media/jellyfin/movies:/media/movies:ro
- /mnt/media/jellyfin/series:/media/series:ro
environment:
- NVIDIA_VISIBLE_DEVICES=all
- NVIDIA_DRIVER_CAPABILITIES=all
- TZ=Europe/Amsterdam
healthcheck:
test: ["CMD-SHELL", "curl -fSs http://localhost:8096/health || exit 1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu, video, compute, utility]
networks:
- docker-dataplane
# ============================================================
# SONARR - TV Show Management & Automation
# ============================================================
sonarr:
image: linuxserver/sonarr:latest
container_name: sonarr
restart: unless-stopped
ports:
- "8989:8989"
volumes:
# Config on SSD
- /home/jpmschweitzer/docker-data/sonarr:/config
# Media and downloads on HDD
- /mnt/media/jellyfin/series:/tv
- /mnt/media/downloads:/downloads
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/Amsterdam
# PostgreSQL (postgres-shared)
- SONARR__POSTGRES__HOST=postgres-shared
- SONARR__POSTGRES__PORT=5432
- SONARR__POSTGRES__USER=media_user
- SONARR__POSTGRES__PASSWORD=${MEDIA_DB_PASSWORD}
- SONARR__POSTGRES__MAINDB=sonarr
healthcheck:
test: ["CMD-SHELL", "curl -fSs http://localhost:8989/ping || exit 1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
depends_on:
- sabnzbd
- prowlarr
networks:
- docker-dataplane
# ============================================================
# RADARR - Movie Management & Automation
# ============================================================
radarr:
image: linuxserver/radarr:latest
container_name: radarr
restart: unless-stopped
ports:
- "7878:7878"
volumes:
# Config on SSD
- /home/jpmschweitzer/docker-data/radarr:/config
# Media and downloads on HDD
- /mnt/media/jellyfin/movies:/movies
- /mnt/media/downloads:/downloads
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/Amsterdam
# PostgreSQL (postgres-shared)
- RADARR__POSTGRES__HOST=postgres-shared
- RADARR__POSTGRES__PORT=5432
- RADARR__POSTGRES__USER=media_user
- RADARR__POSTGRES__PASSWORD=${MEDIA_DB_PASSWORD}
- RADARR__POSTGRES__MAINDB=radarr
healthcheck:
test: ["CMD-SHELL", "curl -fSs http://localhost:7878/ping || exit 1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
depends_on:
- sabnzbd
- prowlarr
networks:
- docker-dataplane
# ============================================================
# PROWLARR - Indexer Management
# ============================================================
prowlarr:
image: linuxserver/prowlarr:latest
container_name: prowlarr
restart: unless-stopped
ports:
- "9696:9696"
volumes:
# Config on SSD
- /home/jpmschweitzer/docker-data/prowlarr:/config
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/Amsterdam
# PostgreSQL (postgres-shared)
- PROWLARR__POSTGRES__HOST=postgres-shared
- PROWLARR__POSTGRES__PORT=5432
- PROWLARR__POSTGRES__USER=media_user
- PROWLARR__POSTGRES__PASSWORD=${MEDIA_DB_PASSWORD}
- PROWLARR__POSTGRES__MAINDB=prowlarr
healthcheck:
test: ["CMD-SHELL", "curl -fSs http://localhost:9696/ping || exit 1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
networks:
- docker-dataplane
# ============================================================
# SABNZBD - Usenet Download Client
# ============================================================
sabnzbd:
image: linuxserver/sabnzbd:latest
container_name: sabnzbd
restart: unless-stopped
ports:
- "8880:8080" # Web UI (remapped to avoid Portainer conflict)
volumes:
# Config on SSD
- /home/jpmschweitzer/docker-data/sabnzbd:/config
# Downloads on HDD
- /mnt/media/downloads:/downloads
- /mnt/media/downloads/incomplete:/incomplete-downloads
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/Amsterdam
healthcheck:
test: ["CMD-SHELL", "curl -fSs http://localhost:8080/api?mode=version || exit 1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
networks:
- docker-dataplane
networks:
docker-dataplane:
external: true
name: docker-dataplane
# ============================================================
# SETUP GUIDE
# ============================================================
#
# 0. Create PostgreSQL databases (run once):
# docker exec -it postgres-shared psql -U postgres -c "
# CREATE USER media_user WITH PASSWORD '<MEDIA_DB_PASSWORD>';
# CREATE DATABASE sonarr OWNER media_user;
# CREATE DATABASE radarr OWNER media_user;
# CREATE DATABASE prowlarr OWNER media_user;
# GRANT ALL PRIVILEGES ON DATABASE sonarr TO media_user;
# GRANT ALL PRIVILEGES ON DATABASE radarr TO media_user;
# GRANT ALL PRIVILEGES ON DATABASE prowlarr TO media_user;
# "
#
# 1. Create download directories:
# mkdir -p /mnt/media/downloads/complete /mnt/media/downloads/incomplete /mnt/media/downloads/usenet
# chown -R 1000:1000 /mnt/media/downloads
#
# 2. Create config directories:
# mkdir -p ~/docker-data/sonarr ~/docker-data/radarr ~/docker-data/prowlarr ~/docker-data/sabnzbd
# chown -R 1000:1000 ~/docker-data/sonarr ~/docker-data/radarr ~/docker-data/prowlarr ~/docker-data/sabnzbd
#
# 3. Set MEDIA_DB_PASSWORD environment variable in Portainer stack or export before deploy
#
# 4. Deploy the stack via Portainer or:
# docker stack deploy -c media.yml media
#
# 5. Configure services in order:
#
# a) SABnzbd (http://localhost:8880):
# - Complete setup wizard
# - Add Usenet server credentials
# - Configure download categories: tv, movies
# - Note the API key for Sonarr/Radarr
#
# b) Prowlarr (http://localhost:9696):
# - Add indexers (NZBgeek, DrunkenSlug, etc.)
# - Add Sonarr as application: http://sonarr:8989
# - Add Radarr as application: http://radarr:7878
# - Sync indexers to apps
#
# c) Sonarr (http://localhost:8989):
# - Settings → Media Management → Root Folder: /tv
# - Settings → Download Clients → Add SABnzbd:
# Host: sabnzbd, Port: 8080, API Key: <from SABnzbd>
# - Indexers will be synced from Prowlarr
#
# d) Radarr (http://localhost:7878):
# - Settings → Media Management → Root Folder: /movies
# - Settings → Download Clients → Add SABnzbd:
# Host: sabnzbd, Port: 8080, API Key: <from SABnzbd>
# - Indexers will be synced from Prowlarr
#
# e) Jellyfin (http://localhost:8096):
# - Already configured (migrated from previous stack)
# - Libraries should auto-detect new content
#
# 5. Inter-service communication (use container names):
# - SABnzbd from Sonarr/Radarr: http://sabnzbd:8080
# - Prowlarr from Sonarr: http://prowlarr:9696
# - All services on docker-dataplane network
#
# STORAGE LAYOUT:
# /mnt/media/
# ├── downloads/
# │ ├── complete/ # Completed downloads
# │ ├── incomplete/ # In-progress downloads
# │ └── usenet/ # Usenet-specific
# └── jellyfin/
# ├── movies/ # Radarr imports here
# └── series/ # Sonarr imports here