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

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