Add self-hosted Penpot (Figma alternative) with: - Docker stack using shared PostgreSQL and Redis infrastructure - Authentik SSO integration (OIDC, password login disabled) - Three services: frontend, backend, exporter - Port 9001 for web UI, external via penpot.schweitz.net Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
59 KiB
Container Reference - tower-of-joy Infrastructure
Last Updated: 2026-01-31 Total Services: 34 containers across 21 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) |
| Webber | 8086 | http://192.168.86.149:8086 | LAN | No | 9 | ✅ Running (external) |
| Library Desk | 8089 | http://192.168.86.149:8089 | LAN | No | 4 | ✅ Running (external) |
| AMP (Game Server) | 8080-8082 | https://amp.schweitz.net | Internet | No | - | ✅ Running |
| Home Assistant | 8123 | https://housekeeping.schweitz.net | Internet | No | - | ✅ Running |
| Paperless-ngx | 8091 | https://documents.schweitz.net | Internet | No | 8 | ✅ Running |
| Penpot | 9001 | https://penpot.schweitz.net | Internet (SSO) | No | 10 | ⏳ Pending Deploy |
| 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
- penpot.schweitz.net → Penpot (Protected by Authentik SSO)
- 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 |
| penpot.schweitz.internal | localhost | 9001 |
| 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 |
| Webber | webber | git.schweitz.net/jpmschweitzer/webber: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 connectivityGET /infrastructure/services- List all deployed stacks (17 stacks)GET /infrastructure/services/{name}- Get service detailsPOST /infrastructure/services- Deploy new stack from Docker ComposePUT /infrastructure/services/{name}- Update existing stackDELETE /infrastructure/services/{name}- Remove service and stackGET /infrastructure/ports- List all allocated portsGET /infrastructure/domains- List configured domains (11 domains)GET /infrastructure/proxy/{id}- Get proxy host detailsPOST /infrastructure/proxy- Create new proxy host with SSLPUT /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), penpot (Design platform), 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, penpot_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: Webber (sessions), DB 10: Penpot, DB 11-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 |
Tatlock
Tatlock is the "Homelab Butler" - an OpenAI-compatible API server with LLM agent orchestration capabilities, providing intelligent automation and chat functionality for the tower-of-joy infrastructure. It serves as the primary AI backend for the homelab, offering model proxying through Ollama, vector search via Qdrant, web search integration through SearXNG, and memory persistence via Redis. The service provides user authentication and API key management that other agent services (like Webber) use for validation. Part of the unified agents stack alongside Webber.
| Property | Value |
|---|---|
| Image | git.schweitz.net/jpmschweitzer/tatlock:latest |
| Container Name | tatlock |
| Stack | agents (unified agents stack) |
| Access URL (LAN) | http://192.168.86.149:8000 |
| Access URL (Public) | https://tatlock.schweitz.net |
| Internal Domain | http://tatlock.schweitz.internal |
| External Access | Yes (via NPM reverse proxy with SSL + Authentik SSO) |
| Port Mapping | 8000:8000 (HTTP) |
| Network Mode | Bridge (docker-dataplane) |
| Restart Policy | unless-stopped |
| Volume Mounts | ~/docker-data/tatlock/logs:/app/logs |
| Environment | OLLAMA_HOST=http://ollama:11434, OLLAMA_DEFAULT_MODEL=mistral-nemo:latest, QDRANT_HOST=qdrant, SEARXNG_HOST=http://searxng:8080 |
| Source Repository | https://git.schweitz.net/jpmschweitzer/tatlock |
| Resource Limits | CPU: 1.0, Memory: 1GB limit, 256MB reservation |
| GPU Required | No (uses Ollama for GPU inference) |
| Redis DB | DB 1 (memory), DB 6 (benchmarks) |
| Dependencies | Ollama, Qdrant, Redis Shared, SearXNG, Library Desk |
| Framework | FastAPI, Python |
| Key Features | OpenAI-compatible API, LLM agent orchestration, vector search, web search, user auth, API key management |
| Health Check | curl -f http://localhost:8000/health (30s interval) |
| Inter-service URL | http://tatlock:8000 (from other containers) |
Webber
Webber is an LLM agent orchestration API that provides autonomous agent execution with tool use capabilities, enabling complex multi-step tasks through natural language instructions. It connects to Ollama for LLM inference and embedding models, authenticates users via the Tatlock API, and manages agent sessions with configurable TTL and context limits. The service supports sandboxed tool execution with configurable timeouts and allowed paths, making it suitable for agentic workflows that require code execution or file manipulation. Part of the unified agents stack alongside Tatlock.
| Property | Value |
|---|---|
| Image | git.schweitz.net/jpmschweitzer/webber:latest |
| Container Name | webber |
| Stack | agents (unified agents stack) |
| Access URL (LAN) | http://192.168.86.149:8086 |
| External Access | LAN only (internal API) |
| Port Mapping | 8086:8086 (HTTP) |
| Network Mode | Bridge (docker-dataplane) |
| Restart Policy | unless-stopped |
| Volume Mounts | ~/docker-data/webber/logs:/app/logs, ~/docker-data/webber/sandbox:/app/sandbox |
| Environment | OLLAMA_URL=http://ollama:11434, OLLAMA_AGENT_MODEL=mistral-nemo:latest, OLLAMA_EMBED_MODEL=nomic-embed-text:latest, TATLOCK_API_URL=http://tatlock:8000, TOOL_TIMEOUT_SECONDS=30, SESSION_TTL_HOURS=24, MAX_CONTEXT_TOKENS=8192 |
| Source Repository | https://git.schweitz.net/jpmschweitzer/webber |
| Resource Limits | CPU: 1.0, Memory: 1GB limit, 256MB reservation |
| GPU Required | No (uses Ollama for GPU inference) |
| Redis DB | DB 9 (sessions) |
| Dependencies | Ollama, Tatlock (auth), Redis Shared |
| Framework | FastAPI, Python |
| Key Features | Autonomous agent execution, tool use, sandboxed code execution, session management, embedding support |
| Health Check | curl -f http://localhost:8086/health (30s interval) |
| Inter-service URL | http://webber:8086 (from other containers) |
AMP (Game Server Manager)
AMP (Application Management Panel) by CubeCoders is a game server management panel that provides a web interface for deploying, configuring, and managing multiple game servers including Minecraft, Vintage Story, and many others. The ADS (Application Deployment Service) controller runs as a standalone Docker container on host network, spawning individual game server instances as separate containers. The setup uses a custom entrypoint wrapper to handle Docker socket permissions, allowing AMP to manage child containers while running as a non-root user.
| Property | Value |
|---|---|
| Image | mitchtalmadge/amp-dockerized:latest |
| Container Name | amp-ads |
| Deployment | Standalone docker-compose (not Portainer stack) |
| Access URL (LAN) | http://192.168.86.149:8080 |
| Access URL (Public) | https://amp.schweitz.net |
| External Access | Yes (via NPM reverse proxy with SSL) |
| Port Mapping | 8080 (ADS), 8081 (justcreate01), 8082 (vine01), plus game ports |
| Network Mode | Host (required for ADS to reach game containers) |
| Restart Policy | unless-stopped |
| Volume Mounts | ~/docker-data/amp:/home/amp/.ampdata (SSD), /mnt/media/amp/instances (HDD via symlink) |
| Environment | UID=1013, GID=1014, TZ=Europe/Amsterdam, MODULE=ADS |
| Resource Limits | None |
| GPU Required | No |
| Dependencies | Docker socket, custom entrypoint wrapper for permissions |
| Compose Location | /home/jpmschweitzer/docker-data/amp/docker-compose.yml |
| Game Instances | justcreate01 (Minecraft NeoForge), vine01 (Vintage Story) |
| License | Static MAC address (02:42:ac:11:00:a0) for license persistence |
| Health Check | curl -fSs http://localhost:8080 (30s interval) |
Note: Game server containers (AMP_justcreate01, AMP_vine01) are spawned dynamically by AMP and appear as standalone containers in Portainer, not grouped under a stack.
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) |
Penpot
Penpot is an open-source design and prototyping platform, serving as a self-hosted alternative to Figma with support for real-time collaboration, vector editing, prototyping, and design handoff. It provides a web-based interface for creating UI/UX designs, wireframes, and interactive prototypes with features like components, auto-layout, and multi-page documents. The service uses Authentik SSO for authentication (password login disabled), stores design assets on the SSD, and leverages shared PostgreSQL and Redis infrastructure for data persistence and real-time collaboration via WebSockets.
| Property | Value |
|---|---|
| Stack | penpot |
| Containers | penpot-frontend (nginx), penpot-backend (Clojure API), penpot-exporter (PDF/SVG) |
| Access URL (LAN) | http://192.168.86.149:9001 |
| Access URL (Public) | https://penpot.schweitz.net |
| Internal Domain | http://penpot.schweitz.internal |
| External Access | Yes (via NPM reverse proxy with SSL + Authentik SSO) |
| Port Mapping | 9001:80 (HTTP) |
| Network Mode | Bridge (docker-dataplane) |
| Restart Policy | unless-stopped |
| Volume Mounts | ~/docker-data/penpot/assets:/opt/data/assets (SSD - uploads, exports) |
| Environment | PENPOT_PUBLIC_URI=https://penpot.schweitz.net, PENPOT_DATABASE_URI=postgresql://postgres-shared:5432/penpot, PENPOT_REDIS_URI=redis://redis-shared:6379/10, TZ=Europe/Amsterdam |
| Resource Limits | Backend: 1GB memory, Exporter: 1GB memory |
| GPU Required | No |
| Database | PostgreSQL penpot on postgres-shared (user: penpot_user) |
| Redis DB | DB 10 (cache + WebSocket coordination) |
| Dependencies | PostgreSQL Shared, Redis Shared, Authentik (SSO), NPM (reverse proxy) |
| Authentication | Authentik OIDC only (password login disabled) |
| Health Check | Frontend: curl http://localhost:80, Backend: curl http://localhost:6060/api/health |
| WebSocket Support | Required (enabled via NPM for real-time collaboration) |
| Features | Vector editing, prototyping, components, auto-layout, multi-page, real-time collaboration, PDF/SVG export |
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 |
| Webber | http://192.168.86.149:8086 | No | LLM agent execution 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 |
| AMP | https://amp.schweitz.net | Yes | Game server management |
| Penpot | https://penpot.schweitz.net | Yes (SSO) | Design & prototyping |
| 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 |
| AMP | ~/docker-data/amp/ |
/mnt/media/amp/instances/ (via symlink) |
Config: ~1.1GB (versions), Game data: variable |
| Home Assistant | ~/docker-data/home-assistant/config/ |
N/A | Config: ~100MB, DB: ~50MB |
| Tatlock | ~/docker-data/tatlock/logs/ |
N/A | Logs: ~10MB |
| Webber | ~/docker-data/webber/logs/, ~/docker-data/webber/sandbox/ |
N/A | Logs: ~10MB, Sandbox: variable |
| Penpot | ~/docker-data/penpot/assets/ |
N/A | Assets: variable (uploads, exports) |
| 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, Webber, Tatlock UI, Home Assistant, Jellyfin, Sonarr, Radarr, Prowlarr, SABnzbd, Penpot (frontend, backend, exporter) | Unified service mesh for all containerized applications |
| host | Portainer, NPM, AMP (amp-ads + game containers) | Direct host port access for infrastructure and game servers |
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-31