Split monolithic compose into 5 independent stacks

- docker-compose.infra.yml: core infrastructure (portainer, npm, homepage, wud, etc.)
- docker-compose.media.yml: media stack (arrs, jellyfin, qbittorrent, scrobbling)
- docker-compose.documents.yml: paperless-ngx, onlyoffice, stirling, open-webui
- docker-compose.photo-roms.yml: immich, syncthing, retrom
- docker-compose.utils.yml: gitea, tandoor, speedtest, linkwarden, rustdesk, etc.

Each stack has its own project name (docker-infra, docker-media, etc.) to prevent
orphan warnings. Networks defined in infra.yml, referenced as external by others.
Original preserved as docker-compose.full.yaml.bak.
Updated .gitignore, README, AGENTS.md, and RESTORE.md to reflect new structure.
This commit is contained in:
KansaiGaijin
2026-05-14 22:58:11 +12:00
parent 76e99f9df9
commit b2f4d37f19
10 changed files with 1675 additions and 601 deletions

7
.gitignore vendored
View File

@@ -2,7 +2,12 @@
/* /*
# Only track these files # Only track these files
!docker-compose.yaml !docker-compose.infra.yml
!docker-compose.media.yml
!docker-compose.documents.yml
!docker-compose.photo-roms.yml
!docker-compose.utils.yml
!docker-compose.full.yaml.bak
!.env.example !.env.example
!.gitignore !.gitignore
!README.md !README.md

209
AGENTS.md
View File

@@ -1,20 +1,34 @@
# AGENTS - Docker Infrastructure Documentation # AGENTS - Docker Infrastructure Documentation
## Overview ## Overview
This document provides a comprehensive overview of the Docker infrastructure managed in `/docker/`. This self-hosted ecosystem contains 30+ services organized into functional categories, all integrated through a reverse proxy and secured with proper network segmentation. This document provides a comprehensive overview of the Docker infrastructure managed in `/docker/`. This self-hosted ecosystem contains 50+ services organized into 5 compose stacks, all integrated through a reverse proxy and secured with proper network segmentation.
## Core Infrastructure Agents ## Compose Stack Organization
The infrastructure is split into 5 independent compose files sharing a common `.env`:
| Stack | File | Services |
|-------|------|----------|
| **Infrastructure** | `docker-compose.infra.yml` | Core: portainer, npm, dockerproxy, homepage, wud, ntopng, newt |
| **Media** | `docker-compose.media.yml` | Media: arr stack, jellyfin, qbittorrent, slskd, metube, maloja, scrobbler |
| **Documents** | `docker-compose.documents.yml` | Paperless-ngx + AI, onlyoffice, stirling-pdf, open-webui |
| **Photo & ROM Library** | `docker-compose.photo-roms.yml` | Immich, syncthing, retrom |
| **Utilities** | `docker-compose.utils.yml` | Gitea, tandoor, speedtest-tracker, rustdesk, redbot, linkwarden, neolink, iperf3 |
## Core Infrastructure Agents (infra.yml)
### Management & Monitoring ### Management & Monitoring
- **Portainer** - Container management UI (port 9443) - **Portainer** - Container management UI (port 9443)
- **Homepage** - Service dashboard (port 7575) - **Homepage** - Service dashboard (port 7575)
- **WUD (WhatsUpDocker)** - Docker image management utility - **WUD (WhatsUpDocker)** - Docker image management utility
- **ntopng** - Network traffic monitoring (port 3939)
### Reverse Proxy & Security ### Reverse Proxy & Security
- **Nginx Proxy Manager** - SSL termination and reverse proxy (ports 80, 443, 81) - **Nginx Proxy Manager** - SSL termination and reverse proxy (ports 80, 443, 81)
- **Docker Socket Proxy** - Secure Docker API access (port 2375) - **Docker Socket Proxy** - Secure Docker API access (port 2375)
- **Newt** - Pangolin tunnel client
## Media & Entertainment Stack ## Media & Entertainment Stack (media.yml)
### Media Server ### Media Server
- **Jellyfin** - Media server with hardware transcoding (port 8096) - **Jellyfin** - Media server with hardware transcoding (port 8096)
@@ -25,6 +39,7 @@ This document provides a comprehensive overview of the Docker infrastructure man
- **qBittorrent** - Torrent client (ports 56881, 7070) - **qBittorrent** - Torrent client (ports 56881, 7070)
- **Prowlarr** - Indexer manager (port 9696) - **Prowlarr** - Indexer manager (port 9696)
- **FlareSolverr** - Cloudflare bypass service (port 8191) - **FlareSolverr** - Cloudflare bypass service (port 8191)
- **Metube** - YouTube video downloader (port 8081)
### Content Management ### Content Management
- **Radarr** - Movie management (port 7878) - **Radarr** - Movie management (port 7878)
@@ -36,7 +51,12 @@ This document provides a comprehensive overview of the Docker infrastructure man
### File Sharing ### File Sharing
- **Slskd** - Soulseek file sharing client (ports 5030, 5031, 50300) - **Slskd** - Soulseek file sharing client (ports 5030, 5031, 50300)
## Document & Data Management ### Music & Scrobbling
- **Maloja** - Music scrobbling service (port 42010)
- **Multi-Scrobbler** - Cross-platform scrobbling (port 9078)
- Integrates with Jellyfin and Last.fm
## Document & AI Suite (documents.yml)
### Document Processing ### Document Processing
- **Paperless-ngx** - Document management (port 8100) - **Paperless-ngx** - Document management (port 8100)
@@ -45,9 +65,14 @@ This document provides a comprehensive overview of the Docker infrastructure man
- **Stirling-PDF** - PDF manipulation tools (port 8090) - **Stirling-PDF** - PDF manipulation tools (port 8090)
- **OnlyOffice** - Document collaboration (port 8091) - **OnlyOffice** - Document collaboration (port 8091)
### AI Interface
- **Open WebUI** - LLM interface (port 3000)
## Photo Management & Library (photo-roms.yml)
### Photo Management ### Photo Management
- **Immich** - AI-powered photo management (port 2283) - **Immich** - AI-powered photo management (port 2283)
- PostgreSQL with vector search, Redis cache - PostgreSQL with vector search, Valkey/Redis cache
- Local SSD storage for config and thumbs - Local SSD storage for config and thumbs
### File Synchronization ### File Synchronization
@@ -55,58 +80,6 @@ This document provides a comprehensive overview of the Docker infrastructure man
- Obsidian vault synchronization - Obsidian vault synchronization
- Multiple shared folders - Multiple shared folders
## AI & Development Services
### AI Infrastructure
- **Open WebUI** - LLM interface (port 3000)
- **LiteLLM** - AI gateway (port 4000)
- PostgreSQL database for configuration
- Supports multiple AI providers
### Development Tools
- **Gitea** - Git service (ports 222, 8418)
- MySQL database
- **Newt** - AI service integration
## Genealogy & Personal Tools
### Family History
- **GrampsWeb Jamie** - Genealogy UI (port 5511)
- **GrampsWeb Helen** - Genealogy UI (port 5512)
- Shared Redis broker
- Separate trees for different family branches
### Finance & Tracking
- **Speedtest Tracker** - Network monitoring (port 8180)
- MariaDB database, automated testing
### Personal Tools
- **Tandoor Recipes** - Self-hosted recipe management
- **Surmai** - Personal flight tracking tool
### Music & Scrobbling
- **Maloja** - Music scrobbling service (port 42010)
- **Multi-Scrobbler** - Cross-platform scrobbling (port 9078)
- Integrates with Jellyfin and Last.fm
## Utilities & External Services
### Remote Access
- **RustDesk** - Remote desktop (host mode)
### Network Tools
- **iperf3-server** - Network performance testing (port 5201)
- **ntopng** - Network traffic monitoring tool (port 3939)
### Browser Workspace
- **Kasm** - Browser isolation workspace (containerized browsing)
### Game Servers
- **Foundry Watcher** - Foundry VTT player monitoring service
- SSH log tailing from Foundry server
- REST API for player status (port 30001)
- MQTT integration for connection events
### ROM Management ### ROM Management
- **Retrom** - ROM library management service - **Retrom** - ROM library management service
- **retrom**: Main ROM service container (port 5111) - **retrom**: Main ROM service container (port 5111)
@@ -114,29 +87,50 @@ This document provides a comprehensive overview of the Docker infrastructure man
- **retrom-adminer**: Adminer interface for database management (port 8080) - **retrom-adminer**: Adminer interface for database management (port 8080)
- **retrom-jaeger**: Distributed tracing for performance monitoring - **retrom-jaeger**: Distributed tracing for performance monitoring
## Utilities Stack (utils.yml)
### Development Tools
- **Gitea** - Git service (ports 222, 8418)
- MySQL database
### Personal Tools
- **Tandoor Recipes** - Self-hosted recipe management (port 8450)
- PostgreSQL database
### Finance & Tracking
- **Speedtest Tracker** - Network monitoring (port 8180)
- MariaDB database, automated testing
### Bookmark Management
- **Linkwarden** - Collaborative bookmark manager (port 3400)
- PostgreSQL database
- Meilisearch for full-text search
### Remote Access
- **RustDesk** - Remote desktop (host mode)
### Home Automation ### Home Automation
- **Neolink** - Reolink camera bridge for Frigate/Home Assistant integration - **Neolink** - Reolink camera bridge for Frigate/Home Assistant integration
### Discord Bot (OpenCode) ### Discord Bots
- **Service**: Discord Agent Bot - **RedBot** - Discord bot with custom cogs (internal_net)
- **Role**: AI-powered Discord bot using Ollama LLM
- **Container**: `discord-agent`
- **Network**: `internal_net`, `db_net`
- **Configuration**: `/docker/discord-agent/config/agent-config.yaml`
- **Data**: `/docker/discord-agent/data/`
- **LLM**: Ollama (ministral-3:8b) at `http://192.168.0.31:11434`
- **Features**: Discord commands, service integrations, AI chat capabilities
- **Database**: MySQL for conversation persistence
- **Cogs**: Modular architecture with base_cog and integration_cog
### RedBot ### Network Tools
- **Service**: RedBot Discord Bot - **iperf3-server** - Network performance testing (port 5201)
- **Role**: Alternative Discord bot with custom cogs
- **Container**: `redbot`
- **Network**: `web_net`
### Other Tools ## Independent Stacks (separate compose files)
- **Newt** - AI service integration
These services are deployed independently and are not part of the main 5-stack split:
| Service | Directory | Role |
|---------|-----------|------|
| **Discord Agent Bot** | `discord-agent/` | AI-powered Discord bot using Ollama LLM |
| **Foundry Watcher** | `foundry-watcher/` | Foundry VTT player monitoring |
| **GrampsWeb Jamie** | `gramps-jamie/` | Genealogy UI (port 5511) |
| **GrampsWeb Helen** | `gramps-helen/` | Genealogy UI (port 5512) |
| **Kasm** | `kasm/` | Browser isolation workspace |
| **LiteLLM** | `litellm/` | AI gateway (port 4000) |
| **MBI Poller** | `mbi-poller/` | MBI data polling service |
## Network Architecture ## Network Architecture
@@ -146,17 +140,18 @@ This document provides a comprehensive overview of the Docker infrastructure man
- **web_net** - Web-accessible services - **web_net** - Web-accessible services
- **internal_net** - Internal service communication - **internal_net** - Internal service communication
Networks are defined in `docker-compose.infra.yml` and referenced as `external: true` by all other stacks.
### Storage Structure ### Storage Structure
``` ```
/docker/ /docker/
├── Arrs/ (Media stack: Prowlarr, Radarr, Sonarr, Lidarr, Bazarr, Jellyfin, Jellyseerr) ├── Arrs/ (Media stack: Prowlarr, Radarr, Sonarr, Lidarr, Bazarr, Jellyfin, Jellyseerr)
├── immich/ (Photo management) ├── immich/ (Photo management)
├── paperless/ (Document management) ├── paperless/ (Document management)
├── litellm/ (AI gateway) ├── discord-agent/ (Independent — Discord bot with Ollama)
├── discord-agent/ (Discord bot with Ollama LLM integration)
├── gitea/ (Git service) ├── gitea/ (Git service)
├── gramps-jamie/ (Genealogy) ├── gramps-jamie/ (Independent — Genealogy)
├── gramps-helen/ (Genealogy) ├── gramps-helen/ (Independent — Genealogy)
├── npm/ (Nginx Proxy Manager) ├── npm/ (Nginx Proxy Manager)
├── qBittorrent/ (Download client) ├── qBittorrent/ (Download client)
├── slskd/ (Soulseek client) ├── slskd/ (Soulseek client)
@@ -168,19 +163,43 @@ This document provides a comprehensive overview of the Docker infrastructure man
├── retrom/ (ROM library management) ├── retrom/ (ROM library management)
├── wud/ (Docker image management) ├── wud/ (Docker image management)
├── ntopng/ (Network traffic monitoring) ├── ntopng/ (Network traffic monitoring)
├── kasm/ (Browser workspace) ├── kasm/ (Independent — Browser workspace)
├── litellm/ (Independent — AI gateway)
├── neolink/ (Reolink camera bridge) ├── neolink/ (Reolink camera bridge)
├── linkwarden/ (Bookmark manager)
├── surmai/ (Flight tracking) ├── surmai/ (Flight tracking)
├── tandoor/ (Recipe management) ├── tandoor/ (Recipe management)
├── foundry-watcher/ (Foundry VTT monitoring) ├── foundry-watcher/ (Independent — Foundry VTT)
├── rustdesk/ (Remote desktop)
├── redbot/ (Discord bot)
├── stirling/ (PDF tools)
└── Various other service configs └── Various other service configs
``` ```
## Deployment
### Deploy all main stacks
```bash
for f in docker-compose.infra.yml docker-compose.media.yml docker-compose.documents.yml docker-compose.photo-roms.yml docker-compose.utils.yml; do
docker compose -f "$f" up -d
done
```
### Deploy a specific stack
```bash
docker compose -f docker-compose.media.yml up -d
```
### Stop a specific stack
```bash
docker compose -f docker-compose.media.yml down
```
## Key Features & Configuration ## Key Features & Configuration
### Security ### Security
- Container security with `no-new-privileges:true` - Container security with `no-new-privileges:true`
- Network segmentation (databases internal-only) - Network segmentation (databases internal-only via `db_net`)
- Reverse proxy with SSL termination - Reverse proxy with SSL termination
### Performance ### Performance
@@ -189,7 +208,7 @@ This document provides a comprehensive overview of the Docker infrastructure man
- Resource limits (Portainer: 512MB RAM) - Resource limits (Portainer: 512MB RAM)
### Data Management ### Data Management
- Comprehensive backup script included - Comprehensive backup script included (`backup.sh`)
- Separate volumes for critical data - Separate volumes for critical data
- NAS storage integration for media files - NAS storage integration for media files
@@ -197,25 +216,30 @@ This document provides a comprehensive overview of the Docker infrastructure man
- System configured for Pacific/Auckland timezone - System configured for Pacific/Auckland timezone
- PUID/PGID for proper file permissions - PUID/PGID for proper file permissions
- Extensive environment variable configuration - Extensive environment variable configuration
- Shared `.env` file across all stacks
## Service Dependencies ## Service Dependencies
### Database Services ### Database Services
- MariaDB instances for media stack, tracking, and document services - MariaDB: npm, paperless, speedtest-tracker
- PostgreSQL for AI services, photo management, and finance - PostgreSQL: immich, retrom, tandoor, linkwarden
- Redis for caching and message brokering - MySQL: gitea
- Redis/Valkey: paperless-broker, immich-redis
- Meilisearch: linkwarden
### Network Dependencies ### Network Dependencies
- `infra.yml` must be deployed first (creates shared networks)
- All web services route through Nginx Proxy Manager - All web services route through Nginx Proxy Manager
- Internal services communicate via internal_net - Internal services communicate via `internal_net`
- Media services isolated on media_net - Media services isolated on `media_net`
- Database services on internal-only db_net - Database services on internal-only `db_net`
## Maintenance Agents ## Maintenance
### Automated Tasks ### Automated Tasks
- **Backup Script** - Regular data backups - **Backup Script** (`backup.sh`) - Regular data backups
- **Speedtest Tracker** - Automated network testing - **Speedtest Tracker** - Automated network testing
- **WUD** - Automatic Docker image update monitoring
### Manual Tasks ### Manual Tasks
- Service monitoring via Portainer - Service monitoring via Portainer
@@ -232,5 +256,6 @@ This document provides a comprehensive overview of the Docker infrastructure man
### Troubleshooting ### Troubleshooting
- Container logs accessible via Portainer - Container logs accessible via Portainer
- Network diagnostics via iperf3-server - Network diagnostics via iperf3-server
- Per-stack logs: `docker compose -f docker-compose.<stack>.yml logs -f <service>`
This Docker infrastructure represents a comprehensive self-hosted ecosystem covering media management, document processing, AI services, development tools, and personal productivity applications, all integrated through a reverse proxy and organized with proper network segmentation. This Docker infrastructure represents a comprehensive self-hosted ecosystem covering media management, document processing, AI services, development tools, and personal productivity applications, all integrated through a reverse proxy and organized into independent compose stacks with proper network segmentation.

371
README.md
View File

@@ -2,101 +2,62 @@
## Overview ## Overview
This infrastructure manages a comprehensive self-hosted environment including media management (Jellyfin, *arr stack), document management (Paperless-ngx), AI services (Open WebUI, LiteLLM), photo management (Immich), genealogy tools (GrampsWeb), and various utilities. This infrastructure manages a comprehensive self-hosted environment including media management (Jellyfin, *arr stack), document management (Paperless-ngx), AI services (Open WebUI), photo management (Immich), and various utilities.
The deployment is split into **5 independent compose stacks** sharing a common `.env` file and Docker networks.
## Compose Stacks
| Stack | File | Services |
|-------|------|----------|
| **Infrastructure** | `docker-compose.infra.yml` | portainer, ntopng, wud, homepage, dockerproxy, newt, npm, npm-db |
| **Media** | `docker-compose.media.yml` | prowlarr, flaresolverr, qbittorrent, radarr, sonarr, lidarr, bazarr, seerr, jellyfin, slskd, metube, maloja, multi-scrobbler |
| **Documents** | `docker-compose.documents.yml` | onlyoffice, paperless-ngx (db, broker, tika, gotenberg, webserver, ai), stirling-pdf, open-webui |
| **Photo & ROM Library** | `docker-compose.photo-roms.yml` | immich (server, postgres, ml, redis), syncthing, retrom (db, adminer, service, jaeger) |
| **Utilities** | `docker-compose.utils.yml` | gitea (server + db), tandoor (db + web), speedtest-tracker (app + db), rustdesk (hbbs + hbbr), redbot, iperf3-server, neolink, linkwarden (app + db + meilisearch) |
## Architecture ## Architecture
### Internal Docker Services ### Internal Docker Services
| Service Categories | Service | Role / Component | Web UI Port | | Stack | Service | Role | Port |
|---|---|---|---| |-------|---------|------|------|
| Media & Arr Stack | Jellyfin | Media server with hardware transcoding | 8096 | | Infrastructure | Nginx Proxy Manager | SSL termination & reverse proxy | 80, 443, 81 |
| Media & Arr Stack | Jellyseerr | Media request management | 5055 | | Infrastructure | Portainer | Container management UI | 9443 |
| Media & Arr Stack | Radarr | Movie management | 7878 | | Infrastructure | Homepage | Service dashboard | 7575 |
| Media & Arr Stack | Sonarr | TV show management | 8989 | | Infrastructure | WUD | Docker image update monitoring | 3666 |
| Media & Arr Stack | Lidarr | Music management | 8686 | | Infrastructure | ntopng | Network traffic monitoring | 3939 |
| Media & Arr Stack | Bazarr | Subtitle management | 6767 | | Infrastructure | Docker Socket Proxy | Secure Docker API access | 2375 |
| Media & Arr Stack | Prowlarr | Indexer manager | 9696 | | Infrastructure | Newt | Pangolin tunnel client | - |
| Media & Arr Stack | FlareSolverr | Cloudflare bypass service | 8191 | | Media | Jellyfin | Media server (HW transcoding) | 8096 |
| Media & Arr Stack | qBittorrent | Download client | 7070 | | Media | Jellyseerr (seerr) | Media request management | 5055 |
| Data Management | Paperless | Document management interface | 8100 | | Media | Radarr | Movie management | 7878 |
| Data Management | Paperless-AI | AI-powered document processing | - | | Media | Sonarr | TV show management | 8989 |
| Data Management | Stirling-PDF | PDF manipulation tools | 8090 | | Media | Lidarr | Music management | 8686 |
| Data Management | OnlyOffice | Document collaboration server | 8091 | | Media | Bazarr | Subtitle management | 6767 |
| Local AI | Open WebUI | LLM interface | 3000 | | Media | Prowlarr | Indexer manager | 9696 |
| Local AI | LiteLLM | AI gateway | 4000 | | Media | FlareSolverr | Cloudflare bypass | 8191 |
| Data Management | Immich | Photo management | 2283 | | Media | qBittorrent | Download client | 7070 |
| Data Management | Syncthing | File synchronization | 8384 | | Media | Slskd | Soulseek file sharing | 5030, 5031 |
| Management & Infrastructure | Gitea | Git service | 8418 | | Media | Metube | YouTube downloader | 8081 |
| Data Management | GrampsWeb Jamie | Genealogy UI | 5511 | | Media | Maloja | Music scrobbling | 42010 |
| Data Management | GrampsWeb Helen | Genealogy UI | 5512 | | Media | Multi-Scrobbler | Cross-platform scrobbler | 9078 |
| Data Management | Speedtest Tracker | Network performance | 8180 | | Documents | Paperless-ngx | Document management | 8100 |
| Management & Infrastructure | NPM Admin | NPM admin UI | 81 | | Documents | Paperless-AI | AI document processing | 3040 |
| Data Management | Maloja | Music scrobbling | 42010 | | Documents | Stirling-PDF | PDF manipulation | 8090 |
| Data Management | Multi-Scrobbler | Cross-platform scrobbler | 9078 | | Documents | OnlyOffice | Document collaboration | 8091 |
| Management & Infrastructure | Portainer | Container management UI | 9443 | | Documents | Open WebUI | LLM interface | 3000 |
| Management & Infrastructure | Homepage | Service dashboard | 7575 | | Photo & ROM | Immich | Photo management | 2283 |
| Management & Infrastructure | WUD | Docker image management | 3000 | | Photo & ROM | Syncthing | File synchronization | 8384 |
| Management & Infrastructure | ntopng | Network traffic monitoring | 3939 | | Photo & ROM | Retrom | ROM library management | 5111 |
| Management & Infrastructure | Retrom | ROM library management | 5111 | | Utilities | Gitea | Git service | 8418 |
| Management & Infrastructure | iperf3-server | Network performance testing | 5201 | | Utilities | Tandoor Recipes | Recipe management | 8450 |
| Management & Infrastructure | Foundry Watcher | Foundry VTT player monitoring | 30001 | | Utilities | Speedtest Tracker | Network monitoring | 8180 |
| Discord Bots | Discord Agent Bot | AI-powered Discord bot with Ollama | - | | Utilities | RustDesk | Remote desktop (host mode) | - |
| Discord Bots | RedBot | Alternative Discord bot | - | | Utilities | RedBot | Discord bot | - |
| Utilities | iperf3-server | Network performance test | 5201 |
### Discord Agent Integration | Utilities | Neolink | Reolink camera bridge | 8554 |
| Utilities | Linkwarden | Bookmark manager | 3400 |
### Discord Bot Service
- **Service**: Discord Agent Bot
- **Role**: AI-powered Discord bot using Ollama LLM
- **Container**: `discord-agent`
- **Network**: `internal_net`, `db_net`
- **Web UI**: Discord (no direct web interface)
- **Configuration**: `/docker/discord-agent/config/agent-config.yaml`
- **Data**: `/docker/discord-agent/data/`
### Features
- **AI Integration**: Uses Ollama LLM (ministral-3:8b) at `http://192.168.0.31:11434`
- **Modular Architecture**: Cogs for service integrations
- **Database Support**: MySQL for conversation persistence
- **Caching**: Redis for improved performance (configurable)
- **Security**: Discord role-based permissions
- **Logging**: Configurable logging levels (default: INFO)
- **Rate Limiting**: Built-in rate limiting for API calls
### Available Commands
- `!agent` - Chat with the AI assistant
- `!status` - Check bot status and latency
- `!help` - Show available commands
- Service integration commands (configurable)
### Configuration
- **Main Config**: `config/agent-config.yaml` (YAML-based with env var substitution)
- **Discord Token**: Sourced from `DISCORD_BOT_TOKEN` environment variable
- **Ollama Config**: Model, endpoint, temperature, top_p, top_k parameters
- **Integrations**: Configurable service integrations in YAML
### Environment Variables
```
DISCORD_BOT_TOKEN=your_discord_bot_token_here
OLLAMA_ENDPOINT=http://192.168.0.31:11434
OLLAMA_MODEL=ministral-3:8b
TZ=Pacific/Auckland
```
### Bot Architecture
- **Main Bot**: `discord_agent.py` - Core Discord bot implementation
- **Base Cog**: `cogs/base_cog.py` - Base functionality and commands
- **Integration Cog**: `cogs/integration_cog.py` - Service integrations
- **Config**: YAML-based configuration with environment variable substitution
- **Database**: MySQL with asyncpg driver for conversation history
### Security
- Runs on internal networks only
- Discord role-based access control
- Configurable rate limiting to prevent abuse
- No direct database access from external networks
### Network Segmentation ### Network Segmentation
@@ -105,47 +66,95 @@ TZ=Pacific/Auckland
- **web_net**: Web-accessible services - **web_net**: Web-accessible services
- **internal_net**: Internal service communication - **internal_net**: Internal service communication
Networks are created by `infra.yml` and referenced as external by all other stacks.
## Storage Structure ## Storage Structure
### Local Docker Configs (`/docker/`) ### Local Docker Configs (`/docker/`)
``` ```
/docker/ /docker/
├── Homepage/
├── Arrs/ (Prowlarr, Radarr, Sonarr, Lidarr, Bazarr, Jellyfin, Jellyseerr) ├── Arrs/ (Prowlarr, Radarr, Sonarr, Lidarr, Bazarr, Jellyfin, Jellyseerr)
├── qBittorrent/ ├── Homepage/
├── discord-agent/ (Discord bot with Ollama LLM)
├── paperless/
├── stirling/
├── immich/ ├── immich/
├── syncthing/ ├── paperless/
├── discord-agent/ (Separate stack)
├── gitea/ ├── gitea/
├── gramps-jamie/ ├── gramps-jamie/ (Separate stack)
├── gramps-helen/ ├── gramps-helen/ (Separate stack)
├── speedtest-tracker/ ├── kasm/ (Separate stack)
├── rustdesk/ ├── foundry-watcher/ (Separate stack)
├── redbot/ ├── litellm/ (Separate stack)
├── linkwarden/
├── maloja/ ├── maloja/
├── scrobble/ ├── neolink/
├── litellm/ ├── npm/
├── retrom/
├── wud/
├── ntopng/ ├── ntopng/
├── qBittorrent/
├── redbot/
├── retrom/
├── rustdesk/
├── scrobble/ (Multi-scrobbler)
├── slskd/ ├── slskd/
── npm/ ── speedtest-tracker/
├── stirling/
├── surmai/
├── syncthing/
├── tandoor/
├── wud/
└── .env (shared environment variables)
``` ```
### NAS Storage (`/mnt/Nas-Storage/data/`) ### NAS Storage (`/mnt/nas-storage/data/`)
``` ```
/mnt/Nas-Storage/data/ /mnt/nas-storage/data/
├── media/ ├── media/
│ ├── movies/ │ ├── movies/
│ ├── tv/ │ ├── tv/
│ ├── music/ │ ├── music/
│ └── images/ │ └── romms/
└── torrents/ └── torrents/
├── metube/
└── soulsync/ └── soulsync/
``` ```
## Deployment
### First-time deploy (or after network cleanup)
```bash
# Deploy infrastructure first (creates shared networks)
docker compose -f docker-compose.infra.yml up -d
# Then deploy remaining stacks in any order
docker compose -f docker-compose.media.yml up -d
docker compose -f docker-compose.documents.yml up -d
docker compose -f docker-compose.photo-roms.yml up -d
docker compose -f docker-compose.utils.yml up -d
```
### Deploy all stacks
```bash
for f in docker-compose.*.yml; do
if [ "$f" != "docker-compose.full.yaml.bak" ]; then
docker compose -f "$f" up -d
fi
done
```
### Stop/start individual stacks
```bash
docker compose -f docker-compose.media.yml down
docker compose -f docker-compose.media.yml up -d
```
### View logs
```bash
docker compose -f docker-compose.media.yml logs -f jellyfin
```
## Prerequisites ## Prerequisites
### Required Environment Variables (.env file) ### Required Environment Variables (.env file)
@@ -159,7 +168,6 @@ TZ=Pacific/Auckland
# URLs # URLs
JELLYFIN_URL=https://your-jellyfin-domain.com JELLYFIN_URL=https://your-jellyfin-domain.com
PAPERLESS_URL=https://your-paperless-domain.com PAPERLESS_URL=https://your-paperless-domain.com
WYGIWYH_URL=https://your-wygiwyh-domain.com
HOMEPAGE_ALLOWED_HOSTS=your-homepage-domain.com HOMEPAGE_ALLOWED_HOSTS=your-homepage-domain.com
# Nginx Proxy Manager # Nginx Proxy Manager
@@ -175,10 +183,6 @@ PAPERLESS_SECRET_KEY=your_secret_key
# Immich # Immich
IMMICH_POSTGRES_PASSWORD=your_secure_password IMMICH_POSTGRES_PASSWORD=your_secure_password
# LiteLLM
GROQ_API_KEY=your_groq_api_key
LITELLM_MASTER_KEY=your_master_key
# Slskd # Slskd
SLSKD_USERNAME=your_username SLSKD_USERNAME=your_username
SLSKD_PASSWORD=your_secure_password SLSKD_PASSWORD=your_secure_password
@@ -189,15 +193,35 @@ SPEEDTEST_DB_USER=speedtest
SPEEDTEST_DB_PASSWORD=your_secure_password SPEEDTEST_DB_PASSWORD=your_secure_password
SPEEDTEST_APP_KEY=base64:your_generated_key SPEEDTEST_APP_KEY=base64:your_generated_key
# WYGIWYH
WYGIWYH_DB_DATABASE=wygiwyh
WYGIWYH_DB_USER=wygiwyh
WYGIWYH_DB_PASSWORD=your_secure_password
WYGIWYH_SECRET_KEY=your_secret_key
WYGIWYH_ALLOWED_HOSTS=localhost,127.0.0.1,your-domain.com
# RedBot # RedBot
REDBOT_TOKEN=your_discord_bot_token REDBOT_TOKEN=your_discord_bot_token
# Tandoor
TANDOOR_SECRET_KEY=your_secret_key
TANDOOR_POSTGRES_DB=tandoor
TANDOOR_POSTGRES_USER=tandoor
TANDOOR_POSTGRES_PASSWORD=your_secure_password
# Linkwarden
LINKWARDEN_DB_PASSWORD=your_secure_password
NEXTAUTH_SECRET=your_secret
NEXTAUTH_URL=https://your-linkwarden-domain.com
# WUD
WUD_REGISTRY_HUB_0_LOGIN=your_dockerhub_username
WUD_REGISTRY_HUB_0_TOKEN=your_dockerhub_token
# OnlyOffice
OO_JWT_SECRET=your_secret
# Maloja
MALOJA_FORCE_PASSWORD=your_password
MALOJA_URL=http://maloja:42010
MALOJA_API_KEY=your_key
# Jellyfin
JELLYFIN_APIKEY_MS=your_api_key_for_multiscrobbler
JELLYFIN_USER=your_username
``` ```
### System Requirements ### System Requirements
@@ -209,27 +233,15 @@ REDBOT_TOKEN=your_discord_bot_token
## Installation ## Installation
1. Clone/Download this repository 1. Clone this repository
2. Create required directories 2. Create `.env` from `.env.example` and fill in values
3. Run infrastructure:
```bash ```bash
# See directory_structure.sh for automated setup docker compose -f docker-compose.infra.yml up -d
chmod +x directory_structure.sh
./directory_structure.sh
``` ```
3. Create .env file 4. Deploy desired stacks:
```bash ```bash
cp .env.example .env docker compose -f docker-compose.media.yml up -d
# Edit .env with your values
nano .env
```
4. Set correct permissions
```bash
sudo chown -R $PUID:$PGID /docker
sudo chown -R $PUID:$PGID /mnt/Nas-Storage/data
```
5. Start services
```bash
docker compose up -d
``` ```
## Maintenance ## Maintenance
@@ -237,34 +249,26 @@ REDBOT_TOKEN=your_discord_bot_token
### Backup Strategy ### Backup Strategy
**Critical Data to Backup:** **Critical Data to Backup:**
- `/docker/` - All service configurations - `/docker/` — all service configurations
- Database volumes (see docker-compose.yaml) - Named volumes: `portainer_data`, `docker_dbdata`, `open-webui`
- `.env` file (store securely, contains secrets) - `.env` file (contains secrets)
**Optional (can be regenerated):** **Optional (can be regenerated):**
- Media files on NAS - Media files on NAS
### Updates ### Updates
To manually update containers: ```bash
for f in docker-compose.infra.yml docker-compose.media.yml docker-compose.documents.yml docker-compose.photo-roms.yml docker-compose.utils.yml; do
``` docker compose -f "$f" pull
docker compose pull docker compose -f "$f" up -d
done
docker compose up -d
```
### Logs
View logs for any service:
```
docker compose logs -f [service_name]
``` ```
### Resource Limits ### Resource Limits
- Portainer: 512MB RAM limit - Portainer: 512MB RAM limit
- Log rotation: 10MB max, 3 files - Log rotation: 10MB max, 3 files (on services with logging config)
## Hardware Acceleration ## Hardware Acceleration
@@ -273,71 +277,68 @@ Jellyfin is configured for Intel GPU transcoding:
- Group: `104` (render group) - Group: `104` (render group)
Verify GPU access: Verify GPU access:
``` ```bash
ls -l /dev/dri/renderD128 ls -l /dev/dri/renderD128
``` ```
## Security Considerations ## Security Considerations
1. Secrets Management: Store `.env` securely, never commit to version control 1. Secrets Management: Store `.env` securely, never commit to version control
2. Network Segmentation: Database network is internal-only 2. Network Segmentation: Database network is internal-only (`db_net`)
3. Container Security: `no-new-privileges:true` on supported services 3. Container Security: `no-new-privileges:true` on supported services
4. Reverse Proxy: Use NPM for SSL termination and authentication 4. Reverse Proxy: Use NPM for SSL termination and authentication
5. Updates: Regularly update containers with `docker compose pull && docker compose up -d` 5. Updates: Regularly update containers as shown above
## Troubleshooting ## Troubleshooting
### Service won't start ### Service won't start
``` ```bash
docker compose logs [service_name] docker compose -f docker-compose.media.yml logs service_name
docker compose restart [service_name] docker compose -f docker-compose.media.yml restart service_name
``` ```
### Database connection issues ### Database connection issues
``` ```bash
# Check database is healthy docker compose -f docker-compose.documents.yml ps
docker compose ps docker compose -f docker-compose.documents.yml exec paperless-webserver ping paperless-db
# Verify network connectivity
docker compose exec [service] ping [db_service]
``` ```
### Permission errors ### Permission errors
``` ```bash
# Verify ownership ls -la /docker/service_name/
ls -la /docker/[service]/ sudo chown -R $PUID:$PGID /docker/service_name/
# Fix if needed
sudo chown -R $PUID:$PGID /docker/[service]/
``` ```
### Storage full ### Storage full
``` ```bash
# Check Docker disk usage
docker system df docker system df
# Clean up unused resources
docker system prune -a docker system prune -a
``` ```
## Contributing Services ## Contributing Services
To add new services: To add new services:
1. Add service definition to appropriate section 1. Add service definition to the appropriate compose file
2. Assign to correct network(s) 2. Assign to correct network(s)
3. Add volume mounts under `/docker/[service]/` 3. Add volume mounts under `/docker/[service]/`
4. Update this README with service description 4. Update this README with service description
5. Add required environment variables to `.env.example` 5. Add required environment variables to `.env.example`
## Independent Stacks
The following services have their own compose files (not part of the main split):
- **discord-agent/** — Discord Agent Bot
- **foundry-watcher/** — Foundry VTT monitoring
- **gramps-jamie/** — Genealogy (Jamie)
- **gramps-helen/** — Genealogy (Helen)
- **kasm/** — Browser workspace
- **litellm/** — AI gateway
- **mbi-poller/** — MBI poller service
## License ## License
This is a personal infrastructure setup. Adapt as needed for your use case. This is a personal infrastructure setup. Adapt as needed for your use case.
## Support
For issues with specific services, consult their official documentation:
- Jellyfin: https://jellyfin.org/docs/
- Paperless-ngx: https://docs.paperless-ngx.com/
- Immich: https://immich.app/docs/
- And so on...
--- ---
**Last Updated**: January 2026 **Last Updated**: May 2026

View File

@@ -4,274 +4,187 @@ This guide walks you through restoring your Docker infrastructure from a backup.
## Architecture Alignment ## Architecture Alignment
The architecture inventory is documented in README.md as two tables under Architecture: The infrastructure is split into 5 compose files (stacks) sharing a common `.env`:
- Internal Docker Services (Service | Category | Web UI Port)
- External Non-Docker Services (Service | Category | IP | Web UI Port)
If you are restoring, follow the standard restoration steps below, and refer to README.md for the exact service inventory and ports as implemented in your environment. | Stack | File | Purpose |
|-------|------|---------|
| Infrastructure | `docker-compose.infra.yml` | Portainer, NPM, homepage, WUD, ntopng, newt, dockerproxy |
| Media | `docker-compose.media.yml` | arr stack, Jellyfin, qBittorrent, slskd, metube, scrobbling |
| Documents | `docker-compose.documents.yml` | Paperless-ngx, AI, OnlyOffice, Stirling-PDF, Open WebUI |
| Photo & ROM | `docker-compose.photo-roms.yml` | Immich, Syncthing, Retrom |
| Utilities | `docker-compose.utils.yml` | Gitea, Tandoor, Speedtest, RustDesk, RedBot, Linkwarden, Neolink, iperf3 |
Refer to README.md for the exact service inventory and ports.
## Prerequisites ## Prerequisites
- Fresh system with Docker and Docker Compose installed - Fresh system with Docker and Docker Compose V2 installed
- Backup archive (`docker-backup-YYYYMMDD_HHMMSS.tar.gz`) - Backup archive containing `/docker/` configs
- Access to NAS storage (if applicable) - Access to NAS storage (if applicable)
- Root or sudo access - Root or sudo access
## Discord Agent Service ## Step 1: Restore Directory Structure
### Step 1: Create Discord Agent Directory
```bash
mkdir -p /docker/discord-agent/config /docker/discord-agent/data/logs /docker/discord-agent/data/database /docker/discord-agent/data/cache /docker/discord-agent/cogs /docker/discord-agent/scripts
```
### Step 2: Copy Configuration Files
```bash
# Copy agent configuration
cp agent-config.yaml /docker/discord-agent/config/
cp permissions.json /docker/discord-agent/config/
# Copy scripts
cp startup.sh /docker/discord-agent/scripts/
cp health_check.sh /docker/discord-agent/scripts/
```
### Step 3: Copy Python Files
```bash
cp discord_agent.py /docker/discord-agent/
cp base_cog.py /docker/discord-agent/cogs/
cp integration_cog.py /docker/discord-agent/cogs/
```
### Step 4: Copy Requirements
```bash
cp requirements.txt /docker/discord-agent/
cp Dockerfile /docker/discord-agent/
```
### Step 5: Update Environment Variables
Add these to your `.env` file:
```bash
# Discord Agent
DISCORD_BOT_TOKEN=your_discord_bot_token_here
OLLAMA_ENDPOINT=http://192.168.0.31:11434
OLLAMA_MODEL=ministral-3:8b
TZ=Pacific/Auckland
```
### Step 6: Update Configuration
Edit `/docker/discord-agent/config/agent-config.yaml` with your specific settings:
```yaml
discord:
token: ${DISCORD_BOT_TOKEN}
prefix: "!"
status: "AI Assistant | !help"
ollama:
endpoint: "${OLLAMA_ENDPOINT:http://192.168.0.31:11434}"
model: "${OLLAMA_MODEL:ministral-3:8b}"
parameters:
temperature: 0.7
top_p: 0.9
top_k: 40
timeout: 60
```
### Step 7: Build and Start Service
```bash
# Build the Discord agent image
docker compose build discord-agent
# Start the service
docker compose up -d discord-agent
# Verify the service is running
docker compose logs discord-agent
```
### Step 8: Verify Integration
```bash
# Check Discord bot connection
docker exec discord-agent python3 -c "import discord; print('Discord library available')"
# Check Ollama connection
curl http://192.168.0.31:11434/api/tags
# Check MySQL database
docker compose exec agent-db mysql -u agent -pagent -e "SHOW DATABASES;"
```
### Step 9: Test Bot Functionality
- The bot should appear in your Discord server
- Test with `!help` command to verify functionality
- Test with `!agent <message>` to verify Ollama integration
- Test with `!status` to check bot status
### Troubleshooting
- If bot doesn't start, check logs: `docker compose logs discord-agent`
- Verify DISCORD_BOT_TOKEN is set correctly in `.env` file
- Ensure Ollama is running and accessible at the configured endpoint
- Verify internal_net and db_net networks are available
- Check that MySQL database agent-db is running and healthy
## Step 2: Restore Directory Structure
```bash ```bash
# Copy the directory structure script # Create the root docker directory
cp directory_structure.sh /opt/docker-compose/ mkdir -p /docker
cd /opt/docker-compose/ cd /docker
# Make it executable and run # Copy configuration files from backup
chmod +x directory_structure.sh
./directory_structure.sh
```
## Step 3: Restore Docker Compose Configuration
```bash
# Copy main configuration files
cp /path/to/backup/docker-compose.yaml .
cp /path/to/backup/.env . cp /path/to/backup/.env .
cp /path/to/backup/.gitignore . cp /path/to/backup/.gitignore .
cp /path/to/backup/README.md . cp /path/to/backup/README.md .
cp /path/to/backup/AGENTS.md .
cp /path/to/backup/RESTORE.md .
cp /path/to/backup/backup.sh .
# Copy all compose files
cp /path/to/backup/docker-compose.infra.yml .
cp /path/to/backup/docker-compose.media.yml .
cp /path/to/backup/docker-compose.documents.yml .
cp /path/to/backup/docker-compose.photo-roms.yml .
cp /path/to/backup/docker-compose.utils.yml .
# Copy the original full backup (for reference)
cp /path/to/backup/docker-compose.full.yaml.bak .
# IMPORTANT: Edit .env file with new system-specific values # IMPORTANT: Edit .env file with new system-specific values
nano .env nano .env
# Verify the configuration
docker compose config
``` ```
## Step 4: Restore Service Configurations ## Step 2: Restore Service Configuration Directories
```bash ```bash
# Copy service configurations back to /docker # Copy service configurations back to /docker
rsync -av /path/to/backup/docker/ /docker/ rsync -av /path/to/backup/docker/ /docker/
# Create required subdirectories that may be missing
mkdir -p /docker/Arrs/{Prowlarr,Radarr,Sonarr,Lidarr,Bazarr,Jellyfin,Seerr}/config
mkdir -p /docker/{immich,qBittorrent,paperless,stirling,syncthing,gitea}
mkdir -p /docker/{speedtest-tracker,rustdesk,redbot,maloja,scrobble}
mkdir -p /docker/{retrom/config,retrom/data}
mkdir -p /docker/{wud,ntopng,slskd,npm/data,npm/letsencrypt,npm/mysql}
mkdir -p /docker/{Homepage/config,neolink,tandoor,linkwarden}
# Set correct permissions # Set correct permissions
PUID=$(id -u) PUID=$(id -u)
PGID=$(id -g) PGID=$(id -g)
sudo chown -R $PUID:$PGID /docker sudo chown -R $PUID:$PGID /docker
``` ```
## Step 5: Restore Docker Volumes ## Step 3: Restore Docker Volumes
For each volume backup in `/path/to/backup/volumes/`: For each volume backup:
```bash ```bash
# Create the volume if it doesn't exist # Create the volume if it doesn't exist
docker volume create VOLUME_NAME
# Restore the volume data
docker run --rm \
-v VOLUME_NAME:/volume \
-v /path/to/backup/volumes:/backup \
alpine \
tar xzf /backup/VOLUME_NAME.tar.gz -C /volume
```
Example for specific volumes:
```bash
# Restore Portainer data
docker volume create portainer_data docker volume create portainer_data
docker run --rm \
-v portainer_data:/volume \
-v /path/to/backup/volumes:/backup \
alpine \
tar xzf /backup/portainer_data.tar.gz -C /volume
# Restore Open WebUI data
docker volume create open-webui docker volume create open-webui
docker volume create docker_dbdata
docker volume create docker_aidata
docker volume create docker_onlyoffice
docker volume create docker_redisdata
# Restore volume data
for volume in portainer_data open-webui docker_dbdata docker_aidata docker_onlyoffice docker_redisdata; do
if [ -f "/path/to/backup/volumes/${volume}.tar.gz" ]; then
docker run --rm \ docker run --rm \
-v open-webui:/volume \ -v ${volume}:/volume \
-v /path/to/backup/volumes:/backup \ -v /path/to/backup/volumes:/backup \
alpine \ alpine \
tar xzf /backup/open-webui.tar.gz -C /volume tar xzf /backup/${volume}.tar.gz -C /volume
fi
# Repeat for other volumes... done
``` ```
## Step 6: Start Database Services First ## Step 4: Start Infrastructure First
```bash ```bash
# Start only database services # Start infrastructure (creates shared networks: media_net, db_net, web_net, internal_net)
docker compose up -d paperless-db immich-postgres litellm-postgres gitea-db speedtest-db npm-db docker compose -f docker-compose.infra.yml up -d
# Verify networks were created
docker network ls | grep -E "media_net|db_net|web_net|internal_net"
```
## Step 5: Start Database Services
```bash
# Start database-dependent stacks
docker compose -f docker-compose.documents.yml up -d paperless-db paperless-broker
docker compose -f docker-compose.photo-roms.yml up -d immich-postgres immich-redis retrom-db
docker compose -f docker-compose.utils.yml up -d gitea-db speedtest-db tandoor_db linkwarden-db meilisearch
# Wait for databases to be healthy # Wait for databases to be healthy
docker compose ps docker compose -f docker-compose.documents.yml ps
docker compose -f docker-compose.utils.yml ps
# Check logs for any errors
docker compose logs -f paperless-db
# Press Ctrl+C to exit logs
``` ```
## Step 7: Restore Database Dumps ## Step 6: Restore Database Dumps (if available)
### Paperless MariaDB ### Paperless MariaDB
``` ```bash
# Copy SQL file into container
docker cp /path/to/backup/database-dumps/paperless.sql paperless-db:/tmp/
# Import the database
docker exec -i paperless-db mysql -u root -p"${PAPERLESS_DB_ROOT_PASSWORD}" paperless < /path/to/backup/database-dumps/paperless.sql docker exec -i paperless-db mysql -u root -p"${PAPERLESS_DB_ROOT_PASSWORD}" paperless < /path/to/backup/database-dumps/paperless.sql
``` ```
### Immich PostgreSQL ### Immich PostgreSQL
``` ```bash
docker exec -i immich_postgres psql -U postgres immich < /path/to/backup/database-dumps/immich.sql docker exec -i immich_postgres psql -U postgres immich < /path/to/backup/database-dumps/immich.sql
``` ```
### LiteLLM PostgreSQL
```
docker exec -i litellm-postgres psql -U litellm litellm_db < /path/to/backup/database-dumps/litellm.sql
```
### Gitea MySQL ### Gitea MySQL
``` ```bash
docker exec -i gitea-db mysql -u root -pgitea gitea < /path/to/backup/database-dumps/gitea.sql docker exec -i gitea-db mysql -u root -pgitea gitea < /path/to/backup/database-dumps/gitea.sql
``` ```
### Speedtest Tracker MariaDB ### Speedtest Tracker MariaDB
``` ```bash
docker exec -i speedtest-db mysql -u root -p"${SPEEDTEST_DB_PASSWORD}" speedtest < /path/to/backup/database-dumps/speedtest.sql docker exec -i speedtest-db mysql -u root -p"${SPEEDTEST_DB_PASSWORD}" speedtest < /path/to/backup/database-dumps/speedtest.sql
``` ```
## Step 8: Mount NAS Storage (if applicable) ### Tandoor PostgreSQL
```bash
docker exec -i tandoor_DB psql -U "${TANDOOR_POSTGRES_USER}" "${TANDOOR_POSTGRES_DB}" < /path/to/backup/database-dumps/tandoor.sql
```
## Step 7: Mount NAS Storage (if applicable)
```bash ```bash
# Create mount point # Create mount point
sudo mkdir -p /mnt/Nas-Storage sudo mkdir -p /mnt/nas-storage
# Add to /etc/fstab for permanent mounting # Add to /etc/fstab for permanent mounting
# Example for NFS: # Example for NFS:
# nas-server:/volume1/data /mnt/Nas-Storage nfs defaults 0 0 # nas-server:/volume1/data /mnt/nas-storage nfs defaults 0 0
# Example for CIFS/SMB:
# //nas-server/data /mnt/Nas-Storage cifs credentials=/root/.smbcredentials,uid=1000,gid=1000 0 0
# Mount immediately # Mount immediately
sudo mount -a sudo mount -a
# Verify mount # Verify mount
df -h /mnt/Nas-Storage df -h /mnt/nas-storage
``` ```
## Step 9: Start All Services ## Step 8: Start All Services
```bash ```bash
# Start all services # Deploy all stacks
docker compose up -d for f in docker-compose.infra.yml docker-compose.media.yml docker-compose.documents.yml docker-compose.photo-roms.yml docker-compose.utils.yml; do
docker compose -f "$f" up -d
done
# Watch the startup process # Watch the startup process for a specific stack
docker compose logs -f docker compose -f docker-compose.media.yml logs -f
# Check service health # Check service health across all stacks
docker compose ps for f in docker-compose.*.yml; do
if [ "$f" != "docker-compose.full.yaml.bak" ]; then
echo "=== $f ==="
docker compose -f "$f" ps
fi
done
``` ```
## Step 10: Verify Services ## Step 9: Verify Services
Go through each service and verify it's working correctly:
### Check Web Interfaces ### Check Web Interfaces
- Homepage: http://your-server:7575 - Homepage: http://your-server:7575
@@ -279,9 +192,11 @@ Go through each service and verify it's working correctly:
- Jellyfin: http://your-server:8096 - Jellyfin: http://your-server:8096
- Paperless: http://your-server:8100 - Paperless: http://your-server:8100
- Immich: http://your-server:2283 - Immich: http://your-server:2283
- Gitea: http://your-server:8418
- Speedtest: http://your-server:8180
### Verify Databases ### Verify Databases
``` ```bash
# Paperless # Paperless
docker exec paperless-db mysql -u root -p"${PAPERLESS_DB_ROOT_PASSWORD}" -e "SELECT COUNT(*) FROM paperless.documents_document;" docker exec paperless-db mysql -u root -p"${PAPERLESS_DB_ROOT_PASSWORD}" -e "SELECT COUNT(*) FROM paperless.documents_document;"
@@ -289,9 +204,35 @@ docker exec paperless-db mysql -u root -p"${PAPERLESS_DB_ROOT_PASSWORD}" -e "SEL
docker exec immich_postgres psql -U postgres -d immich -c "SELECT COUNT(*) FROM assets;" docker exec immich_postgres psql -U postgres -d immich -c "SELECT COUNT(*) FROM assets;"
``` ```
... (rest of file continues) ## Step 10: Restore Independent Stacks (if applicable)
These services have their own compose files and are restored separately:
```bash
# Discord Agent Bot
cd /docker/discord-agent
docker compose up -d
# LiteLLM
cd /docker/litellm
docker compose up -d
# Gramps genealogy
cd /docker/gramps-jamie
docker compose up -d
cd /docker/gramps-helen
docker compose up -d
# Other independent stacks
cd /docker/kasm && docker compose up -d
cd /docker/foundry-watcher && docker compose up -d
```
## Architecture Alignment ## Architecture Alignment
- This section connects to the Architecture two-table layout described in README.md. - This section connects to the Architecture table described in README.md.
- Each compose file corresponds to a functional domain in the architecture.
- Networks are created by `infra.yml` and shared across all other stacks.
**Last Updated**: December 2025 ---
**Last Updated**: May 2026

View File

@@ -0,0 +1,210 @@
# =============================================================================
# DOCUMENTS STACK - Document management, PDF tools, and AI services
# =============================================================================
# DEPLOYMENT INSTRUCTIONS
# =============================================================================
# This is one of multiple compose files in the /docker/ directory.
#
# Deploy ALL stacks (from /docker/ directory):
# Get-ChildItem docker-compose.*.yml | ForEach-Object { docker compose -f $_ up -d }
#
# Deploy this stack only:
# docker compose -f docker-compose.documents.yml up -d
#
# Stop this stack:
# docker compose -f docker-compose.documents.yml down
#
# View logs for this stack:
# docker compose -f docker-compose.documents.yml logs -f
#
# IMPORTANT: Requires infra stack to be deployed first (shared networks).
# =============================================================================
name: docker-documents
# Common configurations for re-use
x-logging: &default-logging
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
x-security: &default-security
security_opt:
- no-new-privileges:true
services:
onlyoffice:
image: onlyoffice/documentserver:latest
container_name: onlyoffice-docs
restart: always
ports:
- "8091:80"
environment:
- JWT_ENABLED=true
- JWT_SECRET=${OO_JWT_SECRET}
- JWT_HEADER=Authorization
- ALLOW_PRIVATE_IP_ADDRESS=true
- USE_UNAUTHORIZED_STORAGE=true
volumes:
- docker_onlyoffice:/var/lib/onlyoffice
- docker_onlyoffice:/var/www/onlyoffice/Data
- docker_onlyoffice:/var/log/onlyoffice
paperless-db:
image: mariadb:11
container_name: paperless-db
restart: unless-stopped
networks:
- db_net
environment:
- MARIADB_ROOT_PASSWORD=${PAPERLESS_DB_ROOT_PASSWORD}
- MARIADB_DATABASE=${PAPERLESS_DB_NAME}
- MARIADB_USER=${PAPERLESS_DB_USER}
- MARIADB_PASSWORD=${PAPERLESS_DB_PASSWORD}
volumes:
- docker_dbdata:/var/lib/mysql
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
interval: 10s
timeout: 5s
retries: 3
logging: *default-logging
paperless-broker:
image: redis:8
container_name: paperless-broker
restart: unless-stopped
networks:
- internal_net
volumes:
- docker_redisdata:/data
logging: *default-logging
paperless-tika:
image: apache/tika:latest
container_name: paperless-tika
restart: unless-stopped
networks:
- internal_net
logging: *default-logging
paperless-gotenberg:
image: gotenberg/gotenberg:8.20
container_name: paperless-gotenberg
restart: unless-stopped
networks:
- internal_net
command: ["gotenberg", "--chromium-disable-javascript=true", "--chromium-allow-list=file:///tmp/.*"]
logging: *default-logging
paperless-webserver:
image: ghcr.io/paperless-ngx/paperless-ngx:latest
container_name: paperless-webserver
restart: unless-stopped
networks:
- web_net
- db_net
- internal_net
ports:
- "8100:8000"
environment:
- PAPERLESS_DBENGINE=mariadb
- PAPERLESS_DBHOST=paperless-db
- PAPERLESS_DBPASS=${PAPERLESS_DB_PASSWORD}
- PAPERLESS_DBUSER=${PAPERLESS_DB_USER}
- PAPERLESS_DBPORT=3306
- PAPERLESS_REDIS=redis://paperless-broker:6379
- PAPERLESS_TIKA_ENDPOINT=http://paperless-tika:9998
- PAPERLESS_TIKA_GOTENBERG_ENDPOINT=http://paperless-gotenberg:3000
- PAPERLESS_SECRET_KEY=${PAPERLESS_SECRET_KEY}
- PAPERLESS_URL=${PAPERLESS_URL}
- PAPERLESS_TIME_ZONE=${TZ}
- PAPERLESS_OCR_LANGUAGE=eng
volumes:
- /docker/paperless/consume:/usr/src/paperless/consume
- /docker/paperless/data:/usr/src/paperless/data
- /docker/paperless/export:/usr/src/paperless/export
- /docker/paperless/media:/usr/src/paperless/media
depends_on:
paperless-db:
condition: service_healthy
paperless-broker:
condition: service_started
logging: *default-logging
paperless-ai:
image: clusterzx/paperless-ai
container_name: paperless-ai
restart: unless-stopped
networks:
- internal_net
ports:
- 3040:3000
environment:
- PUID=${PUID}
- PGID=${PGID}
- PAPERLESS_USERNAME=jamie
- PAPERLESS_API_URL=http://paperless-webserver:8000/api
- PAPERLESS_API_TOKEN=${PAPERLESS_SECRET_KEY}
- RAG_SERVICE_URL=http://localhost:8000
- RAG_SERVICE_ENABLED=true
volumes:
- docker_aidata:/app/data
depends_on:
- paperless-webserver
logging: *default-logging
stirling-pdf:
image: docker.stirlingpdf.com/stirlingtools/stirling-pdf:latest
container_name: stirling-PDF
restart: unless-stopped
networks:
- web_net
ports:
- "8090:8080"
environment:
- UI_APPNAME=Stirling-PDF
- SHOW_SURVEY=false
- SECURITY_ENABLELOGIN=false
- SYSTEM_MAXFILESIZE=100
- PUID=${PUID}
- PGID=${PGID}
volumes:
- /docker/stirling/config:/configs
- /docker/stirling/data:/usr/share/tessdata
- /docker/stirling/logs:/logs
logging: *default-logging
open-webui:
image: ghcr.io/open-webui/open-webui:main
container_name: open-webui
restart: unless-stopped
networks:
- web_net
- internal_net
ports:
- "3000:8080"
extra_hosts:
- "host.docker.internal:host-gateway"
volumes:
- open-webui:/app/backend/data
logging: *default-logging
networks:
db_net:
name: db_net
external: true
internal_net:
name: internal_net
external: true
web_net:
name: web_net
external: true
volumes:
docker_aidata:
docker_dbdata:
docker_onlyoffice:
docker_redisdata:
open-webui:

View File

@@ -11,23 +11,6 @@ x-security: &default-security
services: services:
# --- MANAGEMENT & INFRASTRUCTURE --- # --- MANAGEMENT & INFRASTRUCTURE ---
glances:
image: nicolargo/glances:ubuntu-latest-full
container_name: glances
restart: unless-stopped
network_mode: host
environment:
- GLANCES_OPT=-w
devices:
- /dev/dri:/dev/dri
volumes:
- /data:/data:ro
- /docker:/docker:ro
- /docker:/docker-local:ro
- /run/user/1000/podman/podman.sock:/run/user/1000/podman/podman.sock
- /var/run/docker.sock:/var/run/docker.sock
logging: *default-logging
ntopng: ntopng:
image: ntop/ntopng:latest image: ntop/ntopng:latest
container_name: ntopng container_name: ntopng
@@ -71,8 +54,21 @@ services:
- /var/run/docker.sock:/var/run/docker.sock - /var/run/docker.sock:/var/run/docker.sock
- ./wud/store:/store - ./wud/store:/store
environment: environment:
- WUD_SERVER_ENABLED=false - WUD_SERVER_ENABLED=true
- WUD_REGISTRY_CUSTOM_LSCR_URL=https://lscr.io - WUD_REGISTRY_HUB_0_LOGIN=${WUD_REGISTRY_HUB_0_LOGIN}
- WUD_REGISTRY_HUB_0_TOKEN=${WUD_REGISTRY_HUB_0_TOKEN}
- WUD_REGISTRY_HUB_0_AUTH=true
- WUD_REGISTRY_GHCR_0_USERNAME=${WUD_REGISTRY_GHCR_0_USERNAME}
- WUD_REGISTRY_GHCR_0_TOKEN=${WUD_REGISTRY_GHCR_0_TOKEN}
- WUD_REGISTRY_LSCR_0_USERNAME=${WUD_REGISTRY_GHCR_0_USERNAME}
- WUD_REGISTRY_LSCR_0_TOKEN=${WUD_REGISTRY_GHCR_0_TOKEN}
- WUD_TRIGGER_MQTT_MOSQUITTO_URL=${MQTT_MOSQUITTO_URL}
- WUD_TRIGGER_MQTT_MOSQUITTO_USER=${MQTT_MOSQUITTO_USER}
- WUD_TRIGGER_MQTT_MOSQUITTO_PASSWORD=${MQTT_MOSQUITTO_PASSWORD}
- WUD_TRIGGER_MQTT_MOSQUITTO_HASS_ENABLED=true
- WUD_TRIGGER_MQTT_MOSQUITTO_HASS_PREFIX=homeassistant
ports:
- 3666:3000
healthcheck: healthcheck:
test: curl --fail http://localhost:${WUD_SERVER_PORT:-3000}/health || exit 1 test: curl --fail http://localhost:${WUD_SERVER_PORT:-3000}/health || exit 1
interval: 10s interval: 10s
@@ -356,7 +352,6 @@ services:
image: postgres image: postgres
container_name: retrom-db container_name: retrom-db
hostname: retrom-db hostname: retrom-db
env_file: ./.env
restart: always restart: always
# set shared memory limit when using docker-compose # set shared memory limit when using docker-compose
shm_size: 128mb shm_size: 128mb
@@ -512,10 +507,13 @@ services:
networks: networks:
- internal_net - internal_net
ports: ports:
- "127.0.0.1:3040:3000" - 3040:3000
environment: environment:
- PUID=${PUID} - PUID=${PUID}
- PGID=${PGID} - PGID=${PGID}
- PAPERLESS_USERNAME=jamie
- PAPERLESS_API_URL=http://paperless-webserver:8000/api
- PAPERLESS_API_TOKEN=${PAPERLESS_SECRET_KEY}
- RAG_SERVICE_URL=http://localhost:8000 - RAG_SERVICE_URL=http://localhost:8000
- RAG_SERVICE_ENABLED=true - RAG_SERVICE_ENABLED=true
volumes: volumes:
@@ -560,43 +558,6 @@ services:
- open-webui:/app/backend/data - open-webui:/app/backend/data
logging: *default-logging logging: *default-logging
litellm:
image: docker.litellm.ai/berriai/litellm:main-latest
container_name: litellm
restart: unless-stopped
networks:
- internal_net
- db_net
ports:
- "127.0.0.1:4000:4000"
environment:
- GROQ_API_KEY=${GROQ_API_KEY}
- DATABASE_URL=postgresql://litellm:litellm_pass@litellm-postgres:5432/litellm_db
- LITELLM_MASTER_KEY=${LITELLM_MASTER_KEY}
volumes:
- /docker/litellm/config.yaml:/app/config.yaml
depends_on:
litellm-postgres:
condition: service_healthy
logging: *default-logging
litellm-postgres:
image: postgres:15
container_name: litellm-postgres
restart: unless-stopped
networks:
- db_net
environment:
- POSTGRES_USER=litellm
- POSTGRES_PASSWORD=litellm_pass
- POSTGRES_DB=litellm_db
volumes:
- /docker/litellm/postgres-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U litellm -d litellm_db"]
interval: 10s
logging: *default-logging
# --- PHOTO & DATA MGMT --- # --- PHOTO & DATA MGMT ---
immich-server: immich-server:
image: ghcr.io/immich-app/immich-server:release image: ghcr.io/immich-app/immich-server:release
@@ -645,6 +606,8 @@ services:
test: ["CMD-SHELL", "pg_isready -U postgres"] test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s interval: 10s
logging: *default-logging logging: *default-logging
labels:
- wud.watch=false
immich-machine-learning: immich-machine-learning:
image: ghcr.io/immich-app/immich-machine-learning:release image: ghcr.io/immich-app/immich-machine-learning:release
@@ -680,7 +643,7 @@ services:
- /docker/syncthing:/var/syncthing - /docker/syncthing:/var/syncthing
logging: *default-logging logging: *default-logging
# --- DEVELOPMENT & APPS --- # --- GIT ---
gitea: gitea:
image: docker.gitea.com/gitea:1.25.3 image: docker.gitea.com/gitea:1.25.3
container_name: gitea container_name: gitea
@@ -722,56 +685,45 @@ services:
interval: 10s interval: 10s
logging: *default-logging logging: *default-logging
# --- GENEALOGY (Gramps) ---
grampsweb-redis:
image: redis:7.2.4-alpine
container_name: grampsweb_redis
restart: unless-stopped
networks:
- internal_net
logging: *default-logging
grampsweb-jamie:
image: ghcr.io/gramps-project/grampsweb:latest
container_name: grampsweb-jamie
restart: unless-stopped
networks:
- web_net
- internal_net
ports:
- "5511:5000"
environment:
- GRAMPSWEB_TREE=Miller Tree
- GRAMPSWEB_CELERY_CONFIG__broker_url=redis://grampsweb_redis:6379/0
volumes:
- /docker/gramps-jamie/cache:/app/cache
- /docker/gramps-jamie/db:/app/data/.gramps/grampsdb
- /docker/gramps-jamie/media:/app/media
depends_on:
- grampsweb-redis
logging: *default-logging
grampsweb-helen:
image: ghcr.io/gramps-project/grampsweb:latest
container_name: grampsweb-helen
restart: unless-stopped
networks:
- web_net
- internal_net
ports:
- "5512:5000"
environment:
- GRAMPSWEB_TREE=Helen Tree
- GRAMPSWEB_CELERY_CONFIG__broker_url=redis://grampsweb_redis:6379/0
volumes:
- /docker/gramps-helen/cache:/app/cache
- /docker/gramps-helen/db:/app/data/.gramps/grampsdb
- /docker/gramps-helen/media:/app/media
depends_on:
- grampsweb-redis
logging: *default-logging
# --- UTILITIES --- # --- UTILITIES ---
tandoor_db:
restart: unless-stopped
image: postgres:16-alpine
container_name: tandoor_DB
environment:
- POSTGRES_DB=${TANDOOR_POSTGRES_DB}
- POSTGRES_USER=${TANDOOR_POSTGRES_USER}
- POSTGRES_PASSWORD=${TANDOOR_POSTGRES_PASSWORD}
volumes:
- ./tandoor/postgresql:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${TANDOOR_POSTGRES_USER} -d ${TANDOOR_POSTGRES_DB}"]
interval: 5s
timeout: 5s
retries: 10
tandoor_web:
restart: unless-stopped
image: vabene1111/recipes
container_name: tandoor_web
environment:
- ALLOWED_HOSTS=recipes.kansaigaijin.com
- SECRET_KEY=${TANDOOR_SECRET_KEY}
- DB_ENGINE=${TANDOOR_DB_ENGINE}
- POSTGRES_HOST=${TANDOOR_POSTGRES_HOST}
- POSTGRES_DB=${TANDOOR_POSTGRES_DB}
- POSTGRES_PORT=${TANDOOR_POSTGRES_PORT}
- POSTGRES_USER=${TANDOOR_POSTGRES_USER}
- POSTGRES_PASSWORD=${TANDOOR_POSTGRES_PASSWORD}
ports:
- 8450:80
volumes:
- ./tandoor/staticfiles:/opt/recipes/staticfiles
- ./tandoor/mediafiles:/opt/recipes/mediafiles
depends_on:
tandoor_db:
condition: service_healthy
speedtest-tracker: speedtest-tracker:
image: lscr.io/linuxserver/speedtest-tracker:latest image: lscr.io/linuxserver/speedtest-tracker:latest
container_name: speedtest-tracker container_name: speedtest-tracker
@@ -847,25 +799,6 @@ services:
- /docker/redbot:/data - /docker/redbot:/data
logging: *default-logging logging: *default-logging
discord-agent:
build: ./discord-agent
container_name: discord-agent
restart: unless-stopped
networks:
- internal_net
volumes:
- ./discord-agent/data:/app/data
- /docker:/docker
env_file:
- .env
environment:
- DISCORD_BOT_TOKEN=${DISCORD_BOT_TOKEN}
- OLLAMA_ENDPOINT=${OLLAMA_ENDPOINT:-http://ollama:11434}
- OLLAMA_MODEL=${OLLAMA_MODEL:-llama3.2}
- OPENCODE_ENDPOINT=${OPENCODE_ENDPOINT:-http://192.168.0.10:4096}
- OPENCODE_API_KEY=${OPENCODE_API_KEY}
logging: *default-logging
iperf3-server: iperf3-server:
image: networkstatic/iperf3 image: networkstatic/iperf3
container_name: iperf3-server container_name: iperf3-server
@@ -877,7 +810,46 @@ services:
command: -s command: -s
logging: *default-logging logging: *default-logging
# --- FINANCE --- neolink:
image: quantumentangledandy/neolink
container_name: neolink
ports:
- 8554:8554
volumes:
- ./neolink/neolink.toml:/etc/neolink.toml
restart: unless-stopped
linkwarden-db:
container_name: linkwarden-db
image: postgres:16-alpine
restart: always
environment:
- POSTGRES_PASSWORD=${LINKWARDEN_DB_PASSWORD}
volumes:
- ./linkwarden/pgdata:/var/lib/postgresql/data
linkwarden:
container_name: linkwarden
environment:
- DATABASE_URL=postgresql://postgres:${LINKWARDEN_DB_PASSWORD}@linkwarden-db:5432/postgres
- NEXTAUTH_SECRET=${NEXTAUTH_SECRET}
- NEXTAUTH_URL=${NEXTAUTH_URL}
restart: always
image: ghcr.io/linkwarden/linkwarden:latest
ports:
- 3400:3000
volumes:
- ./linkwarden/data:/data/data
depends_on:
- linkwarden-db
- meilisearch
meilisearch:
container_name: meilisearch
image: getmeili/meilisearch:v1.12.8
restart: always
volumes:
- ./linkwarden/meili_data:/meili_data
# --- MUSIC & SCROBBLING --- # --- MUSIC & SCROBBLING ---
maloja: maloja:
@@ -917,6 +889,15 @@ services:
- /docker/scrobble/config:/config - /docker/scrobble/config:/config
logging: *default-logging logging: *default-logging
metube:
image: ghcr.io/alexta69/metube
container_name: metube
restart: unless-stopped
ports:
- "8081:8081"
volumes:
- /mnt/nas-storage/data/torrents/metube:/downloads
networks: networks:
media_net: media_net:
name: media_net name: media_net
@@ -940,4 +921,3 @@ volumes:
docker_soulsync: docker_soulsync:
open-webui: open-webui:
portainer_data: portainer_data:
discord_agent_data:

207
docker-compose.infra.yml Normal file
View File

@@ -0,0 +1,207 @@
# =============================================================================
# INFRASTRUCTURE STACK - Core services & shared networks
# =============================================================================
# DEPLOYMENT INSTRUCTIONS
# =============================================================================
# This is one of multiple compose files in the /docker/ directory.
#
# Deploy ALL stacks (from /docker/ directory):
# Get-ChildItem docker-compose.*.yml | ForEach-Object { docker compose -f $_ up -d }
#
# Deploy this stack only:
# docker compose -f docker-compose.infra.yml up -d
#
# Stop this stack:
# docker compose -f docker-compose.infra.yml down
#
# View logs for this stack:
# docker compose -f docker-compose.infra.yml logs -f
#
# IMPORTANT: Deploy this stack FIRST - it defines the shared networks
# (media_net, db_net, web_net, internal_net) that all other stacks require.
# =============================================================================
name: docker-infra
# Common configurations for re-use
x-logging: &default-logging
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
x-security: &default-security
security_opt:
- no-new-privileges:true
services:
portainer:
image: portainer/portainer-ce:2.21.5
container_name: portainer
restart: unless-stopped
networks:
- web_net
ports:
- "8000:8000"
- "9443:9443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- portainer_data:/data
deploy:
resources:
limits:
memory: 512M
logging: *default-logging
ntopng:
image: ntop/ntopng:latest
container_name: ntopng
restart: unless-stopped
network_mode: host
cap_add:
- NET_ADMIN
- NET_RAW
command: >
--interface=eth0
--http-port=3939
--disable-login=1
--community
volumes:
- /docker-local/ntopng/data:/var/lib/ntopng
- /docker-local/ntopng/redis:/var/lib/redis
logging: *default-logging
whatsupdocker:
image: getwud/wud:latest
container_name: wud
restart: unless-stopped
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./wud/store:/store
environment:
- WUD_SERVER_ENABLED=true
- WUD_REGISTRY_HUB_0_LOGIN=${WUD_REGISTRY_HUB_0_LOGIN}
- WUD_REGISTRY_HUB_0_TOKEN=${WUD_REGISTRY_HUB_0_TOKEN}
- WUD_REGISTRY_HUB_0_AUTH=true
- WUD_REGISTRY_GHCR_0_USERNAME=${WUD_REGISTRY_GHCR_0_USERNAME}
- WUD_REGISTRY_GHCR_0_TOKEN=${WUD_REGISTRY_GHCR_0_TOKEN}
- WUD_REGISTRY_LSCR_0_USERNAME=${WUD_REGISTRY_GHCR_0_USERNAME}
- WUD_REGISTRY_LSCR_0_TOKEN=${WUD_REGISTRY_GHCR_0_TOKEN}
- WUD_TRIGGER_MQTT_MOSQUITTO_URL=${MQTT_MOSQUITTO_URL}
- WUD_TRIGGER_MQTT_MOSQUITTO_USER=${MQTT_MOSQUITTO_USER}
- WUD_TRIGGER_MQTT_MOSQUITTO_PASSWORD=${MQTT_MOSQUITTO_PASSWORD}
- WUD_TRIGGER_MQTT_MOSQUITTO_HASS_ENABLED=true
- WUD_TRIGGER_MQTT_MOSQUITTO_HASS_PREFIX=homeassistant
ports:
- 3666:3000
healthcheck:
test: curl --fail http://localhost:${WUD_SERVER_PORT:-3000}/health || exit 1
interval: 10s
timeout: 10s
retries: 3
start_period: 10s
labels:
- 'wud.tag.include=^\d+\.\d+\.\d+$$'
- 'wud.link.template=https://github.com/getwud/wud/releases/tag/$${major}.$${minor}.$${patch}'
homepage:
image: ghcr.io/gethomepage/homepage:latest
container_name: homepage
restart: unless-stopped
networks:
- web_net
ports:
- "7575:3000"
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
- HOMEPAGE_ALLOWED_HOSTS=${HOMEPAGE_ALLOWED_HOSTS}
volumes:
- ./Homepage/config/icons:/app/public/icons
- ./Homepage/config/images:/app/public/images
- ./Homepage/config:/app/config
logging: *default-logging
dockerproxy:
image: ghcr.io/tecnativa/docker-socket-proxy:latest
container_name: dockerproxy
restart: unless-stopped
networks:
- internal_net
ports:
- "127.0.0.1:2375:2375"
environment:
- CONTAINERS=1
- SERVICES=1
- TASKS=1
- EVENTS=1
- PING=1
- VERSION=1
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
logging: *default-logging
newt:
image: fosrl/newt:latest
container_name: newt
restart: unless-stopped
environment:
- PANGOLIN_ENDPOINT=https://png.kansaigaijin.com
- NEWT_ID=cuvfw5hnsszh0gc
- NEWT_SECRET=iitbnuk2cevm40lt1xtrgmnehce4f2bdk4rnllj6ebeznf6h
- LOG_LEVEL=DEBUG
npm:
image: 'jc21/nginx-proxy-manager:latest'
container_name: npm
restart: unless-stopped
ports:
- '80:80'
- '443:443'
- '81:81'
environment:
DB_MYSQL_HOST: "npm-db"
DB_MYSQL_PORT: 3306
DB_MYSQL_USER: "npm"
DB_MYSQL_PASSWORD: ${NPM_PASSWORD}
DB_MYSQL_NAME: "npm"
volumes:
- ./npm/data:/data
- ./npm/letsencrypt:/etc/letsencrypt
networks:
web_net:
db_net:
depends_on:
- npm-db
npm-db:
image: 'jc21/mariadb-aria:latest'
container_name: npm-db
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: ${NPM_PASSWORD}
MYSQL_DATABASE: 'npm'
MYSQL_USER: 'npm'
MYSQL_PASSWORD: ${NPM_PASSWORD}
networks:
db_net:
volumes:
- ./npm/mysql:/var/lib/mysql
networks:
media_net:
name: media_net
driver: bridge
db_net:
name: db_net
internal: true
web_net:
name: web_net
driver: bridge
internal_net:
name: internal_net
driver: bridge
volumes:
portainer_data:

275
docker-compose.media.yml Normal file
View File

@@ -0,0 +1,275 @@
# =============================================================================
# MEDIA STACK - Media management, downloading, and playback services
# =============================================================================
# DEPLOYMENT INSTRUCTIONS
# =============================================================================
# This is one of multiple compose files in the /docker/ directory.
#
# Deploy ALL stacks (from /docker/ directory):
# Get-ChildItem docker-compose.*.yml | ForEach-Object { docker compose -f $_ up -d }
#
# Deploy this stack only:
# docker compose -f docker-compose.media.yml up -d
#
# Stop this stack:
# docker compose -f docker-compose.media.yml down
#
# View logs for this stack:
# docker compose -f docker-compose.media.yml logs -f
#
# IMPORTANT: Requires infra stack to be deployed first (shared networks).
# =============================================================================
name: docker-media
# Common configurations for re-use
x-logging: &default-logging
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
x-security: &default-security
security_opt:
- no-new-privileges:true
services:
prowlarr:
image: lscr.io/linuxserver/prowlarr:latest
container_name: prowlarr
restart: unless-stopped
networks:
media_net:
ports:
- "9696:9696"
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
volumes:
- /docker/Arrs/Prowlarr/config:/config
logging: *default-logging
flaresolverr:
image: ghcr.io/flaresolverr/flaresolverr:latest
container_name: flaresolverr
restart: unless-stopped
networks:
media_net:
ports:
- "127.0.0.1:8191:8191"
environment:
- TZ=${TZ}
logging: *default-logging
qbittorrent:
image: lscr.io/linuxserver/qbittorrent:latest
container_name: qbittorrent
restart: unless-stopped
networks:
media_net:
ports:
- "56881:6881"
- "56881:6881/udp"
- "7070:8080"
environment:
- TZ=${TZ}
- WEBUI_PORT=8080
- PUID=${PUID}
- PGID=${PGID}
volumes:
- /mnt/nas-storage/data:/data
- /docker/qBittorrent/config:/config
logging: *default-logging
radarr:
image: lscr.io/linuxserver/radarr:latest
container_name: radarr
restart: unless-stopped
networks:
media_net:
ports:
- "7878:7878"
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
volumes:
- /mnt/nas-storage/data/:/data
- /docker/Arrs/Radarr/config:/config
logging: *default-logging
sonarr:
image: lscr.io/linuxserver/sonarr:latest
container_name: sonarr
restart: unless-stopped
networks:
media_net:
ports:
- "8989:8989"
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
volumes:
- /mnt/nas-storage/data:/data
- /docker/Arrs/Sonarr/config:/config
logging: *default-logging
lidarr:
image: ghcr.io/hotio/lidarr:nightly
container_name: lidarr
restart: unless-stopped
networks:
media_net:
ports:
- "8686:8686"
environment:
- TZ=${TZ}
- PUID=${PUID}
- PGID=${PGID}
volumes:
- /mnt/nas-storage/data:/data
- /docker/Arrs/Lidarr/config:/config
logging: *default-logging
bazarr:
image: lscr.io/linuxserver/bazarr:latest
container_name: bazarr
restart: unless-stopped
networks:
media_net:
ports:
- "6767:6767"
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
volumes:
- /mnt/nas-storage/data:/data
- /docker/Arrs/Bazarr/config:/config
logging: *default-logging
seerr:
image: ghcr.io/seerr-team/seerr:latest
init: true
container_name: seerr
environment:
- LOG_LEVEL=debug
- TZ=${TZ}
networks:
media_net:
ports:
- 5055:5055
volumes:
- /docker/Arrs/Seerr/config:/app/config
healthcheck:
test: wget --no-verbose --tries=1 --spider http://localhost:5055/api/v1/status || exit 1
start_period: 20s
timeout: 3s
interval: 15s
retries: 3
restart: unless-stopped
jellyfin:
image: jellyfin/jellyfin:latest
container_name: jellyfin
restart: unless-stopped
networks:
- media_net
- internal_net
ports:
- "8096:8096"
environment:
- JELLYFIN_PublishedServerUrl=${JELLYFIN_URL}
- TZ=${TZ}
- PUID=${PUID}
- PGID=${PGID}
group_add:
- "104"
devices:
- /dev/dri/renderD128:/dev/dri/renderD128
volumes:
- /mnt/nas-storage/data:/data
- /docker/Arrs/Jellyfin/cache:/cache
- /docker/Arrs/Jellyfin/config:/config
logging: *default-logging
slskd:
image: slskd/slskd:latest
container_name: slskd
restart: unless-stopped
networks:
media_net:
ports:
- "5030:5030"
- "50300:50300"
- "5031:5031"
hostname: slskd
environment:
- TZ=${TZ}
- SLSKD_REMOTE_CONFIGURATION=true
- SLSKD_USERNAME=${SLSKD_USERNAME}
- SLSKD_PASSWORD=${SLSKD_PASSWORD}
volumes:
- /mnt/nas-storage/data/torrents/soulsync/complete:/data/torrents/soulsync/complete
- /mnt/nas-storage/data/torrents/soulsync/incomplete:/data/torrents/soulsync/incomplete
- /docker/slskd:/app
logging: *default-logging
metube:
image: ghcr.io/alexta69/metube
container_name: metube
restart: unless-stopped
ports:
- "8081:8081"
volumes:
- /mnt/nas-storage/data/torrents/metube:/downloads
maloja:
image: krateng/maloja:latest
container_name: maloja
restart: unless-stopped
environment:
- MALOJA_FORCE_PASSWORD=${MALOJA_FORCE_PASSWORD}
networks:
- internal_net
- web_net
ports:
- "42010:42010"
volumes:
- /docker/maloja/config:/etc/maloja
- /docker/maloja/data:/var/lib/maloja
logging: *default-logging
multi-scrobbler:
image: foxxmd/multi-scrobbler:latest
container_name: multi-scrobbler
restart: unless-stopped
networks:
- internal_net
ports:
- "9078:9078"
environment:
- MALOJA_URL=${MALOJA_URL}
- MALOJA_API_KEY=${MALOJA_API_KEY}
- JELLYFIN_URL=${JELLYFIN_URL}
- JELLYFIN_APIKEY=${JELLYFIN_APIKEY_MS}
- JELLYFIN_USER=${JELLYFIN_USER}
- JELLYFIN_TRANSFORMS=musicbrainz
- MB_CONTACT=${MB_CONTACT}
- MB_PRESETS=default,sensible,native
volumes:
- /docker/scrobble/config:/config
logging: *default-logging
networks:
media_net:
name: media_net
external: true
internal_net:
name: internal_net
external: true
web_net:
name: web_net
external: true

View File

@@ -0,0 +1,178 @@
# =============================================================================
# PHOTO & ROM LIBRARY STACK - Photo management, file sync, and ROM library
# =============================================================================
# DEPLOYMENT INSTRUCTIONS
# =============================================================================
# This is one of multiple compose files in the /docker/ directory.
#
# Deploy ALL stacks (from /docker/ directory):
# Get-ChildItem docker-compose.*.yml | ForEach-Object { docker compose -f $_ up -d }
#
# Deploy this stack only:
# docker compose -f docker-compose.photo-roms.yml up -d
#
# Stop this stack:
# docker compose -f docker-compose.photo-roms.yml down
#
# View logs for this stack:
# docker compose -f docker-compose.photo-roms.yml logs -f
#
# IMPORTANT: Requires infra stack to be deployed first (shared networks).
# =============================================================================
name: docker-photo-roms
# Common configurations for re-use
x-logging: &default-logging
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
x-security: &default-security
security_opt:
- no-new-privileges:true
services:
immich-server:
image: ghcr.io/immich-app/immich-server:release
container_name: immich_server
restart: unless-stopped
networks:
- web_net
- db_net
- internal_net
ports:
- "2283:2283"
environment:
- TZ=${TZ}
- DB_USERNAME=postgres
- DB_PASSWORD=${IMMICH_POSTGRES_PASSWORD}
- DB_DATABASE_NAME=immich
- DB_HOSTNAME=immich-postgres
- REDIS_HOSTNAME=immich-redis
- UPLOAD_LOCATION=/data
volumes:
# LOCAL (SSD) - Config, Thumbs, Profile, and Backups
- /docker/immich:/usr/src/app/upload/library
- /docker/immich/thumbs:/usr/src/app/upload/thumbs
- /docker/immich/profile:/usr/src/app/upload/profile
- /docker/immich/backups:/usr/src/app/upload/backups
- /docker/immich/encoded-video:/usr/src/app/upload/encoded-video
- /docker/immich/upload:/usr/src/app/upload/upload
depends_on:
immich-postgres:
condition: service_healthy
logging: *default-logging
immich-postgres:
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0
container_name: immich_postgres
restart: unless-stopped
networks:
- db_net
environment:
- POSTGRES_USER=postgres
- POSTGRES_DB=immich
- POSTGRES_PASSWORD=${IMMICH_POSTGRES_PASSWORD}
volumes:
- /docker/immich/postgres:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
logging: *default-logging
labels:
- wud.watch=false
immich-machine-learning:
image: ghcr.io/immich-app/immich-machine-learning:release
container_name: immich-machine-learning
restart: unless-stopped
networks:
- internal_net
volumes:
- /docker/immich/model-cache:/cache
logging: *default-logging
immich-redis:
image: valkey/valkey:8-bookworm
container_name: immich_redis
restart: unless-stopped
networks:
- internal_net
logging: *default-logging
syncthing:
image: syncthing/syncthing
container_name: syncthing
restart: unless-stopped
networks:
- web_net
- internal_net
ports:
- "21027:21027/udp"
- "22000:22000"
- "8384:8384"
volumes:
- /docker/obsidian/vaults:/var/syncthing/obsidian
- /docker/syncthing:/var/syncthing
logging: *default-logging
retrom-db:
image: postgres
container_name: retrom-db
hostname: retrom-db
restart: always
shm_size: 128mb
ports:
- 5432:5432
environment:
TZ: "America/Los_Angeles"
PGTZ: "America/Los_Angeles"
POSTGRES_PASSWORD: ${DB_PASS:-password}
POSTGRES_USER: ${DB_USER:-postgres}
POSTGRES_DB: ${DB_NAME:-retrom-dev}
retrom-adminer:
container_name: retrom-adminer
image: adminer
restart: always
ports:
- 8080:8080
retrom:
container_name: retrom
hostname: retrom
image: ghcr.io/jmberesford/retrom-service:latest
ulimits:
nofile:
hard: 65536
soft: 65536
ports:
- 5111:5101
volumes:
- /mnt/nas-storage/data/media/romms:/app/library
- ./retrom/config:/app/config/
- ./retrom/data:/app/data/
depends_on:
- retrom-db
retrom-jaeger:
image: jaegertracing/jaeger:2.2.0
ports:
- 16686:16686
- 4317:4317
- 4318:4318
- 5778:5778
- 9411:9411
networks:
web_net:
name: web_net
external: true
db_net:
name: db_net
external: true
internal_net:
name: internal_net
external: true

252
docker-compose.utils.yml Normal file
View File

@@ -0,0 +1,252 @@
# =============================================================================
# UTILITIES STACK - Development tools, tracking, remote access, and misc services
# =============================================================================
# DEPLOYMENT INSTRUCTIONS
# =============================================================================
# This is one of multiple compose files in the /docker/ directory.
#
# Deploy ALL stacks (from /docker/ directory):
# Get-ChildItem docker-compose.*.yml | ForEach-Object { docker compose -f $_ up -d }
#
# Deploy this stack only:
# docker compose -f docker-compose.utils.yml up -d
#
# Stop this stack:
# docker compose -f docker-compose.utils.yml down
#
# View logs for this stack:
# docker compose -f docker-compose.utils.yml logs -f
#
# IMPORTANT: Requires infra stack to be deployed first (shared networks).
# =============================================================================
name: docker-utils
# Common configurations for re-use
x-logging: &default-logging
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
x-security: &default-security
security_opt:
- no-new-privileges:true
services:
gitea:
image: docker.gitea.com/gitea:1.25.3
container_name: gitea
restart: unless-stopped
networks:
- web_net
- db_net
ports:
- "222:22"
- "8418:3000"
environment:
- GITEA__database__HOST=gitea-db:3306
- GITEA__database__NAME=gitea
- GITEA__database__USER=gitea
- GITEA__database__PASSWD=gitea
- GITEA__database__DB_TYPE=mysql
volumes:
- /docker/gitea/data:/data
depends_on:
gitea-db:
condition: service_healthy
logging: *default-logging
gitea-db:
image: mysql:8
container_name: gitea-db
restart: unless-stopped
networks:
- db_net
environment:
- MYSQL_ROOT_PASSWORD=gitea
- MYSQL_USER=gitea
- MYSQL_PASSWORD=gitea
- MYSQL_DATABASE=gitea
volumes:
- /docker/gitea/mysql:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
interval: 10s
logging: *default-logging
tandoor_db:
restart: unless-stopped
image: postgres:16-alpine
container_name: tandoor_DB
environment:
- POSTGRES_DB=${TANDOOR_POSTGRES_DB}
- POSTGRES_USER=${TANDOOR_POSTGRES_USER}
- POSTGRES_PASSWORD=${TANDOOR_POSTGRES_PASSWORD}
volumes:
- ./tandoor/postgresql:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${TANDOOR_POSTGRES_USER} -d ${TANDOOR_POSTGRES_DB}"]
interval: 5s
timeout: 5s
retries: 10
tandoor_web:
restart: unless-stopped
image: vabene1111/recipes
container_name: tandoor_web
environment:
- ALLOWED_HOSTS=recipes.kansaigaijin.com
- SECRET_KEY=${TANDOOR_SECRET_KEY}
- DB_ENGINE=${TANDOOR_DB_ENGINE}
- POSTGRES_HOST=${TANDOOR_POSTGRES_HOST}
- POSTGRES_DB=${TANDOOR_POSTGRES_DB}
- POSTGRES_PORT=${TANDOOR_POSTGRES_PORT}
- POSTGRES_USER=${TANDOOR_POSTGRES_USER}
- POSTGRES_PASSWORD=${TANDOOR_POSTGRES_PASSWORD}
ports:
- 8450:80
volumes:
- ./tandoor/staticfiles:/opt/recipes/staticfiles
- ./tandoor/mediafiles:/opt/recipes/mediafiles
depends_on:
tandoor_db:
condition: service_healthy
speedtest-tracker:
image: lscr.io/linuxserver/speedtest-tracker:latest
container_name: speedtest-tracker
restart: unless-stopped
networks:
- web_net
- db_net
ports:
- "8180:80"
environment:
- SPEEDTEST_SCHEDULE="0 */6 * * *"
- SPEEDTEST_SERVERS=7317
- DB_HOST=speedtest-db
- DB_DATABASE=${SPEEDTEST_DB_NAME}
- DB_PASSWORD=${SPEEDTEST_DB_PASSWORD}
- DB_CONNECTION=mariadb
- DB_USERNAME=${SPEEDTEST_DB_USER}
- APP_KEY=${SPEEDTEST_APP_KEY}
volumes:
- /docker/speedtest-tracker/data:/config
depends_on:
speedtest-db:
condition: service_healthy
logging: *default-logging
speedtest-db:
image: mariadb:11
container_name: speedtest-db
restart: unless-stopped
networks:
- db_net
environment:
- MYSQL_USER=${SPEEDTEST_DB_USER}
- MYSQL_PASSWORD=${SPEEDTEST_DB_PASSWORD}
- MYSQL_DATABASE=${SPEEDTEST_DB_NAME}
- MYSQL_RANDOM_ROOT_PASSWORD=true
volumes:
- /docker/speedtest-tracker/db:/var/lib/mysql
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
interval: 10s
logging: *default-logging
rustdesk-hbbs:
image: rustdesk/rustdesk-server:latest
container_name: hbbs
network_mode: host
restart: unless-stopped
command: hbbs
volumes:
- /docker/rustdesk/data:/root
logging: *default-logging
rustdesk-hbbr:
image: rustdesk/rustdesk-server:latest
container_name: hbbr
network_mode: host
restart: unless-stopped
command: hbbr
volumes:
- /docker/rustdesk/data:/root
logging: *default-logging
redbot:
image: phasecorex/red-discordbot
container_name: redbot
restart: unless-stopped
networks:
- internal_net
environment:
- TOKEN=${REDBOT_TOKEN}
volumes:
- /docker/redbot:/data
logging: *default-logging
iperf3-server:
image: networkstatic/iperf3
container_name: iperf3-server
restart: unless-stopped
networks:
- internal_net
ports:
- "5201:5201"
command: -s
logging: *default-logging
neolink:
image: quantumentangledandy/neolink
container_name: neolink
ports:
- 8554:8554
volumes:
- ./neolink/neolink.toml:/etc/neolink.toml
restart: unless-stopped
linkwarden-db:
container_name: linkwarden-db
image: postgres:16-alpine
restart: always
environment:
- POSTGRES_PASSWORD=${LINKWARDEN_DB_PASSWORD}
volumes:
- ./linkwarden/pgdata:/var/lib/postgresql/data
linkwarden:
container_name: linkwarden
environment:
- DATABASE_URL=postgresql://postgres:${LINKWARDEN_DB_PASSWORD}@linkwarden-db:5432/postgres
- NEXTAUTH_SECRET=${NEXTAUTH_SECRET}
- NEXTAUTH_URL=${NEXTAUTH_URL}
restart: always
image: ghcr.io/linkwarden/linkwarden:latest
ports:
- 3400:3000
volumes:
- ./linkwarden/data:/data/data
depends_on:
- linkwarden-db
- meilisearch
meilisearch:
container_name: meilisearch
image: getmeili/meilisearch:v1.12.8
restart: always
volumes:
- ./linkwarden/meili_data:/meili_data
networks:
web_net:
name: web_net
external: true
db_net:
name: db_net
external: true
internal_net:
name: internal_net
external: true