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

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