Files
portainer-core/CONTAINERS.md
T
jpmschweitzerandClaude Opus 4.5 6052f81ec1 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>
2026-01-06 12:39:27 +01:00

50 KiB

Container Reference - tower-of-joy Infrastructure

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


🚀 Quick Reference - All Services

Service Port(s) URL External Access GPU Redis DB Status
Portainer 8080, 8443 http://192.168.86.149:8080 LAN No - Running
Nginx Proxy Manager 81 (admin), 80, 443 http://192.168.86.149:81 Internet No - Running
Authentik 9000, 9444 (outpost) https://auth.schweitz.net Internet (SSO) No - Running
PostgreSQL Shared 5432 N/A (internal) No No - Running
Redis Shared 6379 N/A (internal) No No - Running
Ollama 11434 http://192.168.86.149:11434 LAN Yes (RTX 2080 Ti) - Running
Headscale 8085, 9090 http://192.168.86.149:8085 LAN No - Running
Watchtower None N/A (background) No No - Running
Open WebUI 82 https://webui.schweitz.net Internet (SSO) No - Running
Core API 8083 http://192.168.86.149:8083 LAN No - Running (external)
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
Qdrant 6333, 6334 http://192.168.86.149:6333 LAN No - Running
Wiki.js 3000 http://192.168.86.149:3000 LAN No 2 Running
Tatlock 8000 https://tatlock.schweitz.net Internet (SSO) No 1, 6 Running (external)
Library Desk 8089 http://192.168.86.149:8089 LAN No 4 Running (external)
AMP (Game Server) Varies http://192.168.86.149:8081 LAN No - Running
Home Assistant 8123 https://housekeeping.schweitz.net Internet No - Running
Paperless-ngx 8091 https://documents.schweitz.net Internet No 8 Running
ClamAV 3310 N/A (host service) No No - Running
AdGuard Home 53, 3053 http://dns.schweitz.internal LAN (DNS) No - Running
Tatlock UI 9999 https://home.schweitz.net Internet No - Running

External Domains (SSL via Let's Encrypt)

  • home.schweitz.net → Tatlock UI
  • media.schweitz.net → Jellyfin
  • cloud.schweitz.net → Nextcloud
  • git.schweitz.net → Gitea
  • auth.schweitz.net → Authentik SSO
  • api.schweitz.net → Core API
  • code.schweitz.net → Code-Server (host service)
  • amp.schweitz.net → AMP Game Server
  • housekeeping.schweitz.net → Home Assistant
  • documents.schweitz.net → Paperless-ngx
  • library.schweitz.net → Wiki.js
  • tatlock.schweitz.net → Tatlock API (Protected by Authentik SSO)
  • webui.schweitz.net → Open WebUI (Protected by Authentik SSO)

Internal Domains (HTTP, No Auth)

Internal domains provide LAN-accessible URLs without SSL or Authentik, ideal for programmatic access, scripts, and healthchecks. Each mirrors its external counterpart.

Internal Domain Backend Port
home.schweitz.internal localhost 9999
media.schweitz.internal localhost 8096
cloud.schweitz.internal localhost 8082
api.schweitz.internal localhost 8083
code.schweitz.internal localhost 8084
amp.schweitz.internal localhost 8080
housekeeping.schweitz.internal localhost 8123
documents.schweitz.internal 192.168.86.149 8091
git.schweitz.internal localhost 3002
library.schweitz.internal localhost 8088
tatlock.schweitz.internal localhost 8000
webui.schweitz.internal localhost 82
dns.schweitz.internal localhost 3053

DNS Resolution: Via /etc/hosts on tower-of-joy (192.168.86.149)

Usage: curl http://api.schweitz.internal/health or docker pull git.schweitz.internal/jpmschweitzer/core-api:latest

External Repositories

Services marked "(external)" have source code in separate Gitea repositories. Container images are built via Gitea Actions on release and auto-updated by Watchtower.

Service Repository Image
Scheduler scheduler git.schweitz.net/jpmschweitzer/scheduler:latest
Core API core-api git.schweitz.net/jpmschweitzer/core-api:latest
Library Desk library-desk git.schweitz.net/jpmschweitzer/library-desk:latest
Tatlock UI tatlock-ui git.schweitz.net/jpmschweitzer/tatlock-ui:latest

Development workflow: Clone repo → make changes → create Gitea release → Watchtower auto-updates container.


📊 Infrastructure Management via Core API

The Core API (port 8083) provides REST endpoints for managing the entire infrastructure:

Available Endpoints

  • GET /infrastructure/health - Check Portainer + NPM connectivity
  • GET /infrastructure/services - List all deployed stacks (17 stacks)
  • GET /infrastructure/services/{name} - Get service details
  • POST /infrastructure/services - Deploy new stack from Docker Compose
  • PUT /infrastructure/services/{name} - Update existing stack
  • DELETE /infrastructure/services/{name} - Remove service and stack
  • GET /infrastructure/ports - List all allocated ports
  • GET /infrastructure/domains - List configured domains (11 domains)
  • GET /infrastructure/proxy/{id} - Get proxy host details
  • POST /infrastructure/proxy - Create new proxy host with SSL
  • PUT /infrastructure/proxy/{id} - Update proxy configuration API Documentation: http://192.168.86.149:8083/docs

Infrastructure Layer

Portainer

Portainer provides the web-based container management interface for the entire stack, offering visual control over Docker containers, stacks, images, volumes, and networks. It serves as the primary management tool for deploying and monitoring all other services, with GPU device management enabled for allocation to ML and transcoding workloads. The interface replaces the need for manual Docker CLI operations and provides real-time container logs, stats, and control.

Property Value
Image portainer/portainer-ce:latest
Container Name portainer
Access URL http://192.168.86.149:8001
External Access LAN only (behind firewall)
Port Mapping 8001:9000 (HTTP), 8443:9443 (HTTPS)
Network Mode Host
Restart Policy always
Volume Mounts portainer_data:/data, /var/run/docker.sock
Resource Limits None
GPU Required No
Dependencies None (base service)

PostgreSQL Shared

PostgreSQL Shared is a centralized PostgreSQL 17 database server providing isolated database instances for multiple applications across the infrastructure, including Authentik (SSO), Gitea (Git hosting), and future services requiring relational database storage. It implements a shared infrastructure pattern where each application gets its own database and user credentials while sharing the same PostgreSQL instance for resource efficiency. The service stores all database data on the HDD with automated backups scheduled to the backups directory, providing persistent storage with volume-based data retention across container updates.

Property Value
Image postgres:17
Container Name postgres-shared
Access URL N/A (internal database server)
External Access No (docker-dataplane network only)
Port Mapping 5432:5432 (PostgreSQL)
Network Mode Bridge (docker-dataplane)
Restart Policy unless-stopped
Volume Mounts /home/jpmschweitzer/docker-data/postgres-shared/data:/var/lib/postgresql/data, /home/jpmschweitzer/docker-data/postgres-shared/backups:/backups
Environment POSTGRES_PASSWORD=<secure-password>, POSTGRES_DB=postgres, TZ=Europe/Amsterdam, PGDATA=/var/lib/postgresql/data/pgdata
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), 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

Initialization: Databases and users for authentik and gitea are created by the postgres-init.sh script.


Redis Shared

Redis Shared is a centralized Redis 7 key-value store providing cache, session storage, and message queue capabilities for multiple applications, with logical database isolation (DB 0-15) allowing each service to maintain separate keyspaces within the same Redis instance. It implements a shared infrastructure pattern where applications use dedicated database numbers, eliminating the need for separate Redis containers per application. The service stores data on the HDD for persistence across restarts, with AOF (Append-Only File) enabled for durability and optional RDB snapshots for backup points.

Property Value
Image redis:7-alpine
Container Name redis-shared
Access URL N/A (internal cache server)
External Access No (docker-dataplane network only)
Port Mapping 6379:6379 (Redis)
Network Mode Bridge (docker-dataplane)
Restart Policy unless-stopped
Volume Mounts /home/jpmschweitzer/docker-data/redis-shared/data:/data
Command redis-server --appendonly yes --dir /data
Resource Limits None
GPU Required No
Dependencies docker-dataplane network
Database Allocation DB 0: Available, DB 1: Tatlock (memory), DB 2: Wiki.js, DB 3: Scheduler, DB 4: Library Desk, DB 5: SearXNG, DB 6: Tatlock (benchmarks), DB 7: Nextcloud, DB 8: Paperless, DB 9-15: Available
Persistence AOF (Append-Only File) enabled for durability
Health Check redis-cli ping returns PONG (30s interval)
Connection String redis://redis-shared:6379/0 (DB 0), redis://redis-shared:6379/1 (DB 1), etc.

Nginx Proxy Manager

Nginx Proxy Manager serves as the unified reverse proxy and SSL certificate manager, providing a web-based interface for routing HTTP/HTTPS traffic to backend services with automatic Let's Encrypt certificate provisioning. It consolidates access to all web services through a single entry point with path-based or subdomain routing, eliminating the need to remember individual service ports. The service handles SSL termination, proxy host configuration, and access list management through an intuitive dashboard.

Property Value
Image jc21/nginx-proxy-manager:latest
Container Name nginx-proxy-manager
Access URL http://192.168.86.149:81
External Access LAN + Internet (ports 80/443 forwarded)
Port Mapping 81:81 (Admin), 80:80 (HTTP), 443:443 (HTTPS)
Network Mode Host
Restart Policy unless-stopped
Volume Mounts ~/docker-data/nginx-proxy-manager/data:/data, ~/docker-data/nginx-proxy-manager/letsencrypt:/etc/letsencrypt
Resource Limits None
GPU Required No
Dependencies None (reverse proxy for other services)

AdGuard Home

AdGuard Home is a network-wide DNS-based ad and tracker blocker that functions as a local DNS server, filtering requests at the network level before they reach any device. It provides encrypted DNS (DoH/DoT) to upstream resolvers, a web-based dashboard for query statistics and configuration, and customizable blocklists for ads, trackers, and malware domains. All devices on the network pointing to this DNS server receive ad blocking without requiring per-device software installation.

Property Value
Image adguard/adguardhome:latest
Container Name adguard
Access URL (LAN) http://192.168.86.149:3053
Internal Domain http://dns.schweitz.internal
External Access LAN only (DNS server for local network)
Port Mapping 192.168.86.149:53:53 (DNS), 3053:3000 (Web UI)
Network Mode Bridge (docker-dataplane)
Restart Policy unless-stopped
Volume Mounts ~/docker-data/adguard/work:/opt/adguardhome/work, ~/docker-data/adguard/conf:/opt/adguardhome/conf
Resource Limits None
GPU Required No
Dependencies None
Upstream DNS Quad9 DoH (https://dns.quad9.net/dns-query)
Health Check nslookup localhost 127.0.0.1 (30s interval)

Ollama

Ollama is a GPU-accelerated large language model server that provides a REST API for running local LLM inference with models up to 13B parameters, leveraging the RTX 2080 Ti's 11GB VRAM for fast on-device AI capabilities. It manages model downloads, quantization, and serving through a simple API compatible with OpenAI's format, supporting use cases like code generation, chat applications, and text processing without cloud dependencies. The service stores models on the SSD for quick loading times and maintains persistent model storage across container restarts.

Property Value
Image ollama/ollama:latest
Container Name ollama
Access URL http://192.168.86.149:11434
External Access LAN only (API endpoint)
Port Mapping 11434:11434 (API)
Network Mode Bridge (custom network)
Restart Policy unless-stopped
Volume Mounts ~/docker-data/ollama/models:/root/.ollama
Resource Limits Memory: 8GB, GPU: 11GB VRAM
GPU Required Yes (NVIDIA RTX 2080 Ti)
GPU Configuration NVIDIA_VISIBLE_DEVICES=all, NVIDIA_DRIVER_CAPABILITIES=compute,utility
Dependencies NVIDIA Container Toolkit
Typical Models llama3.2:3b (~2GB), mistral:7b (~4GB), codellama:7b (~4GB)

Code-Server

Code-Server provides a browser-based Visual Studio Code IDE running directly on the host system, offering a persistent development environment with full access to host-level configurations, filesystems, and systemd services without the limitations of containerization. It replaces traditional SSH access by providing a rich IDE experience that survives network disconnections through session persistence, with integrated terminal access, file explorer, git integration, and extension support. The service runs as a systemd service on the host, listening on localhost and exposed externally through Nginx Proxy Manager with SSL encryption and multi-layer authentication for secure remote development access.

Property Value
Deployment Type Host-based systemd service (NOT containerized)
Binary Location /usr/bin/code-server
Service Name code-server.service
Access URL (LAN) http://127.0.0.1:8084 (localhost only)
Access URL (Public) https://code.schweitz.net
External Access Yes (via NPM reverse proxy with SSL)
Port Binding 127.0.0.1:8084 (not exposed to network)
User/Group jpmschweitzer:jpmschweitzer
Restart Policy always (systemd)
Config Location ~/.config/code-server/config.yaml
Data Storage (SSD) ~/docker-data/code-server/user-data/ (settings, workspace), ~/docker-data/code-server/extensions/ (extensions)
Resource Limits None (native host process)
GPU Required No
Dependencies NPM (reverse proxy), systemd
Authentication Triple-layer: NPM access list, code-server password, SSL certificate
WebSocket Support Required (enabled via NPM proxy)
Typical Memory ~200-500MB (depends on workspace size)
Setup Guide docs/code-server-setup.md

Networking Layer

Headscale

Headscale is a self-hosted control server for Tailscale's mesh VPN protocol, creating a private software-defined network across all connected devices with end-to-end encryption and zero-configuration NAT traversal. It enables secure remote access to all homelab services from anywhere without exposing ports to the internet, using a custom 10.99.0.0/16 IP range for the mesh network. The service manages device registration, authentication, and mesh routing while maintaining full data sovereignty compared to the hosted Tailscale control plane.

Property Value
Image headscale/headscale:latest
Container Name headscale
Access URL http://192.168.86.149:8085
External Access LAN only (control server)
Port Mapping 8085:8080 (Web/API), 9090:9090 (Metrics)
Network Mode Bridge (custom network)
Restart Policy unless-stopped
Volume Mounts ~/docker-data/headscale/config:/etc/headscale, ~/docker-data/headscale/data:/var/lib/headscale
Resource Limits None
GPU Required No
Dependencies None
Network Range 10.99.0.0/16 (mesh IPs)
Pre-Auth Keys 24-hour expiration

Dashboard Layer

Tatlock UI

Tatlock UI is a modern Flutter-based home lab dashboard providing a responsive web interface for monitoring and accessing all infrastructure services. Built as a stateless static web application served via nginx, it offers fast load times and a clean, customizable interface for the tower-of-joy infrastructure. The Flutter web build is compiled and containerized via Gitea Actions, with automatic deployment through Watchtower.

Property Value
Image git.schweitz.net/jpmschweitzer/tatlock-ui:latest
Container Name tatlock-ui
Access URL (LAN) http://192.168.86.149:9999
Access URL (Public) https://home.schweitz.net
External Access Yes (via NPM reverse proxy with SSL)
Port Mapping 9999:80 (HTTP)
Network Mode Bridge (docker-dataplane)
Restart Policy unless-stopped
Volume Mounts None (stateless static web app)
Resource Limits Memory: 128M limit, 32M reservation
GPU Required No
Dependencies None (static frontend)
Source Repository https://git.schweitz.net/jpmschweitzer/tatlock-ui
Health Check wget -q --spider http://localhost:80/ (30s interval)
Features Service dashboard, infrastructure monitoring, responsive design

Optimization Layer

Watchtower

Watchtower automatically monitors all running containers for updated images and performs rolling updates on a configurable schedule, ensuring the infrastructure stays current with security patches and feature releases without manual intervention. It checks Docker Hub and configured registries daily at 4 AM, pulls new images when available, gracefully stops containers, deploys updated versions, and cleans up old images to prevent disk bloat. The service logs all update activities and can send notifications through various channels when updates occur.

Property Value
Image containrrr/watchtower:latest
Container Name watchtower
Access URL N/A (background service)
External Access N/A
Port Mapping None (no exposed ports)
Network Mode Bridge
Restart Policy unless-stopped
Volume Mounts /var/run/docker.sock:/var/run/docker.sock
Environment WATCHTOWER_CLEANUP=true, WATCHTOWER_SCHEDULE=0 0 4 * * *
Resource Limits None
GPU Required No
Dependencies Docker socket (read-write for updates)
Schedule Daily at 4:00 AM
Cleanup Automatic (removes old images)

Application Layer

Open WebUI

Open WebUI is a feature-rich, self-hosted web interface for interacting with large language models via Ollama, providing a ChatGPT-like experience with support for multiple models, conversation history, RAG (Retrieval-Augmented Generation), web search integration, and user authentication. It offers a modern chat interface with streaming responses, markdown rendering, code syntax highlighting, and conversation management, enabling seamless switching between different LLM models and maintaining persistent chat histories in a local database. The service integrates directly with the local Ollama instance for GPU-accelerated inference without cloud dependencies, supporting features like web search via DuckDuckGo, document upload for context, and multi-user access with authentication. It is documented at: https://docs.openwebui.com/

Property Value
Image ghcr.io/open-webui/open-webui:main
Container Name open-webui
Access URL (LAN) http://192.168.86.149:82
Access URL (Public) https://webui.schweitz.net
Internal Domain http://webui.schweitz.internal
External Access Yes (via NPM reverse proxy with SSL + Authentik SSO)
Port Mapping 82:8080 (HTTP)
Network Mode Bridge (custom network: ai-network)
Restart Policy unless-stopped
Volume Mounts ~/docker-data/open-webui:/app/backend/data
Environment OLLAMA_BASE_URL=http://192.168.86.149:11434, DEFAULT_MODELS=llama3.2:3b, ENABLE_RAG_WEB_SEARCH=true, ENABLE_OLLAMA_API=true, WEBUI_AUTH=true, RAG_WEB_SEARCH_ENGINE=duckduckgo, AUDIO_STT_ENGINE=openai, AUDIO_TTS_ENGINE=openai
Resource Limits None
GPU Required No (uses Ollama for GPU inference)
Dependencies Ollama (ML inference backend)
Database SQLite (persistent in volume)
Authentication Built-in user management
Integrated Services Ollama, DuckDuckGo (web search)

Core API

Core API provides OpenAI-compatible HTTP functions for Open WebUI, extending LLM capabilities with AI orchestration, web scraping, and content processing services in a hot-reload development environment. The service implements Phase 1 of the AI Orchestrator plan, providing /v1/chat/completions and /v1/models endpoints with full OpenAI API compatibility, model aliasing (gpt-3.5-turbo → gemma:7b), and streaming support via Server-Sent Events. It uses Trafilatura for intelligent content extraction with BeautifulSoup fallback, offering configurable content length limits and optional link extraction optimized for feeding webpage content to language models. The service runs on Python 3.12 with mounted source code for instant updates, maintaining a persistent venv in docker-data for fast container restarts and development agility.

Property Value
Image git.schweitz.net/jpmschweitzer/core-api:latest
Container Name core-api
Access URL http://192.168.86.149:8083
API Documentation http://192.168.86.149:8083/docs (Swagger UI)
External Access LAN only (internal API)
Port Mapping 8083:8083 (HTTP)
Network Mode Bridge (custom network: docker-dataplane)
Restart Policy unless-stopped
Volume Mounts ~/docker-data/core-api/logs:/app/logs (logs), /var/run/docker.sock:/var/run/docker.sock:ro (Docker access)
Environment APP_NAME=Core API, APP_VERSION=1.0.0-phase1, DEBUG=true, PORT=8083, LOG_LEVEL=INFO, PYTHONPATH=/app, Model aliases: ALIAS_GPT35=gemma:7b, ALIAS_GPT4=mistral:7b
Source Repository https://git.schweitz.net/jpmschweitzer/core-api
Resource Limits None
GPU Required No (proxies requests to Ollama which uses GPU)
Dependencies Ollama (model inference), Open WebUI (consumes this API), ai-dataplane network
Framework FastAPI 0.115.0, Uvicorn 0.32.0, Pydantic 2.10.4, httpx 0.28.1
Key Features OpenAI-compatible API (/v1/chat/completions, /v1/models), Model aliasing (OpenAI → local models), Streaming & non-streaming responses, Web scraping (Trafilatura, BeautifulSoup), Hot-reload development, OpenAPI spec, Infrastructure management (Portainer)
AI Orchestrator Phase 1 Complete - OpenAI API wrapper with model routing. Phase 2+ will add memory systems, multi-agent workflows, and tool integration.
Health Check GET /health (30s interval) - checks API status and Ollama connectivity

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. 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 (docker-dataplane)
Restart Policy unless-stopped
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), 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)

Nextcloud

Nextcloud is a self-hosted cloud storage and collaboration platform providing file sync, sharing, calendar, contacts, and collaborative document editing with a web interface and mobile apps. Uses shared PostgreSQL for metadata and shared Redis for caching. Application config on SSD, user data on HDD. External access via NPM at https://cloud.schweitz.net.

Property Value
Image nextcloud:stable
Container Name nextcloud
Access URL (LAN) http://192.168.86.149:8082
Access URL (Public) https://cloud.schweitz.net
External Access Yes (via NPM reverse proxy with SSL)
Port Mapping 8082:80 (HTTP)
Network Mode docker-dataplane
Restart Policy unless-stopped
Volume Mounts ~/docker-data/nextcloud/config:/var/www/html (SSD), /mnt/media/nextcloud/data:/var/www/html/data (HDD)
Resource Limits None
GPU Required No
Dependencies PostgreSQL Shared, Redis Shared, NPM (reverse proxy)
Database PostgreSQL (shared)
Storage Split Config/apps on SSD, user data on HDD
Features File sync, calendar, contacts, document editing, photo gallery, mobile apps

Home Assistant

Home Assistant is an open-source smart home automation platform that integrates with thousands of IoT devices, sensors, and services to provide centralized control, automation rules, and monitoring through a web dashboard and mobile apps. It supports local processing without cloud dependencies, enabling privacy-focused home automation with features like device tracking, energy monitoring, voice assistants, and custom automations triggered by time, location, or device states. The service stores all configuration, automations, and historical data on the SSD for responsive dashboard loading, with USB device support for Z-Wave and Zigbee coordinators.

Property Value
Image ghcr.io/home-assistant/home-assistant:stable
Container Name home-assistant
Access URL (LAN) http://192.168.86.149:8123
Access URL (Public) https://housekeeping.schweitz.net
External Access Yes (via NPM reverse proxy with SSL)
Port Mapping 8123:8123 (HTTP)
Network Mode Bridge (docker-dataplane)
Restart Policy unless-stopped
Volume Mounts ~/docker-data/home-assistant/config:/config (SSD - configs, database, automations)
Environment TZ=Europe/Amsterdam
Privileged Mode Yes (for USB device access: Z-Wave, Zigbee dongles)
Resource Limits Memory: 1GB
GPU Required No
Dependencies NPM (reverse proxy), USB devices (optional)
Health Check curl -fSs http://localhost:8123/api/ (30s interval)
Features Device integrations, automations, dashboards, energy monitoring, voice assistants, mobile apps

Paperless-ngx

Paperless-ngx is a document management system that transforms physical documents into a searchable online archive with automatic OCR text recognition, tagging, and full-text search. It provides a web interface for uploading, organizing, and retrieving documents with support for correspondents, document types, and custom fields. The service integrates with Library Desk for document indexing and uses ClamAV for virus scanning of uploaded files. Configs and database are stored on SSD (backed up), while documents are stored on HDD for capacity. Uses shared PostgreSQL for metadata and shared Redis (DB 8) for task queuing.

Property Value
Image ghcr.io/paperless-ngx/paperless-ngx:latest
Container Name paperless
Access URL (LAN) http://192.168.86.149:8091
Access URL (Public) https://documents.schweitz.net
External Access Yes (via NPM reverse proxy with SSL)
Port Mapping 8091:8000 (HTTP)
Network Mode Bridge (docker-dataplane)
Restart Policy unless-stopped
Volume Mounts SSD (backed up): ~/docker-data/paperless/data:/usr/src/paperless/data; HDD: /mnt/media/paperless/media:/usr/src/paperless/media, /mnt/media/paperless/consume:/usr/src/paperless/consume, /mnt/media/paperless/export:/usr/src/paperless/export
Environment PAPERLESS_DBHOST=postgres-shared, PAPERLESS_REDIS=redis://redis-shared:6379/8, PAPERLESS_URL=https://documents.schweitz.net, TZ=Europe/Amsterdam
Resource Limits Memory: 4GB limit, 512MB reservation
GPU Required No
Dependencies PostgreSQL Shared, Redis Shared (DB 8), NPM (reverse proxy), ClamAV (host)
Database PostgreSQL paperless on postgres-shared
Health Check curl -f http://localhost:8000 (30s interval)
Features OCR (eng+nld), document tagging, full-text search, correspondents, custom fields, webhooks
Integration Library Desk (webhook on document added), ClamAV (virus scanning)

ClamAV

ClamAV is an open-source antivirus engine running on the host OS, providing virus scanning capabilities for the entire server and accessible via TCP socket for container-based services like Paperless-ngx. It includes automatic virus definition updates via freshclam and can perform both on-demand and real-time scanning. Running on the host provides better security isolation than containerized scanning and allows scanning of the host filesystem directly.

Property Value
Deployment Type Host-based systemd service (NOT containerized)
Binary Location /usr/bin/clamd, /usr/bin/clamdscan
Service Names clamav-daemon.service, clamav-freshclam.service
Access URL N/A (TCP socket only)
External Access No (internal service)
Port Binding 0.0.0.0:3310 (TCP socket for remote scanning)
Restart Policy always (systemd)
Config Location /etc/clamav/clamd.conf, /etc/clamav/freshclam.conf
Database Location /var/lib/clamav/ (virus definitions)
Resource Usage ~2-4GB RAM (virus definitions loaded in memory)
GPU Required No
Dependencies None (host service)
Update Schedule Automatic via freshclam (checks multiple times daily)
Connection String clamav://192.168.86.149:3310
Features On-demand scanning, TCP socket API, automatic updates, host filesystem access

Usage from containers:

# Test connectivity
nc -zv 192.168.86.149 3310

# Scan a file (from host)
clamdscan /path/to/file

Samba

Samba provides SMB/CIFS network file sharing for seamless access to homelab storage from Windows, macOS, Linux, and mobile devices, exposing curated shares for media libraries, downloads, and backups with configurable read-only and read-write permissions. It runs as a single container on the samba_default network, serving three shares: Media (read-write access to Jellyfin content), Downloads (read-write for torrent clients), and Backups (read-only for safe data recovery). The service uses password authentication for the user jpmschweitzer and stores its minimal configuration on the SSD while directly mounting HDD paths for zero-copy file access with native performance.

Property Value
Image dperson/samba
Container Name samba
Access URL \\192.168.86.149 or \\tower-of-joy
External Access LAN only (ports firewalled)
Port Mapping 139:139 (NetBIOS), 445:445 (SMB)
Network Mode Bridge (custom network: samba_default)
Restart Policy unless-stopped
Volume Mounts ~/docker-data/samba:/share/config (SSD config), /mnt/media/jellyfin:/share/media (Media share), /mnt/media/downloads:/share/downloads (Downloads share), /mnt/media/backups:/share/backups:ro (Backups read-only)
Environment TZ=Europe/Amsterdam, USERID=1000, GROUPID=1000
Command Share configs: Media (browseable, guest access), Downloads (no guest), Backups (read-only, browseable)
Resource Limits None
GPU Required No
Dependencies UFW firewall rules (ports 139, 445), Host Samba service disabled
Shares 3 total: Media (R/W), Downloads (R/W), Backups (R/O)
Authentication Username/password (jpmschweitzer)
Client Compatibility Windows, macOS, Linux, iOS, Android

Gitea

Gitea is a lightweight, self-hosted Git service providing repository hosting, issue tracking, pull requests, code review, and CI/CD integration through a clean web interface accessible via both HTTPS and SSH. It runs as a multi-container stack with a PostgreSQL database for metadata storage, offering GitHub-like functionality including organizations, teams, wikis, webhooks, and automated Actions workflows while maintaining complete data sovereignty and minimal resource overhead. The service stores all Git repositories and configuration on the SSD for fast access, integrates behind Nginx Proxy Manager with SSL at https://git.schweitz.net for web access, and exposes SSH on port 2222 for standard Git operations without conflicting with the host's SSH service.

Property Value
Image gitea/gitea:latest
Container Name gitea
Access URL (LAN) http://192.168.86.149:3002
Access URL (Public) https://git.schweitz.net
External Access Yes (via NPM reverse proxy with SSL)
Port Mapping 3002:3000 (HTTP), 2222:22 (SSH)
Network Mode Bridge (custom network: gitea_gitea-network)
Restart Policy unless-stopped
Volume Mounts ~/docker-data/gitea/data:/data (SSD - repos, config)
Environment USER_UID=1000, USER_GID=1000, GITEA__database__* (PostgreSQL connection), TZ=Europe/Amsterdam
Resource Limits None
GPU Required No
Dependencies PostgreSQL 14 (gitea-db), NPM (reverse proxy)
Database PostgreSQL on SSD (~50MB)
SSH Access Port 2222 - git clone ssh://git@git.schweitz.net:2222/user/repo.git
Features Git hosting, Organizations/teams, Issues/PRs, Code review, Wikis, Webhooks, Gitea Actions (CI/CD), GitHub/GitLab migration
SSH Config Tip Add to ~/.ssh/config: Host git.schweitz.net / Port 2222 / User git for seamless cloning

Quick Reference Tables

Service Access Matrix

Service LAN URL Internet Access Primary Function
Portainer http://192.168.86.149:8001 No Container management
PostgreSQL Shared postgres-shared:5432 No (internal) Shared database server
Redis Shared redis-shared:6379 No (internal) Shared cache/session store
NPM http://192.168.86.149:81 Yes (admin) Reverse proxy admin
Code-Server https://code.schweitz.net Yes Browser-based IDE
Ollama http://192.168.86.149:11434 No ML model API
Headscale http://192.168.86.149:8085 No VPN control server
Open WebUI https://webui.schweitz.net Yes (SSO) LLM chat interface
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
Home Assistant https://housekeeping.schweitz.net Yes Smart home automation
Tatlock UI https://home.schweitz.net Yes Home lab dashboard
Watchtower N/A (background) N/A Auto-updates

GPU-Enabled Services

Service GPU Usage VRAM Requirements Purpose
Ollama Compute, Utility 2-10GB (model dependent) LLM inference
Jellyfin Video Encode/Decode ~1-2GB (during transcode) Media transcoding

Total VRAM Available: 11GB (RTX 2080 Ti)


Storage Distribution

Service Config Location (SSD) Data Location (HDD) Typical Size
Portainer Docker volume: portainer_data N/A ~100MB
PostgreSQL Shared N/A ~/docker-data/postgres-shared/data/ Data: 100MB-5GB (depends on databases), Backups: variable
Redis Shared N/A ~/docker-data/redis-shared/data/ ~10-100MB (AOF + RDB snapshots)
NPM ~/docker-data/nginx-proxy-manager/ N/A ~50MB
Code-Server ~/.config/code-server/, ~/docker-data/code-server/ N/A Config: ~5MB, Extensions: ~50-200MB, User data: ~50MB
Ollama ~/docker-data/ollama/models/ Alt: /mnt/media/ollama/ 2-15GB per model
Headscale ~/docker-data/headscale/ N/A ~10MB
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
Home Assistant ~/docker-data/home-assistant/config/ N/A Config: ~100MB, DB: ~50MB
Tatlock UI None (stateless) N/A ~0MB (static files in container)

SSD Usage (docker-data): ~6-11GB (configs, caches, databases) HDD Usage (/mnt/media): ~2.1TB / 3.6TB (58% used)


Network Architecture

As of 2025-11-15, all services have been consolidated to the docker-dataplane bridge network for simplified service discovery and inter-container communication. This consolidation replaced 12+ legacy networks with a single unified network, enabling all services to communicate using container names as DNS hostnames.

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, 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:

  • Service Discovery: All services reachable via http://container-name:port (e.g., http://postgres-shared:5432)
  • Shared Infrastructure: postgres-shared and redis-shared accessible to all applications
  • Network Cleanup: Removed 7 obsolete networks (stacks_default, ai-dataplane, various stack-specific networks)

Container Name Resolution Examples:

# From any container on docker-dataplane
curl http://ollama:11434           # Ollama LLM API
psql -h postgres-shared -U postgres  # PostgreSQL connection
redis-cli -h redis-shared          # Redis connection

Restart Policies

Policy Containers Behavior
always Portainer Restart on failure, on Docker daemon restart
unless-stopped All others Restart on failure, but not after manual stop

Automated Tasks

Service Task Frequency Time
Watchtower Container updates Daily 4:00 AM
Scheduler Config backups Daily 3:05 AM
Scheduler Doc sync Monthly 11th/12th

Last Updated: 2026-01-04