From 89760895f2c07a46f4dd381150c88f75d172e002 Mon Sep 17 00:00:00 2001 From: EZ-Homelab Date: Thu, 22 Jan 2026 16:44:44 -0500 Subject: [PATCH] Refactor docker-compose structure to folder-based organization - Remove redundant .yml files from main docker-compose folder - Update deploy script to use folder-based structure for all stacks - Update documentation to reflect new folder-based organization - Standardize all stacks to use docker-compose.yml in individual folders This eliminates confusion between file-based and folder-based structures, making the repository more maintainable and consistent. --- Install script testing results.md | 23 ++ docker-compose/README.md | 34 +-- docker-compose/core.yml | 137 ----------- docker-compose/dashboards.yml | 91 -------- docker-compose/infrastructure.yml | 267 ---------------------- docker-compose/media-management.yml | 341 ---------------------------- docker-compose/media.yml | 81 ------- docker-compose/monitoring.yml | 227 ------------------ docker-compose/productivity.yml | 337 --------------------------- docker-compose/utilities.yml | 170 -------------- docs/manual-setup.md | 6 +- docs/quick-reference.md | 10 +- scripts/deploy-homelab.sh | 4 +- 13 files changed, 51 insertions(+), 1677 deletions(-) create mode 100644 Install script testing results.md delete mode 100644 docker-compose/core.yml delete mode 100644 docker-compose/dashboards.yml delete mode 100644 docker-compose/infrastructure.yml delete mode 100644 docker-compose/media-management.yml delete mode 100644 docker-compose/media.yml delete mode 100644 docker-compose/monitoring.yml delete mode 100644 docker-compose/productivity.yml delete mode 100644 docker-compose/utilities.yml diff --git a/Install script testing results.md b/Install script testing results.md new file mode 100644 index 0000000..0513b73 --- /dev/null +++ b/Install script testing results.md @@ -0,0 +1,23 @@ +Install script testing results + +Installed debian to start from scratch. + +Install Nvidia driver failed in setup-homelab.scratch +Attempted to follow manual directions, manual directions missing how to generate the authelia secrets +script didn't generate + AUTHELIA_JWT_SECRET=generate-with-openssl-rand-hex-64 + AUTHELIA_SESSION_SECRET=generate-with-openssl-rand-hex-64 + AUTHELIA_STORAGE_ENCRYPTION_KEY=generate-with-openssl-rand-hex-64 + +in setup-homelab.sh +commented out the apt install nvidia lines +script completed successfully, but still missing authelia secrets + +ran deploy script, it completed successfully as well. +however missing authelia secrets prevents proxy access + +Fix setup and deploy scripts to ensure an effortless install from scratch for the user experience. +Confirm they work as intended, and services are available by proxy url. + + + diff --git a/docker-compose/README.md b/docker-compose/README.md index 9c53e51..4e2c3b9 100644 --- a/docker-compose/README.md +++ b/docker-compose/README.md @@ -1,15 +1,22 @@ # Docker Compose Stacks -This directory contains Docker Compose files for managing your homelab services. Each file is organized by functional area to maintain clarity and organization. +This directory contains Docker Compose files for managing your homelab services. Each stack is organized in its own folder for better organization and maintainability. ## Structure ``` docker-compose/ -├── infrastructure.yml # Core services (reverse proxy, DNS, etc.) -├── media.yml # Media server services (Plex, Jellyfin, etc.) -├── monitoring.yml # Observability stack (Prometheus, Grafana, etc.) -├── development.yml # Development tools and services +├── core/ # Core infrastructure (Traefik, Authelia, DuckDNS) +├── infrastructure/ # Additional infrastructure (Pi-hole, Dockge, etc.) +├── dashboards/ # Dashboard services (Homepage, Homarr) +├── vpn/ # VPN services (Gluetun, qBittorrent) +├── media/ # Media services (Plex, Jellyfin, etc.) +├── monitoring/ # Observability stack (Prometheus, Grafana, etc.) +├── alternatives/ # Alternative services (Authentik, etc.) +├── homeassistant/ # Home Assistant stack +├── nextcloud/ # Nextcloud stack +├── productivity/ # Productivity tools +├── utilities/ # Utility services └── README.md # This file ``` @@ -17,31 +24,26 @@ docker-compose/ ### Starting Services -Start all services in a compose file: +Start all services in a stack: ```bash -docker compose -f docker-compose/infrastructure.yml up -d +cd docker-compose/core && docker compose up -d ``` Start a specific service: ```bash -docker compose -f docker-compose/media.yml up -d plex -``` - -Start multiple compose files together: -```bash -docker compose -f docker-compose/infrastructure.yml -f docker-compose/media.yml up -d +cd docker-compose/vpn && docker compose up -d gluetun ``` ### Stopping Services -Stop all services in a compose file: +Stop all services in a stack: ```bash -docker compose -f docker-compose/infrastructure.yml down +cd docker-compose/core && docker compose down ``` Stop a specific service: ```bash -docker compose -f docker-compose/media.yml stop plex +cd docker-compose/vpn && docker compose stop qbittorrent ``` ### Viewing Status diff --git a/docker-compose/core.yml b/docker-compose/core.yml deleted file mode 100644 index bb7f4bc..0000000 --- a/docker-compose/core.yml +++ /dev/null @@ -1,137 +0,0 @@ -# Core Infrastructure Stack -# Essential services required for the homelab to function -# Deploy this stack FIRST before any other services -# Place in /opt/stacks/core/docker-compose.yml - -services: - # DuckDNS - Dynamic DNS updater - # Updates your public IP automatically for Let's Encrypt SSL - duckdns: - image: lscr.io/linuxserver/duckdns:latest - container_name: duckdns - restart: unless-stopped - environment: - - PUID=${PUID:-1000} - - PGID=${PGID:-1000} - - TZ=${TZ} - - SUBDOMAINS=${DUCKDNS_SUBDOMAINS} # Your subdomain(s), comma separated - - TOKEN=${DUCKDNS_TOKEN} # Your DuckDNS token - - UPDATE_IP=ipv4 # or ipv6, or both - volumes: - - /opt/stacks/core/duckdns:/config - labels: - - "homelab.category=infrastructure" - - "homelab.description=Dynamic DNS updater" - - # Traefik - Reverse proxy with automatic SSL - # Routes all traffic and manages Let's Encrypt certificates - traefik: - image: traefik:v2.11 - container_name: traefik - restart: unless-stopped - security_opt: - - no-new-privileges:true - networks: - - traefik-network - ports: - - "80:80" # HTTP - - "443:443" # HTTPS - - "8080:8080" # Dashboard (protected with Authelia) - volumes: - - /etc/localtime:/etc/localtime:ro - - /var/run/docker.sock:/var/run/docker.sock:ro - - /opt/stacks/core/traefik/traefik.yml:/traefik.yml:ro - - /opt/stacks/core/traefik/dynamic:/dynamic:ro - - /opt/stacks/core/traefik/acme.json:/acme.json - environment: - - CF_DNS_API_TOKEN=${CF_DNS_API_TOKEN} # If using Cloudflare DNS challenge - - DUCKDNS_TOKEN=${DUCKDNS_TOKEN} # If using DuckDNS - labels: - - "traefik.enable=true" - # Dashboard - - "traefik.http.routers.traefik.rule=Host(`traefik.${DOMAIN}`)" - - "traefik.http.routers.traefik.entrypoints=websecure" - - "traefik.http.routers.traefik.tls.certresolver=letsencrypt" - - "traefik.http.routers.traefik.middlewares=authelia@docker" - - "traefik.http.routers.traefik.service=api@internal" - # Global HTTP to HTTPS redirect - - "traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)" - - "traefik.http.routers.http-catchall.entrypoints=web" - - "traefik.http.routers.http-catchall.middlewares=redirect-to-https" - - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https" - depends_on: - - duckdns - - # Authelia - SSO authentication - # Protects all admin services with single sign-on - authelia: - image: authelia/authelia:4.37 - container_name: authelia - restart: unless-stopped - networks: - - traefik-network - volumes: - - /opt/stacks/core/authelia/configuration.yml:/config/configuration.yml:ro - - /opt/stacks/core/authelia/users_database.yml:/config/users_database.yml - - authelia-data:/config - environment: - - TZ=${TZ} - - AUTHELIA_JWT_SECRET=${AUTHELIA_JWT_SECRET} - - AUTHELIA_SESSION_SECRET=${AUTHELIA_SESSION_SECRET} - - AUTHELIA_STORAGE_ENCRYPTION_KEY=${AUTHELIA_STORAGE_ENCRYPTION_KEY} - - AUTHELIA_NOTIFIER_SMTP_PASSWORD=${SMTP_PASSWORD} # If using email notifications - labels: - - "traefik.enable=true" - - "traefik.http.routers.authelia.rule=Host(`auth.${DOMAIN}`)" - - "traefik.http.routers.authelia.entrypoints=websecure" - - "traefik.http.routers.authelia.tls.certresolver=letsencrypt" - - "traefik.http.services.authelia.loadbalancer.server.port=9091" - # Authelia middleware for other services - - "traefik.http.middlewares.authelia.forwardauth.address=http://authelia:9091/api/verify?rd=https://auth.${DOMAIN}" - - "traefik.http.middlewares.authelia.forwardauth.trustForwardHeader=true" - - "traefik.http.middlewares.authelia.forwardauth.authResponseHeaders=Remote-User,Remote-Groups,Remote-Name,Remote-Email" - depends_on: - - traefik - - # Gluetun - VPN client (Surfshark WireGuard) - # Routes download clients through VPN for security - gluetun: - image: qmcgaw/gluetun:latest - container_name: gluetun - restart: unless-stopped - cap_add: - - NET_ADMIN - devices: - - /dev/net/tun:/dev/net/tun - networks: - - homelab-network - - traefik-network - ports: - - "8888:8888/tcp" # HTTP proxy - - "8388:8388/tcp" # Shadowsocks - - "8388:8388/udp" # Shadowsocks - - "8081:8080" # qBittorrent web UI (mapped to 8081 to avoid Traefik conflict) - - "6881:6881" # qBittorrent - - "6881:6881/udp" # qBittorrent - volumes: - - /opt/stacks/core/gluetun:/gluetun - environment: - - VPN_SERVICE_PROVIDER=surfshark - - VPN_TYPE=wireguard - - WIREGUARD_PRIVATE_KEY=${SURFSHARK_PRIVATE_KEY} - - WIREGUARD_ADDRESSES=${SURFSHARK_ADDRESSES} - - SERVER_COUNTRIES=${VPN_SERVER_COUNTRIES:-Netherlands} - - TZ=${TZ} - labels: - - "homelab.category=infrastructure" - - "homelab.description=VPN client for secure downloads" - -volumes: - authelia-data: - driver: local - -networks: - traefik-network: - external: true - homelab-network: - external: true diff --git a/docker-compose/dashboards.yml b/docker-compose/dashboards.yml deleted file mode 100644 index 16d000d..0000000 --- a/docker-compose/dashboards.yml +++ /dev/null @@ -1,91 +0,0 @@ -# Dashboard Services -# Homepage and Homarr for homelab dashboards -# Place in /opt/stacks/dashboards/docker-compose.yml - -# Service Access URLs: -# - Homepage: https://home.${DOMAIN} -# - Homarr: https://homarr.${DOMAIN} - -services: - # Homepage - Application dashboard (AI-configurable via YAML) - # Access at: https://home.${DOMAIN} - homepage: - image: ghcr.io/gethomepage/homepage:latest - deploy: - resources: - limits: - cpus: '0.50' - memory: 256M - pids: 512 - reservations: - cpus: '0.25' - memory: 128M - container_name: homepage - restart: unless-stopped - networks: - - homelab-network - - traefik-network - - dockerproxy-network - volumes: - - ./homepage:/app/config - - /var/run/docker.sock:/var/run/docker.sock # For Docker integration do not mount RO - - /opt/stacks:/opt/stacks # To discover other stacks - environment: - - PUID=995 # Must be set to the docker user ID - - PGID=995 # Must be set to the docker group ID - - TZ=${TZ} - - HOMEPAGE_ALLOWED_HOSTS=home.${DOMAIN} - labels: - - "homelab.category=dashboard" - - "homelab.description=Application dashboard (AI-configurable)" - - "traefik.enable=true" - - "traefik.http.routers.homepage.rule=Host(`home.${DOMAIN}`)" - - "traefik.http.routers.homepage.entrypoints=websecure" - - "traefik.http.routers.homepage.tls=true" - - "traefik.http.routers.homepage.middlewares=authelia@docker" - - "traefik.http.services.homepage.loadbalancer.server.port=3000" - - # Homarr - Modern dashboard - # Access at: https://homarr.${DOMAIN} - homarr: - image: ghcr.io/ajnart/homarr:latest - deploy: - resources: - limits: - cpus: '0.50' - memory: 256M - pids: 512 - reservations: - cpus: '0.25' - memory: 128M - container_name: homarr - restart: unless-stopped - networks: - - homelab-network - - traefik-network - volumes: - - ./homarr/config:/app/config/configs - - ./homarr/data:/data - - ./homarr/icons:/app/public/icons - - /var/run/docker.sock:/var/run/docker.sock - environment: - - TZ=${TZ} - labels: - - "homelab.category=dashboard" - - "homelab.description=Modern homelab dashboard" - - "traefik.enable=true" - - "traefik.http.routers.homarr.rule=Host(`homarr.${DOMAIN}`)" - - "traefik.http.routers.homarr.entrypoints=websecure" - - "traefik.http.routers.homarr.tls=true" - - "traefik.http.routers.homarr.middlewares=authelia@docker" - - "traefik.http.services.homarr.loadbalancer.server.port=7575" - - "x-dockge.url=https://homarr.${DOMAIN}" - - "x-dockge.url=https://homarr.${DOMAIN}" - -networks: - homelab-network: - external: true - traefik-network: - external: true - dockerproxy-network: - external: true diff --git a/docker-compose/infrastructure.yml b/docker-compose/infrastructure.yml deleted file mode 100644 index c94c19e..0000000 --- a/docker-compose/infrastructure.yml +++ /dev/null @@ -1,267 +0,0 @@ -# Infrastructure Services -# Core services that other services depend on -# Place in /opt/stacks/infrastructure/docker-compose.yml -# NOTE: Traefik, Authelia, DuckDNS, and Gluetun have their own separate stacks -# See /opt/stacks/traefik/, /opt/stacks/authelia/, etc. - -# Service Access URLs: -# - Dockge: https://dockge.${DOMAIN} -# - Portainer: https://portainer.${DOMAIN} -# - Pi-hole: https://pihole.${DOMAIN} -# - Dozzle: https://dozzle.${DOMAIN} -# - Glances: https://glances.${DOMAIN} -# - Netdata: https://netdata.${DOMAIN} - -services: - # Dockge - Docker Compose Stack Manager (PRIMARY - preferred over Portainer) - # Access at: https://dockge.${DOMAIN} - dockge: - image: louislam/dockge:1 - deploy: - resources: - limits: - cpus: '0.50' - memory: 256M - pids: 512 - reservations: - cpus: '0.25' - memory: 128M - container_name: dockge - restart: unless-stopped - networks: - - homelab-network - - traefik-network - ports: - - "5001:5001" # Optional: direct access - volumes: - - /var/run/docker.sock:/var/run/docker.sock - - /opt/stacks:/opt/stacks # Dockge manages stacks in this directory - - /opt/dockge/data:/app/data - environment: - - DOCKGE_STACKS_DIR=/opt/stacks - - DOCKGE_ENABLE_CONSOLE=true - # Proxy Authentication for SSO integration with Authelia - - DOCKGE_AUTH_PROXY_HEADER=Remote-User - - DOCKGE_AUTH_PROXY_AUTO_CREATE=true - - DOCKGE_AUTH_PROXY_LOGOUT_URL=https://auth.${DOMAIN}/logout - labels: - - "homelab.category=infrastructure" - - "homelab.description=Docker Compose stack manager (PRIMARY)" - - "traefik.enable=true" - - "traefik.http.routers.dockge.rule=Host(`dockge.${DOMAIN}`)" - - "traefik.http.routers.dockge.entrypoints=websecure" - - "traefik.http.routers.dockge.tls=true" - - "traefik.http.routers.dockge.middlewares=authelia@docker" - - "traefik.http.services.dockge.loadbalancer.server.port=5001" - - "x-dockge.url=https://dockge.${DOMAIN}" - - "x-dockge.url=https://dockge.${DOMAIN}" - - # Pi-hole - Network-wide ad blocker and DNS server - # Access at: https://pihole.${DOMAIN} - pihole: - image: pihole/pihole:2024.01.0 - deploy: - resources: - limits: - cpus: '0.25' - memory: 128M - pids: 256 - reservations: - cpus: '0.10' - memory: 64M - container_name: pihole - restart: unless-stopped - networks: - - homelab-network - - traefik-network - ports: - - "53:53/tcp" # DNS TCP - - "53:53/udp" # DNS UDP - volumes: - - ./pihole/etc-pihole:/etc/pihole - - ./pihole/etc-dnsmasq.d:/etc/dnsmasq.d - environment: - - TZ=${TZ:-America/New_York} - - WEBPASSWORD=${PIHOLE_PASSWORD:-changeme} - - FTLCONF_LOCAL_IPV4=${SERVER_IP} - dns: - - 127.0.0.1 - - 1.1.1.1 - cap_add: - - NET_ADMIN - labels: - - "homelab.category=infrastructure" - - "homelab.description=Network-wide ad blocking and DNS" - - "traefik.enable=true" - - "traefik.http.routers.pihole.rule=Host(`pihole.${DOMAIN}`)" - - "traefik.http.routers.pihole.entrypoints=websecure" - - "traefik.http.routers.pihole.tls=true" - - "traefik.http.routers.pihole.tls.certresolver=letsencrypt" - - "traefik.http.routers.pihole.middlewares=authelia@docker" - - "traefik.http.services.pihole.loadbalancer.server.port=80" - - # Watchtower - Automatic container updates - # TEMPORARILY DISABLED: Docker API version incompatibility with Docker 29.x - # Watchtower versions have API compatibility issues: - # - v1.7.1: Uses API v1.25 (too old for Docker 29.x which requires min v1.44) - # - v1.7.2+/latest: Has issues with API negotiation - # Issue tracked for resolution in future release - # To enable: Uncomment service below and run: docker compose up -d watchtower - # - # Watchtower - Automatic container updates - # Monitors and updates Docker containers to latest versions - # Runs daily at 4 AM - watchtower: - image: containrrr/watchtower:latest - container_name: watchtower - restart: unless-stopped - networks: - - homelab-network - volumes: - - /var/run/docker.sock:/var/run/docker.sock - environment: - - DOCKER_API_VERSION=1.52 - - WATCHTOWER_CLEANUP=true - - WATCHTOWER_INCLUDE_RESTARTING=true - - WATCHTOWER_SCHEDULE=0 0 4 * * * # 4 AM daily - - WATCHTOWER_NOTIFICATIONS=shoutrrr - - WATCHTOWER_NOTIFICATION_URL=${WATCHTOWER_NOTIFICATION_URL:-} - labels: - - "homelab.category=infrastructure" - - "homelab.description=Automatic Docker container updates" - - # Dozzle - Real-time Docker log viewer - # Access at: https://dozzle.${DOMAIN} - dozzle: - image: amir20/dozzle:latest - deploy: - resources: - limits: - cpus: '0.50' - memory: 256M - pids: 512 - reservations: - cpus: '0.25' - memory: 128M - container_name: dozzle - restart: unless-stopped - networks: - - homelab-network - - traefik-network - volumes: - - /var/run/docker.sock:/var/run/docker.sock:ro - environment: - - DOZZLE_LEVEL=info - - DOZZLE_TAILSIZE=300 - - DOZZLE_FILTER=status=running - labels: - - "homelab.category=infrastructure" - - "homelab.description=Real-time Docker log viewer" - - "traefik.enable=true" - - "traefik.http.routers.dozzle.rule=Host(`dozzle.${DOMAIN}`)" - - "traefik.http.routers.dozzle.entrypoints=websecure" - - "traefik.http.routers.dozzle.tls=true" - - "traefik.http.routers.dozzle.middlewares=authelia@docker" - - "traefik.http.services.dozzle.loadbalancer.server.port=8080" - - # Docker Proxy - Socket proxy for security - # Used by services that need Docker socket access - dockerproxy: - image: tecnativa/docker-socket-proxy:latest - container_name: dockerproxy - restart: unless-stopped - networks: - - dockerproxy-network - ports: - - "127.0.0.1:2375:2375" - volumes: - - /var/run/docker.sock:/var/run/docker.sock:ro - environment: - - CONTAINERS=1 - - SERVICES=1 - - TASKS=1 - - NETWORKS=1 - - NODES=1 - labels: - - "homelab.category=infrastructure" - - "homelab.description=Docker socket proxy for security" - - # Glances - System monitoring - # Access at: https://glances.${DOMAIN} - glances: - image: nicolargo/glances:latest-full - deploy: - resources: - limits: - cpus: '0.50' - memory: 256M - pids: 512 - reservations: - cpus: '0.25' - memory: 128M - container_name: glances - restart: unless-stopped - networks: - - homelab-network - - traefik-network - pid: host - volumes: - - /var/run/docker.sock:/var/run/docker.sock:ro - - ./glances/config:/glances/conf - environment: - - GLANCES_OPT=-w - labels: - - "homelab.category=infrastructure" - - "homelab.description=System and Docker monitoring" - - "traefik.enable=true" - - "traefik.http.routers.glances.rule=Host(`glances.${DOMAIN}`)" - - "traefik.http.routers.glances.entrypoints=websecure" - - "traefik.http.routers.glances.tls=true" - - "traefik.http.routers.glances.middlewares=authelia@docker" - - "traefik.http.services.glances.loadbalancer.server.port=61208" - - # Code Server - VS Code in browser - # Access at: https://code.${DOMAIN} - code-server: - image: lscr.io/linuxserver/code-server:latest - deploy: - resources: - limits: - cpus: '1.5' - memory: 1G - pids: 2048 - reservations: - cpus: '0.75' - memory: 512M - container_name: code-server - restart: unless-stopped - networks: - - homelab-network - - traefik-network - volumes: - - ./code-server/config:/config - - /opt/stacks:/opt/stacks # Access to all stacks - - /mnt:/mnt:ro # Read-only access to data - environment: - - PUID=${PUID:-1000} - - PGID=${PGID:-1000} - - TZ=${TZ} - - PASSWORD=${CODE_SERVER_PASSWORD} - - SUDO_PASSWORD=${CODE_SERVER_SUDO_PASSWORD} - labels: - - "homelab.category=infrastructure" - - "homelab.description=VS Code in browser" - - "traefik.enable=true" - - "traefik.http.routers.code-server.rule=Host(`code.${DOMAIN}`)" - - "traefik.http.routers.code-server.entrypoints=websecure" - - "traefik.http.routers.code-server.tls.certresolver=letsencrypt" - - "traefik.http.routers.code-server.middlewares=authelia@docker" - - "traefik.http.services.code-server.loadbalancer.server.port=8443" - -networks: - homelab-network: - external: true - traefik-network: - external: true - dockerproxy-network: - external: true diff --git a/docker-compose/media-management.yml b/docker-compose/media-management.yml deleted file mode 100644 index 026655c..0000000 --- a/docker-compose/media-management.yml +++ /dev/null @@ -1,341 +0,0 @@ -# Media Management Services -# Content automation and library management (*arr apps, transcoders, etc.) -# Place in /opt/stacks/media-management/docker-compose.yml - -# Service Access URLs: -# - Sonarr: https://sonarr.${DOMAIN} -# - Radarr: https://radarr.${DOMAIN} -# - Prowlarr: https://prowlarr.${DOMAIN} -# - Readarr: https://readarr.${DOMAIN} -# - Lidarr: https://lidarr.${DOMAIN} -# - LazyLibrarian: https://lazylibrarian.${DOMAIN} -# - Mylar3: https://mylar.${DOMAIN} -# - Jellyseerr: https://jellyseerr.${DOMAIN} -# - Tdarr: https://tdarr.${DOMAIN} -# - Unmanic: https://unmanic.${DOMAIN} - -services: - # Sonarr - TV show automation - # Access at: https://sonarr.yourdomain.duckdns.org - sonarr: - image: linuxserver/sonarr:4.0.0 - container_name: sonarr - restart: unless-stopped - networks: - - media-network - - homelab-network - - traefik-network - volumes: - - ./sonarr/config:/config - - /mnt/media:/media - - /mnt/downloads:/downloads # Large downloads on separate drive - environment: - - PUID=${PUID:-1000} - - PGID=${PGID:-1000} - - TZ=${TZ:-America/New_York} - labels: - - homelab.category=media - - homelab.description=TV show management and automation - # Traefik labels with Authelia - - traefik.enable=true - - traefik.http.routers.sonarr.rule=Host(`sonarr.${DOMAIN}`) - - traefik.http.routers.sonarr.entrypoints=websecure - - traefik.http.routers.sonarr.tls.certresolver=letsencrypt - - traefik.http.routers.sonarr.middlewares=authelia@docker - - traefik.http.services.sonarr.loadbalancer.server.port=8989 - # Radarr - Movie automation - # Access at: https://radarr.yourdomain.duckdns.org - radarr: - image: linuxserver/radarr:5.2.6 - container_name: radarr - restart: unless-stopped - networks: - - media-network - - homelab-network - - traefik-network - volumes: - - ./radarr/config:/config - - /mnt/media:/media - - /mnt/downloads:/downloads # Large downloads on separate drive - environment: - - PUID=${PUID:-1000} - - PGID=${PGID:-1000} - - TZ=${TZ:-America/New_York} - labels: - - homelab.category=media - - homelab.description=Movie management and automation - # Traefik labels with Authelia - - traefik.enable=true - - traefik.http.routers.radarr.rule=Host(`radarr.${DOMAIN}`) - - traefik.http.routers.radarr.entrypoints=websecure - - traefik.http.routers.radarr.tls.certresolver=letsencrypt - - traefik.http.routers.radarr.middlewares=authelia@docker - - traefik.http.services.radarr.loadbalancer.server.port=7878 - # Prowlarr - Indexer manager - # Access at: https://prowlarr.yourdomain.duckdns.org - prowlarr: - image: linuxserver/prowlarr:1.11.4 - container_name: prowlarr - restart: unless-stopped - networks: - - media-network - - homelab-network - - traefik-network - volumes: - - ./prowlarr/config:/config - environment: - - PUID=${PUID:-1000} - - PGID=${PGID:-1000} - - TZ=${TZ:-America/New_York} - labels: - - homelab.category=media - - homelab.description=Indexer manager for Sonarr/Radarr - # Traefik labels with Authelia - - traefik.enable=true - - traefik.http.routers.prowlarr.rule=Host(`prowlarr.${DOMAIN}`) - - traefik.http.routers.prowlarr.entrypoints=websecure - - traefik.http.routers.prowlarr.tls.certresolver=letsencrypt - - traefik.http.routers.prowlarr.middlewares=authelia@docker - - traefik.http.services.prowlarr.loadbalancer.server.port=9696 - # Readarr - Ebook and audiobook management - # Access at: https://readarr.${DOMAIN} - readarr: - image: linuxserver/readarr:0.4.19-nightly - container_name: readarr - restart: unless-stopped - networks: - - media-network - - homelab-network - - traefik-network - volumes: - - ./readarr/config:/config - - /mnt/media/books:/books - - /mnt/downloads:/downloads - environment: - - PUID=${PUID:-1000} - - PGID=${PGID:-1000} - - TZ=${TZ} - labels: - - homelab.category=media - - homelab.description=Ebook and audiobook management - - traefik.enable=true - - traefik.http.routers.readarr.rule=Host(`readarr.${DOMAIN}`) - - traefik.http.routers.readarr.entrypoints=websecure - - traefik.http.routers.readarr.tls.certresolver=letsencrypt - - traefik.http.routers.readarr.middlewares=authelia@docker - - traefik.http.services.readarr.loadbalancer.server.port=8787 - # Lidarr - Music collection manager - # Access at: https://lidarr.${DOMAIN} - lidarr: - image: linuxserver/lidarr:2.0.7 - container_name: lidarr - restart: unless-stopped - networks: - - media-network - - homelab-network - - traefik-network - volumes: - - ./lidarr/config:/config - - /mnt/media/music:/music - - /mnt/downloads:/downloads - environment: - - PUID=${PUID:-1000} - - PGID=${PGID:-1000} - - TZ=${TZ} - labels: - - homelab.category=media - - homelab.description=Music collection manager - - traefik.enable=true - - traefik.http.routers.lidarr.rule=Host(`lidarr.${DOMAIN}`) - - traefik.http.routers.lidarr.entrypoints=websecure - - traefik.http.routers.lidarr.tls.certresolver=letsencrypt - - traefik.http.routers.lidarr.middlewares=authelia@docker - - traefik.http.services.lidarr.loadbalancer.server.port=8686 - # Lazy Librarian - Book manager - # Access at: https://lazylibrarian.${DOMAIN} - lazylibrarian: - image: linuxserver/lazylibrarian:latest - container_name: lazylibrarian - restart: unless-stopped - networks: - - media-network - - homelab-network - - traefik-network - volumes: - - ./lazylibrarian/config:/config - - /mnt/media/books:/books - - /mnt/downloads:/downloads - environment: - - PUID=${PUID:-1000} - - PGID=${PGID:-1000} - - TZ=${TZ} - - DOCKER_MODS=linuxserver/mods:lazylibrarian-ffmpeg - labels: - - homelab.category=media - - homelab.description=Book download automation - - traefik.enable=true - - traefik.http.routers.lazylibrarian.rule=Host(`lazylibrarian.${DOMAIN}`) - - traefik.http.routers.lazylibrarian.entrypoints=websecure - - traefik.http.routers.lazylibrarian.tls.certresolver=letsencrypt - - traefik.http.routers.lazylibrarian.middlewares=authelia@docker - - traefik.http.services.lazylibrarian.loadbalancer.server.port=5299 - # Mylar3 - Comic book manager - # Access at: https://mylar.${DOMAIN} - mylar3: - image: linuxserver/mylar3:latest - container_name: mylar3 - restart: unless-stopped - networks: - - media-network - - homelab-network - - traefik-network - volumes: - - ./mylar3/config:/config - - /mnt/media/comics:/comics - - /mnt/downloads:/downloads - environment: - - PUID=${PUID:-1000} - - PGID=${PGID:-1000} - - TZ=${TZ} - labels: - - homelab.category=media - - homelab.description=Comic book collection manager - - traefik.enable=true - - traefik.http.routers.mylar.rule=Host(`mylar.${DOMAIN}`) - - traefik.http.routers.mylar.entrypoints=websecure - - traefik.http.routers.mylar.tls.certresolver=letsencrypt - - traefik.http.routers.mylar.middlewares=authelia@docker - - traefik.http.services.mylar.loadbalancer.server.port=8090 - # Jellyseerr - Request management for Jellyfin/Plex - # Access at: https://jellyseerr.${DOMAIN} - jellyseerr: - image: fallenbagel/jellyseerr:latest - container_name: jellyseerr - restart: unless-stopped - networks: - - media-network - - homelab-network - - traefik-network - volumes: - - ./jellyseerr/config:/app/config - environment: - - LOG_LEVEL=info - - TZ=${TZ} - labels: - - homelab.category=media - - homelab.description=Media request management - - traefik.enable=true - - traefik.http.routers.jellyseerr.rule=Host(`jellyseerr.${DOMAIN}`) - - traefik.http.routers.jellyseerr.entrypoints=websecure - - traefik.http.routers.jellyseerr.tls.certresolver=letsencrypt - - traefik.http.routers.jellyseerr.middlewares=authelia@docker - - traefik.http.services.jellyseerr.loadbalancer.server.port=5055 - - "x-dockge.url=https://jellyseerr.${DOMAIN}" - - "x-dockge.url=https://jellyseerr.${DOMAIN}" - # FlareSolverr - Cloudflare bypass for Prowlarr - # No web UI - used by Prowlarr - flaresolverr: - image: flaresolverr/flaresolverr:latest - container_name: flaresolverr - restart: unless-stopped - networks: - - media-network - environment: - - LOG_LEVEL=info - - TZ=${TZ} - labels: - - homelab.category=media - - homelab.description=Cloudflare bypass for indexers - # Tdarr Server - Distributed transcoding server - # Access at: https://tdarr.${DOMAIN} - tdarr-server: - image: ghcr.io/haveagitgat/tdarr:latest - container_name: tdarr-server - restart: unless-stopped - networks: - - media-network - - homelab-network - - traefik-network - ports: - - 8266:8266 # Server port - volumes: - - ./tdarr/server:/app/server - - ./tdarr/configs:/app/configs - - ./tdarr/logs:/app/logs - - /mnt/media:/media - - /mnt/tdarr-transcode:/temp # Transcode cache on separate drive - environment: - - PUID=${PUID:-1000} - - PGID=${PGID:-1000} - - TZ=${TZ} - - serverIP=0.0.0.0 - - serverPort=8266 - - webUIPort=8265 - labels: - - homelab.category=media - - homelab.description=Distributed transcoding server - - traefik.enable=true - - traefik.http.routers.tdarr.rule=Host(`tdarr.${DOMAIN}`) - - traefik.http.routers.tdarr.entrypoints=websecure - - traefik.http.routers.tdarr.tls.certresolver=letsencrypt - - traefik.http.routers.tdarr.middlewares=authelia@docker - - traefik.http.services.tdarr.loadbalancer.server.port=8265 - # Tdarr Node - Transcoding worker - # No web UI - controlled by server - tdarr-node: - image: ghcr.io/haveagitgat/tdarr_node:latest - container_name: tdarr-node - restart: unless-stopped - networks: - - media-network - volumes: - - ./tdarr/configs:/app/configs - - ./tdarr/logs:/app/logs - - /mnt/media:/media - - /mnt/tdarr-transcode:/temp - environment: - - PUID=${PUID:-1000} - - PGID=${PGID:-1000} - - TZ=${TZ} - - nodeID=MainNode - - nodeIP=0.0.0.0 - - nodePort=8267 - - serverIP=tdarr-server - - serverPort=8266 - labels: - - homelab.category=media - - homelab.description=Tdarr transcoding worker node - # Unmanic - Another transcoding option - # Access at: https://unmanic.${DOMAIN} - unmanic: - image: josh5/unmanic:latest - container_name: unmanic - restart: unless-stopped - networks: - - media-network - - homelab-network - - traefik-network - volumes: - - ./unmanic/config:/config - - /mnt/media:/library - - /mnt/unmanic-cache:/tmp/unmanic # Transcode cache on separate drive - environment: - - PUID=${PUID:-1000} - - PGID=${PGID:-1000} - - TZ=${TZ} - labels: - - homelab.category=media - - homelab.description=Library optimization and transcoding - - traefik.enable=true - - traefik.http.routers.unmanic.rule=Host(`unmanic.${DOMAIN}`) - - traefik.http.routers.unmanic.entrypoints=websecure - - traefik.http.routers.unmanic.tls.certresolver=letsencrypt - - traefik.http.routers.unmanic.middlewares=authelia@docker - - traefik.http.services.unmanic.loadbalancer.server.port=8888 -networks: - media-network: - external: true - homelab-network: - external: true - traefik-network: - external: true diff --git a/docker-compose/media.yml b/docker-compose/media.yml deleted file mode 100644 index 58e2cce..0000000 --- a/docker-compose/media.yml +++ /dev/null @@ -1,81 +0,0 @@ -# Media Services -# Default Services for media management and streaming -# Place in /opt/stacks/media/docker-compose.yml - - -# Service Access URLs: -# - Jellyfin: https://jellyfin.${DOMAIN} (no SSO - app access) -# - Plex: https://plex.${DOMAIN} (no SSO - app access) -# - qBittorrent: https://qbit.${DOMAIN} (routed through Gluetun VPN) - -services: - # Jellyfin - Open-source media streaming server - # Access at: https://jellyfin.yourdomain.duckdns.org - # NOTE: No Authelia - allows app access from Roku, Fire TV, mobile, etc. - jellyfin: - image: jellyfin/jellyfin:10.8.13 - container_name: jellyfin - restart: unless-stopped - networks: - - media-network - - homelab-network - - traefik-network - volumes: - - ./jellyfin/config:/config - - ./jellyfin/cache:/cache - - /mnt/media:/media:ro # Large media files on separate drive - environment: - - PUID=${PUID:-1000} - - PGID=${PGID:-1000} - - TZ=${TZ:-America/New_York} - # Uncomment for hardware transcoding - # devices: - # - /dev/dri:/dev/dri - labels: - - "homelab.category=media" - - "homelab.description=Open-source media streaming server" - # Traefik labels - NO Authelia for app access - - "traefik.enable=true" - - "traefik.http.routers.jellyfin.rule=Host(`jellyfin.${DOMAIN}`)" - - "traefik.http.routers.jellyfin.entrypoints=websecure" - - "traefik.http.routers.jellyfin.tls=true" - - "traefik.http.routers.jellyfin.tls.certresolver=letsencrypt" - - "traefik.http.services.jellyfin.loadbalancer.server.port=8096" - - "x-dockge.url=https://jellyfin.${DOMAIN}" - - "x-dockge.url=https://jellyfin.${DOMAIN}" - - # Calibre-Web - Ebook reader and server - # Access at: https://calibre.${DOMAIN} - calibre-web: - image: lscr.io/linuxserver/calibre-web:latest - container_name: calibre-web - restart: unless-stopped - networks: - - media-network - - homelab-network - - traefik-network - volumes: - - ./calibre-web/config:/config - - /mnt/media/books:/books - environment: - - PUID=${PUID:-1000} - - PGID=${PGID:-1000} - - TZ=${TZ:-America/New_York} - - DOCKER_MODS=linuxserver/mods:universal-calibre - labels: - - "homelab.category=media" - - "homelab.description=Ebook reader and library management" - - "traefik.enable=true" - - "traefik.http.routers.calibre.rule=Host(`calibre.${DOMAIN}`)" - - "traefik.http.routers.calibre.entrypoints=websecure" - - "traefik.http.routers.calibre.tls.certresolver=letsencrypt" - - "traefik.http.routers.calibre.middlewares=authelia@docker" - - "traefik.http.services.calibre.loadbalancer.server.port=8083" - -networks: - media-network: - driver: bridge - homelab-network: - external: true - traefik-network: - external: true diff --git a/docker-compose/monitoring.yml b/docker-compose/monitoring.yml deleted file mode 100644 index f7eee27..0000000 --- a/docker-compose/monitoring.yml +++ /dev/null @@ -1,227 +0,0 @@ -# Monitoring and Observability Services -# Services for monitoring your homelab infrastructure -# Place in /opt/stacks/monitoring/docker-compose.yml - -# Service Access URLs: -# - Prometheus: http://server-ip:9090 (or configure Traefik) -# - Grafana: http://server-ip:3000 (or configure Traefik) -# - Uptime Kuma: https://status.${DOMAIN} -# - Node Exporter: http://server-ip:9100/metrics -# - cAdvisor: http://server-ip:8082 -# - Loki: http://server-ip:3100 -# NOTE: Prometheus, Grafana, Loki use ports because they need to be accessible to other services -# Add Traefik labels if you want https://prometheus.${DOMAIN} access - -services: - # Prometheus - Metrics collection and storage - # Access at: http://server-ip:9090 - prometheus: - image: prom/prometheus:v2.48.1 - container_name: prometheus - restart: unless-stopped - networks: - - monitoring-network - - homelab-network - - traefik-network - ports: - - "9090:9090" - volumes: - - ./config/prometheus:/etc/prometheus - - prometheus-data:/prometheus - command: - - '--config.file=/etc/prometheus/prometheus.yml' - - '--storage.tsdb.path=/prometheus' - - '--storage.tsdb.retention.time=30d' - - '--web.console.libraries=/etc/prometheus/console_libraries' - - '--web.console.templates=/etc/prometheus/consoles' - - '--web.enable-lifecycle' - user: "${PUID:-1000}:${PGID:-1000}" - labels: - - "homelab.category=monitoring" - - "homelab.description=Metrics collection and time-series database" - - "traefik.enable=true" - - "traefik.http.routers.prometheus.rule=Host(`prometheus.${DOMAIN}`)" - - "traefik.http.routers.prometheus.entrypoints=websecure" - - "traefik.http.routers.prometheus.tls=true" - - "traefik.http.routers.prometheus.tls.certresolver=letsencrypt" - - "traefik.http.routers.prometheus.middlewares=authelia@docker" - - "traefik.http.services.prometheus.loadbalancer.server.port=9090" - - # Grafana - Metrics visualization - # Access at: http://server-ip:3000 - # Default credentials: admin / admin (change on first login) - grafana: - image: grafana/grafana:10.2.3 - container_name: grafana - restart: unless-stopped - networks: - - monitoring-network - - homelab-network - - traefik-network - ports: - - "3000:3000" - volumes: - - grafana-data:/var/lib/grafana - - ./config/grafana/provisioning:/etc/grafana/provisioning - environment: - - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD:-admin} - - GF_USERS_ALLOW_SIGN_UP=false - - GF_SERVER_ROOT_URL=https://grafana.${DOMAIN} - - GF_INSTALL_PLUGINS=grafana-clock-panel,grafana-simple-json-datasource,grafana-piechart-panel - user: "${PUID:-1000}:${PGID:-1000}" - depends_on: - - prometheus - labels: - - "homelab.category=monitoring" - - "homelab.description=Metrics visualization and dashboards" - - "traefik.enable=true" - - "traefik.http.routers.grafana.rule=Host(`grafana.${DOMAIN}`)" - - "traefik.http.routers.grafana.entrypoints=websecure" - - "traefik.http.routers.grafana.tls=true" - - "traefik.http.routers.grafana.tls.certresolver=letsencrypt" - - "traefik.http.routers.grafana.middlewares=authelia@docker" - - "traefik.http.services.grafana.loadbalancer.server.port=3000" - - # Node Exporter - Host metrics exporter - # Metrics at: http://server-ip:9100/metrics - node-exporter: - image: prom/node-exporter:v1.7.0 - container_name: node-exporter - restart: unless-stopped - networks: - - monitoring-network - ports: - - "9100:9100" - volumes: - - /proc:/host/proc:ro - - /sys:/host/sys:ro - - /:/rootfs:ro - command: - - '--path.procfs=/host/proc' - - '--path.rootfs=/rootfs' - - '--path.sysfs=/host/sys' - - '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)' - labels: - - "homelab.category=monitoring" - - "homelab.description=Hardware and OS metrics exporter" - - # cAdvisor - Container metrics exporter - # Access at: http://server-ip:8082 - cadvisor: - image: gcr.io/cadvisor/cadvisor:v0.47.2 - container_name: cadvisor - restart: unless-stopped - networks: - - monitoring-network - - homelab-network - - traefik-network - ports: - - "8082:8080" - volumes: - - /:/rootfs:ro - - /var/run:/var/run:ro - - /sys:/sys:ro - - /var/lib/docker:/var/lib/docker:ro - - /dev/disk:/dev/disk:ro - privileged: true - devices: - - /dev/kmsg - labels: - - "homelab.category=monitoring" - - "homelab.description=Container metrics and performance monitoring" - - "traefik.enable=true" - - "traefik.http.routers.cadvisor.rule=Host(`cadvisor.${DOMAIN}`)" - - "traefik.http.routers.cadvisor.entrypoints=websecure" - - "traefik.http.routers.cadvisor.tls=true" - - "traefik.http.routers.cadvisor.tls.certresolver=letsencrypt" - - "traefik.http.routers.cadvisor.middlewares=authelia@docker" - - "traefik.http.services.cadvisor.loadbalancer.server.port=8080" - - # Uptime Kuma - Uptime monitoring - # Access at: https://uptime-kuma.${DOMAIN} - uptime-kuma: - image: louislam/uptime-kuma:1 - container_name: uptime-kuma - restart: unless-stopped - networks: - - monitoring-network - - homelab-network - - traefik-network - volumes: - - uptime-kuma-data:/app/data - - /var/run/docker.sock:/var/run/docker.sock:ro - labels: - - "homelab.category=monitoring" - - "homelab.description=Service uptime monitoring and alerts" - - "traefik.enable=true" - - "traefik.http.routers.uptime-kuma.rule=Host(`uptime-kuma.${DOMAIN}`)" - - "traefik.http.routers.uptime-kuma.entrypoints=websecure" - - "traefik.http.routers.uptime-kuma.tls=true" - - "traefik.http.routers.uptime-kuma.tls.certresolver=letsencrypt" - - "traefik.http.routers.uptime-kuma.middlewares=authelia@docker" - - "traefik.http.services.uptime-kuma.loadbalancer.server.port=3001" - - # Loki - Log aggregation - # Access at: http://server-ip:3100 - loki: - image: grafana/loki:2.9.3 - container_name: loki - restart: unless-stopped - networks: - - monitoring-network - - homelab-network - - traefik-network - ports: - - "3100:3100" - volumes: - - ./config/loki:/etc/loki - - loki-data:/loki - command: -config.file=/etc/loki/loki-config.yml - user: "${PUID:-1000}:${PGID:-1000}" - labels: - - "homelab.category=monitoring" - - "homelab.description=Log aggregation system" - - "traefik.enable=true" - - "traefik.http.routers.loki.rule=Host(`loki.${DOMAIN}`)" - - "traefik.http.routers.loki.entrypoints=websecure" - - "traefik.http.routers.loki.tls=true" - - "traefik.http.routers.loki.tls.certresolver=letsencrypt" - - "traefik.http.routers.loki.middlewares=authelia@docker" - - "traefik.http.services.loki.loadbalancer.server.port=3100" - - # Promtail - Log shipper for Loki - # Ships Docker container logs to Loki - promtail: - image: grafana/promtail:2.9.3 - container_name: promtail - restart: unless-stopped - networks: - - monitoring-network - volumes: - - ./config/promtail:/etc/promtail - - /var/log:/var/log:ro - - /var/lib/docker/containers:/var/lib/docker/containers:ro - command: -config.file=/etc/promtail/promtail-config.yml - depends_on: - - loki - labels: - - "homelab.category=monitoring" - - "homelab.description=Log collector for Loki" - -volumes: - prometheus-data: - driver: local - grafana-data: - driver: local - uptime-kuma-data: - driver: local - loki-data: - driver: local - -networks: - monitoring-network: - driver: bridge - homelab-network: - external: true - traefik-network: - external: true diff --git a/docker-compose/productivity.yml b/docker-compose/productivity.yml deleted file mode 100644 index 8bb52a2..0000000 --- a/docker-compose/productivity.yml +++ /dev/null @@ -1,337 +0,0 @@ -# Productivity and Content Management Services -# Place in /opt/stacks/productivity/docker-compose.yml - -# Service Access URLs: -# - Nextcloud: https://nextcloud.${DOMAIN} -# - Mealie: https://mealie.${DOMAIN} -# - WordPress: https://blog.${DOMAIN} -# - Gitea: https://git.${DOMAIN} -# - DokuWiki: https://wiki.${DOMAIN} -# - BookStack: https://docs.${DOMAIN} -# - MediaWiki: https://mediawiki.${DOMAIN} - -services: - # Nextcloud - File sync and collaboration - # Access at: https://nextcloud.${DOMAIN} - nextcloud: - image: nextcloud:28 - container_name: nextcloud - restart: unless-stopped - networks: - - homelab-network - - traefik-network - - nextcloud-network - volumes: - - ./nextcloud/html:/var/www/html - - /mnt/nextcloud-data:/var/www/html/data # Large data on separate drive - environment: - - MYSQL_HOST=nextcloud-db - - MYSQL_DATABASE=nextcloud - - MYSQL_USER=nextcloud - - MYSQL_PASSWORD=${NEXTCLOUD_DB_PASSWORD} - - NEXTCLOUD_ADMIN_USER=${NEXTCLOUD_ADMIN_USER:-admin} - - NEXTCLOUD_ADMIN_PASSWORD=${NEXTCLOUD_ADMIN_PASSWORD} - - NEXTCLOUD_TRUSTED_DOMAINS=nextcloud.${DOMAIN} - - TRUSTED_PROXIES=172.18.0.0/16 - - OVERWRITEPROTOCOL=https - - OVERWRITEHOST=nextcloud.${DOMAIN} - depends_on: - - nextcloud-db - labels: - - "homelab.category=productivity" - - "homelab.description=File sync and collaboration" - - "traefik.enable=true" - - "traefik.http.routers.nextcloud.rule=Host(`nextcloud.${DOMAIN}`)" - - "traefik.http.routers.nextcloud.entrypoints=websecure" - - "traefik.http.routers.nextcloud.tls.certresolver=letsencrypt" - - "traefik.http.routers.nextcloud.middlewares=authelia@docker" - - "traefik.http.services.nextcloud.loadbalancer.server.port=80" - - nextcloud-db: - image: mariadb:10.11 - container_name: nextcloud-db - restart: unless-stopped - networks: - - nextcloud-network - volumes: - - nextcloud-db-data:/var/lib/mysql - environment: - - MYSQL_ROOT_PASSWORD=${NEXTCLOUD_DB_ROOT_PASSWORD} - - MYSQL_DATABASE=nextcloud - - MYSQL_USER=nextcloud - - MYSQL_PASSWORD=${NEXTCLOUD_DB_PASSWORD} - command: --transaction-isolation=READ-COMMITTED --log-bin=binlog --binlog-format=ROW - labels: - - "homelab.category=productivity" - - "homelab.description=Nextcloud database" - - # Mealie - Recipe manager - # Access at: https://mealie.${DOMAIN} - mealie: - image: ghcr.io/mealie-recipes/mealie:latest - container_name: mealie - restart: unless-stopped - networks: - - homelab-network - - traefik-network - volumes: - - ./mealie/data:/app/data - environment: - - PUID=${PUID:-1000} - - PGID=${PGID:-1000} - - TZ=${TZ} - - BASE_URL=https://mealie.${DOMAIN} - - DB_ENGINE=sqlite - labels: - - "homelab.category=productivity" - - "homelab.description=Recipe manager and meal planner" - - "traefik.enable=true" - - "traefik.http.routers.mealie.rule=Host(`mealie.${DOMAIN}`)" - - "traefik.http.routers.mealie.entrypoints=websecure" - - "traefik.http.routers.mealie.tls.certresolver=letsencrypt" - - "traefik.http.services.mealie.loadbalancer.server.port=9000" - # No Authelia - family members should access easily - - # WordPress - Blog/website platform - # Access at: https://blog.${DOMAIN} - wordpress: - image: wordpress:latest - container_name: wordpress - restart: unless-stopped - networks: - - homelab-network - - traefik-network - - wordpress-network - volumes: - - ./wordpress/html:/var/www/html - environment: - - WORDPRESS_DB_HOST=wordpress-db - - WORDPRESS_DB_USER=wordpress - - WORDPRESS_DB_PASSWORD=${WORDPRESS_DB_PASSWORD} - - WORDPRESS_DB_NAME=wordpress - depends_on: - - wordpress-db - labels: - - "homelab.category=productivity" - - "homelab.description=Blog and website platform" - - "traefik.enable=true" - - "traefik.http.routers.wordpress.rule=Host(`wordpress.${DOMAIN}`)" - - "traefik.http.routers.wordpress.entrypoints=websecure" - - "traefik.http.routers.wordpress.tls.certresolver=letsencrypt" - - "traefik.http.services.wordpress.loadbalancer.server.port=80" - # No Authelia - public blog - - wordpress-db: - image: mariadb:10.11 - container_name: wordpress-db - restart: unless-stopped - networks: - - wordpress-network - volumes: - - wordpress-db-data:/var/lib/mysql - environment: - - MYSQL_ROOT_PASSWORD=${WORDPRESS_DB_ROOT_PASSWORD} - - MYSQL_DATABASE=wordpress - - MYSQL_USER=wordpress - - MYSQL_PASSWORD=${WORDPRESS_DB_PASSWORD} - labels: - - "homelab.category=productivity" - - "homelab.description=WordPress database" - - # Gitea - Self-hosted Git service - # Access at: https://git.${DOMAIN} - gitea: - image: gitea/gitea:latest - container_name: gitea - restart: unless-stopped - networks: - - homelab-network - - traefik-network - - gitea-network - volumes: - - ./gitea/data:/data - - /etc/timezone:/etc/timezone:ro - - /etc/localtime:/etc/localtime:ro - environment: - - USER_UID=${PUID:-1000} - - USER_GID=${PGID:-1000} - - GITEA__database__DB_TYPE=postgres - - GITEA__database__HOST=gitea-db:5432 - - GITEA__database__NAME=gitea - - GITEA__database__USER=gitea - - GITEA__database__PASSWD=${GITEA_DB_PASSWORD} - depends_on: - - gitea-db - labels: - - "homelab.category=productivity" - - "homelab.description=Self-hosted Git service" - - "traefik.enable=true" - - "traefik.http.routers.gitea.rule=Host(`gitea.${DOMAIN}`)" - - "traefik.http.routers.gitea.entrypoints=websecure" - - "traefik.http.routers.gitea.tls.certresolver=letsencrypt" - - "traefik.http.routers.gitea.middlewares=authelia@docker" - - "traefik.http.services.gitea.loadbalancer.server.port=3000" - - gitea-db: - image: postgres:14-alpine - container_name: gitea-db - restart: unless-stopped - networks: - - gitea-network - volumes: - - gitea-db-data:/var/lib/postgresql/data - environment: - - POSTGRES_USER=gitea - - POSTGRES_PASSWORD=${GITEA_DB_PASSWORD} - - POSTGRES_DB=gitea - labels: - - "homelab.category=productivity" - - "homelab.description=Gitea database" - - # DokuWiki - Wiki without database - # Access at: https://wiki.${DOMAIN} - dokuwiki: - image: lscr.io/linuxserver/dokuwiki:latest - container_name: dokuwiki - restart: unless-stopped - networks: - - homelab-network - - traefik-network - volumes: - - ./dokuwiki/config:/config - environment: - - PUID=${PUID:-1000} - - PGID=${PGID:-1000} - - TZ=${TZ} - labels: - - "homelab.category=productivity" - - "homelab.description=File-based wiki" - - "traefik.enable=true" - - "traefik.http.routers.dokuwiki.rule=Host(`dokuwiki.${DOMAIN}`)" - - "traefik.http.routers.dokuwiki.entrypoints=websecure" - - "traefik.http.routers.dokuwiki.tls.certresolver=letsencrypt" - - "traefik.http.routers.dokuwiki.middlewares=authelia@docker" - - "traefik.http.services.dokuwiki.loadbalancer.server.port=80" - - # BookStack - Documentation platform - # Access at: https://docs.${DOMAIN} - bookstack: - image: lscr.io/linuxserver/bookstack:latest - container_name: bookstack - restart: unless-stopped - networks: - - homelab-network - - traefik-network - - bookstack-network - volumes: - - ./bookstack/config:/config - environment: - - PUID=${PUID:-1000} - - PGID=${PGID:-1000} - - APP_URL=https://bookstack.${DOMAIN} - - DB_HOST=bookstack-db - - DB_PORT=3306 - - DB_DATABASE=bookstack - - DB_USERNAME=bookstack - - DB_PASSWORD=${BOOKSTACK_DB_PASSWORD} - - APP_KEY=base64:NsYD8+8MAvtBhK8xw9p8pxQDy4x8aOQi/78M3CsseAw= - depends_on: - - bookstack-db - labels: - - "homelab.category=productivity" - - "homelab.description=Documentation and wiki platform" - - "traefik.enable=true" - - "traefik.http.routers.bookstack.rule=Host(`bookstack.${DOMAIN}`)" - - "traefik.http.routers.bookstack.entrypoints=websecure" - - "traefik.http.routers.bookstack.tls.certresolver=letsencrypt" - - "traefik.http.routers.bookstack.middlewares=authelia@docker" - - "traefik.http.services.bookstack.loadbalancer.server.port=80" - - "x-dockge.url=https://bookstack.${DOMAIN}" - - "x-dockge.url=https://bookstack.${DOMAIN}" - - bookstack-db: - image: mariadb:10.11 - container_name: bookstack-db - restart: unless-stopped - networks: - - bookstack-network - volumes: - - bookstack-db-data:/var/lib/mysql - environment: - - MYSQL_ROOT_PASSWORD=${BOOKSTACK_DB_ROOT_PASSWORD} - - MYSQL_DATABASE=bookstack - - MYSQL_USER=bookstack - - MYSQL_PASSWORD=${BOOKSTACK_DB_PASSWORD} - labels: - - "homelab.category=productivity" - - "homelab.description=BookStack database" - - # MediaWiki - Wiki platform - # Access at: https://mediawiki.${DOMAIN} - mediawiki: - image: mediawiki:latest - container_name: mediawiki - restart: unless-stopped - networks: - - homelab-network - - traefik-network - - mediawiki-network - volumes: - - ./mediawiki/images:/var/www/html/images - - ./mediawiki/LocalSettings.php:/var/www/html/LocalSettings.php - environment: - - MEDIAWIKI_DB_HOST=mediawiki-db - - MEDIAWIKI_DB_NAME=mediawiki - - MEDIAWIKI_DB_USER=mediawiki - - MEDIAWIKI_DB_PASSWORD=${MEDIAWIKI_DB_PASSWORD} - depends_on: - - mediawiki-db - labels: - - "homelab.category=productivity" - - "homelab.description=MediaWiki platform" - - "traefik.enable=true" - - "traefik.http.routers.mediawiki.rule=Host(`mediawiki.${DOMAIN}`)" - - "traefik.http.routers.mediawiki.entrypoints=websecure" - - "traefik.http.routers.mediawiki.tls.certresolver=letsencrypt" - - "traefik.http.routers.mediawiki.middlewares=authelia@docker" - - "traefik.http.services.mediawiki.loadbalancer.server.port=80" - - mediawiki-db: - image: mariadb:10.11 - container_name: mediawiki-db - restart: unless-stopped - networks: - - mediawiki-network - volumes: - - mediawiki-db-data:/var/lib/mysql - environment: - - MYSQL_ROOT_PASSWORD=${MEDIAWIKI_DB_ROOT_PASSWORD} - - MYSQL_DATABASE=mediawiki - - MYSQL_USER=mediawiki - - MYSQL_PASSWORD=${MEDIAWIKI_DB_PASSWORD} - labels: - - "homelab.category=productivity" - - "homelab.description=MediaWiki database" - -volumes: - nextcloud-db-data: - wordpress-db-data: - gitea-db-data: - bookstack-db-data: - mediawiki-db-data: - -networks: - homelab-network: - external: true - traefik-network: - external: true - nextcloud-network: - driver: bridge - wordpress-network: - driver: bridge - gitea-network: - driver: bridge - bookstack-network: - driver: bridge - mediawiki-network: - driver: bridge diff --git a/docker-compose/utilities.yml b/docker-compose/utilities.yml deleted file mode 100644 index 90a7737..0000000 --- a/docker-compose/utilities.yml +++ /dev/null @@ -1,170 +0,0 @@ -# Backup and Utility Services -# Place in /opt/stacks/utilities/docker-compose.yml - -# Service Access URLs: -# - Backrest: https://backrest.${DOMAIN} -# - Duplicati: https://duplicati.${DOMAIN} -# - Form.io: https://forms.${DOMAIN} -# - Vaultwarden (Bitwarden): https://vault.${DOMAIN} - -services: - # Backrest - Backup solution for restic - # Access at: https://backrest.${DOMAIN} - backrest: - image: garethgeorge/backrest:latest - container_name: backrest - restart: unless-stopped - networks: - - homelab-network - - traefik-network - volumes: - - ./backrest/data:/data - - ./backrest/config:/config - - /opt/stacks:/opt/stacks:ro # Backup source - - /mnt:/mnt:ro # Backup additional drives - - backrest-cache:/cache - environment: - - BACKREST_DATA=/data - - BACKREST_CONFIG=/config/config.json - - TZ=${TZ} - labels: - - "homelab.category=utilities" - - "homelab.description=Backup management with restic" - - "traefik.enable=true" - - "traefik.http.routers.backrest.rule=Host(`backrest.${DOMAIN}`)" - - "traefik.http.routers.backrest.entrypoints=websecure" - - "traefik.http.routers.backrest.tls.certresolver=letsencrypt" - - "traefik.http.routers.backrest.middlewares=authelia@docker" - - "traefik.http.services.backrest.loadbalancer.server.port=9898" - - "x-dockge.url=https://backrest.${DOMAIN}" - - "x-dockge.url=https://backrest.${DOMAIN}" - - # Duplicati - Backup solution - # Access at: https://duplicati.${DOMAIN} - duplicati: - image: lscr.io/linuxserver/duplicati:2.0.7 - container_name: duplicati - restart: unless-stopped - networks: - - homelab-network - - traefik-network - volumes: - - ./duplicati/config:/config - - /opt/stacks:/source/stacks:ro - - /mnt:/source/mnt:ro - - /mnt/backups:/backups - environment: - - PUID=${PUID:-1000} - - PGID=${PGID:-1000} - - TZ=${TZ} - labels: - - "homelab.category=utilities" - - "homelab.description=Backup software with encryption" - - "traefik.enable=true" - - "traefik.http.routers.duplicati.rule=Host(`duplicati.${DOMAIN}`)" - - "traefik.http.routers.duplicati.entrypoints=websecure" - - "traefik.http.routers.duplicati.tls.certresolver=letsencrypt" - - "traefik.http.routers.duplicati.middlewares=authelia@docker" - - "traefik.http.services.duplicati.loadbalancer.server.port=8200" - - # Form.io - Form builder (DISABLED - image not available) - # Uncomment and configure if formio/formio image becomes available - # formio: - # image: formio/formio:latest - # container_name: formio - # restart: unless-stopped - # networks: - # - homelab-network - # - traefik-network - # - formio-network - # environment: - # - MONGO_URL=mongodb://formio-mongo:27017/formio - # - JWT_SECRET=${FORMIO_JWT_SECRET} - # - DB_SECRET=${FORMIO_DB_SECRET} - # depends_on: - # - formio-mongo - # labels: - # - "homelab.category=utilities" - # - "homelab.description=Form builder platform" - # - "traefik.enable=true" - # - "traefik.http.routers.formio.rule=Host(`forms.${DOMAIN}`)" - # - "traefik.http.routers.formio.entrypoints=websecure" - # - "traefik.http.routers.formio.tls.certresolver=letsencrypt" - # - "traefik.http.routers.formio.middlewares=authelia@docker" - # - "traefik.http.services.formio.loadbalancer.server.port=3000" - - # formio-mongo: - # image: mongo:6.0 - # container_name: formio-mongo - # restart: unless-stopped - # networks: - # - formio-network - # volumes: - # - formio-mongo-data:/data/db - # labels: - # - "homelab.category=utilities" - # - "homelab.description=Form.io database" - - # Bitwarden (Vaultwarden) - Password manager - # Access at: https://vault.${DOMAIN} - # Note: SSO disabled for browser extension and mobile app compatibility - vaultwarden: - image: vaultwarden/server:1.30.1 - container_name: vaultwarden - restart: unless-stopped - networks: - - homelab-network - - traefik-network - volumes: - - ./vaultwarden/data:/data - environment: - - DOMAIN=https://vault.${DOMAIN} - - SIGNUPS_ALLOWED=${BITWARDEN_SIGNUPS_ALLOWED:-true} - - INVITATIONS_ALLOWED=${BITWARDEN_INVITATIONS_ALLOWED:-true} - - ADMIN_TOKEN=${BITWARDEN_ADMIN_TOKEN} - # SMTP disabled - uncomment and configure to enable email - # - SMTP_HOST=${SMTP_HOST} - # - SMTP_FROM=${SMTP_FROM} - # - SMTP_PORT=${SMTP_PORT:-587} - # - SMTP_SECURITY=${SMTP_SECURITY:-starttls} - # - SMTP_USERNAME=${SMTP_USERNAME} - # - SMTP_PASSWORD=${SMTP_PASSWORD} - labels: - - "homelab.category=utilities" - - "homelab.description=Self-hosted password manager (Bitwarden)" - - "traefik.enable=true" - - "traefik.http.routers.vaultwarden.rule=Host(`vault.${DOMAIN}`)" - - "traefik.http.routers.vaultwarden.entrypoints=websecure" - - "traefik.http.routers.vaultwarden.tls=true" - - "traefik.http.routers.vaultwarden.tls.certresolver=letsencrypt" - # SSO disabled for browser extension and mobile app compatibility - # - "traefik.http.routers.vaultwarden.middlewares=authelia@docker" - - "traefik.http.services.vaultwarden.loadbalancer.server.port=80" - - # Authelia Redis - Session storage for Authelia - # No web UI - backend service - authelia-redis: - image: redis:7-alpine - container_name: authelia-redis - restart: unless-stopped - networks: - - homelab-network - volumes: - - authelia-redis-data:/data - command: redis-server --save 60 1 --loglevel warning - labels: - - "homelab.category=utilities" - - "homelab.description=Session storage for Authelia" - -volumes: - backrest-cache: - formio-mongo-data: - authelia-redis-data: - -networks: - homelab-network: - external: true - traefik-network: - external: true - formio-network: - driver: bridge diff --git a/docs/manual-setup.md b/docs/manual-setup.md index 1fbca64..82d3325 100644 --- a/docs/manual-setup.md +++ b/docs/manual-setup.md @@ -114,7 +114,7 @@ users: ```bash # Deploy core infrastructure sudo mkdir -p /opt/stacks/core -cp docker-compose/core.yml /opt/stacks/core/docker-compose.yml +cp docker-compose/core/docker-compose.yml /opt/stacks/core/docker-compose.yml cp -r config-templates/traefik /opt/stacks/core/ cp .env /opt/stacks/core/ @@ -129,7 +129,7 @@ docker compose up -d ```bash sudo mkdir -p /opt/stacks/infrastructure -cp docker-compose/infrastructure.yml /opt/stacks/infrastructure/docker-compose.yml +cp docker-compose/infrastructure/docker-compose.yml /opt/stacks/infrastructure/docker-compose.yml cp .env /opt/stacks/infrastructure/ cd /opt/stacks/infrastructure docker compose up -d @@ -139,7 +139,7 @@ docker compose up -d ```bash sudo mkdir -p /opt/stacks/dashboards -cp docker-compose/dashboards.yml /opt/stacks/dashboards/docker-compose.yml +cp docker-compose/dashboards/docker-compose.yml /opt/stacks/dashboards/docker-compose.yml cp -r config-templates/homepage /opt/stacks/dashboards/ cp .env /opt/stacks/dashboards/ diff --git a/docs/quick-reference.md b/docs/quick-reference.md index f798d0d..7768d81 100644 --- a/docs/quick-reference.md +++ b/docs/quick-reference.md @@ -495,7 +495,7 @@ deploy: ### Create a new stack 1. Create directory: `mkdir /opt/stacks/new-stack` -2. Copy compose file: `cp docker-compose/template.yml /opt/stacks/new-stack/docker-compose.yml` +2. Copy compose file: `cp docker-compose/core/docker-compose.yml /opt/stacks/new-stack/docker-compose.yml` 3. Copy env: `cp .env /opt/stacks/new-stack/` 4. Edit configuration 5. Deploy: `cd /opt/stacks/new-stack && docker compose up -d` @@ -542,7 +542,7 @@ nano .env # Deploy core only mkdir -p /opt/stacks/core -cp docker-compose/core.yml /opt/stacks/core/docker-compose.yml +cp docker-compose/core/docker-compose.yml /opt/stacks/core/docker-compose.yml cp -r config-templates/traefik /opt/stacks/core/ cp -r config-templates/authelia /opt/stacks/core/ cp .env /opt/stacks/core/ @@ -554,9 +554,9 @@ cd /opt/stacks/core && docker compose up -d # After core is running, deploy all stacks # Use Dockge UI at https://dockge.yourdomain.duckdns.org # Or deploy manually: -docker compose -f docker-compose/infrastructure.yml up -d -docker compose -f docker-compose/dashboards.yml up -d -docker compose -f docker-compose/media.yml up -d +cd /opt/stacks/infrastructure && docker compose up -d +cd /opt/stacks/dashboards && docker compose up -d +cd /opt/stacks/media && docker compose up -d # etc. ``` diff --git a/scripts/deploy-homelab.sh b/scripts/deploy-homelab.sh index fbe98fa..bcfdc4e 100755 --- a/scripts/deploy-homelab.sh +++ b/scripts/deploy-homelab.sh @@ -111,7 +111,7 @@ if [ -f "/opt/stacks/core/docker-compose.yml" ]; then log_info "Creating backup: docker-compose.yml.backup.$(date +%Y%m%d_%H%M%S)" cp /opt/stacks/core/docker-compose.yml /opt/stacks/core/docker-compose.yml.backup.$(date +%Y%m%d_%H%M%S) fi -cp "$REPO_DIR/docker-compose/core.yml" /opt/stacks/core/docker-compose.yml +cp "$REPO_DIR/docker-compose/core/docker-compose.yml" /opt/stacks/core/docker-compose.yml if [ -d "/opt/stacks/core/traefik" ]; then log_warning "Traefik configuration already exists in /opt/stacks/core/" @@ -178,7 +178,7 @@ log_info " - Docker Proxy (Security)" echo "" # Copy infrastructure stack -cp "$REPO_DIR/docker-compose/infrastructure.yml" /opt/stacks/infrastructure/docker-compose.yml +cp "$REPO_DIR/docker-compose/infrastructure/docker-compose.yml" /opt/stacks/infrastructure/docker-compose.yml cp "$REPO_DIR/.env" /opt/stacks/infrastructure/.env # Deploy infrastructure stack