# 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: # --- 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 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 watchtower: image: containrrr/watchtower container_name: watchtower restart: unless-stopped networks: - internal_net environment: - WATCHTOWER_CLEANUP=true - WATCHTOWER_POLL_INTERVAL=86400 volumes: - /var/run/docker.sock:/var/run/docker.sock logging: *default-logging 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: - /docker/Homepage/config/icons:/app/public/icons - /docker/Homepage/config/images:/app/public/images - /docker/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' # Public HTTP Port - '443:443' # Public HTTPS Port - '81:81' # Admin Web Port 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 # --- MEDIA & ARRS (Static IPs 172.20.0.x) --- 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/linuxserver-labs/prarr:lidarr-plugins 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 jellyseerr: image: fallenbagel/jellyseerr:latest container_name: jellyseerr restart: unless-stopped networks: media_net: ports: - "5055:5055" environment: - LOG_LEVEL=debug - TZ=${TZ} volumes: - /docker/Arrs/Jellyseerr/config:/app/config logging: *default-logging 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" # This matches the GID from your ls -l output 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 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:/downloads - /mnt/Nas-Storage/data/torrents/soulsync/incomplete:/incomplete - /docker/slskd:/app logging: *default-logging soulsync-webui: image: boulderbadgedad/soulsync:latest container_name: soulsync-webui restart: unless-stopped networks: media_net: ports: - "8887:8008" extra_hosts: - "host.docker.internal:host-gateway" environment: - TZ=${TZ} - PUID=${PUID} - PGID=${PGID} - FLASK_ENV=production volumes: - /mnt/Nas-Storage/data/media/music:/music:ro - /mnt/Nas-Storage/data/torrents/soulsync:/app/downloads - /docker/soulsync/logs:/app/logs - docker_soulsync:/app/database logging: *default-logging # --- DOCUMENT & AI SUITE --- 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: - "127.0.0.1:3040:3000" environment: - PUID=${PUID} - PGID=${PGID} - 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=true - 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 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 --- 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/library/thumbs:/usr/src/app/upload/thumbs - /docker/immich/library/profile:/usr/src/app/upload/profile - /docker/immich/library/backups:/usr/src/app/upload/backups # NAS (HDD) - High Resolution Library & Uploads - /mnt/Nas-Storage/data/media/images/library:/usr/src/app/upload/library - /mnt/Nas-Storage/data/media/images/upload:/usr/src/app/upload/upload - /mnt/Nas-Storage/data/media/images/encoded-video:/usr/src/app/upload/encoded-video 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 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 # --- DEVELOPMENT & APPS --- 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 # --- 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_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 --- 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 # --- FINANCE --- wygiwyh-web: image: eitchtee/wygiwyh:latest container_name: WYGIWYH environment: # --- DATABASE SETTINGS --- - SQL_ENGINE=django.db.backends.postgresql - SQL_HOST=wygiwyh-db # Matches the service name below - SQL_PORT=5432 - SQL_DATABASE=${WYGIWYH_DB_DATABASE} - SQL_USER=${WYGIWYH_DB_USER} - SQL_PASSWORD=${WYGIWYH_DB_PASSWORD} # --- APP SETTINGS --- - SECRET_KEY=${WYGIWYH_SECRET_KEY} - DJANGO_ALLOWED_HOSTS=${WYGIWYH_ALLOWED_HOSTS} - WYGIWYH_URL=${WYGIWYH_URL} networks: - web_net - db_net ports: - 9008:8000 depends_on: - wygiwyh-db restart: unless-stopped wygiwyh-db: image: postgres:15-bookworm container_name: WYGIWYH-db environment: - POSTGRES_USER=${WYGIWYH_DB_USER} - POSTGRES_PASSWORD=${WYGIWYH_DB_PASSWORD} - POSTGRES_DB=${WYGIWYH_DB_DATABASE} networks: - db_net volumes: - ./wygiwyh/postgres_data:/var/lib/postgresql/data/ # --- MUSIC & SCROBBLING --- maloja: image: krateng/maloja:latest container_name: maloja restart: unless-stopped 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=http://maloja:42010 volumes: - /docker/scrobble/config:/config logging: *default-logging 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: docker_aidata: docker_dbdata: docker_model-cache: docker_onlyoffice: docker_redisdata: docker_soulsync: open-webui: portainer_data: