From 6052f81ec1c7656ff0e48224a54c4bc52f77e8dd Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Tue, 6 Jan 2026 12:39:27 +0100 Subject: [PATCH] feat(stack): add unified media stack with Sonarr, Radarr, Prowlarr, SABnzbd MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- CONTAINERS.md | 138 +++++++++++++++++++++-- pg-connections.sh | 8 ++ stacks/jellyfin.yml | 75 ------------- stacks/media.yml | 260 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 396 insertions(+), 85 deletions(-) create mode 100755 pg-connections.sh delete mode 100644 stacks/jellyfin.yml create mode 100644 stacks/media.yml diff --git a/CONTAINERS.md b/CONTAINERS.md index f941bf1..72c9d5b 100644 --- a/CONTAINERS.md +++ b/CONTAINERS.md @@ -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**: diff --git a/pg-connections.sh b/pg-connections.sh new file mode 100755 index 0000000..2642d06 --- /dev/null +++ b/pg-connections.sh @@ -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;" diff --git a/stacks/jellyfin.yml b/stacks/jellyfin.yml deleted file mode 100644 index cb66e43..0000000 --- a/stacks/jellyfin.yml +++ /dev/null @@ -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 diff --git a/stacks/media.yml b/stacks/media.yml new file mode 100644 index 0000000..4579f6a --- /dev/null +++ b/stacks/media.yml @@ -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 ''; +# 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: +# - 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: +# - 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