# 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 # Service Access URLs: # - DuckDNS: No web UI (updates IP automatically) # - Traefik: https://traefik.${DOMAIN} # - Authelia: https://auth.${DOMAIN} 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: - ./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 - ./traefik/traefik.yml:/traefik.yml:ro - ./traefik/dynamic:/dynamic:ro - ./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.tls.domains[0].main=${DOMAIN}" - "traefik.http.routers.traefik.tls.domains[0].sans=*.${DOMAIN}" - "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: - ./authelia/configuration.yml:/config/configuration.yml:ro - ./authelia/users_database.yml:/config/users_database.yml - authelia-data:/data environment: - TZ=${TZ} - AUTHELIA_JWT_SECRET=${AUTHELIA_JWT_SECRET} - AUTHELIA_SESSION_SECRET=${AUTHELIA_SESSION_SECRET} - AUTHELIA_STORAGE_ENCRYPTION_KEY=${AUTHELIA_STORAGE_ENCRYPTION_KEY} labels: - "traefik.enable=true" - "traefik.http.routers.authelia.rule=Host(`auth.${DOMAIN}`)" - "traefik.http.routers.authelia.entrypoints=websecure" - "traefik.http.routers.authelia.tls=true" - "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 volumes: authelia-data: driver: local networks: traefik-network: external: true