- Added STACKS_DIR to dashboards/.env.example (needed for homepage volume mount) - Added HOMEPAGE_VAR_TITLE to dashboards/.env.example - Added CODE_SERVER_PASSWORD and CODE_SERVER_SUDO_PASSWORD to infrastructure/.env.example These variables are required by the docker-compose files but were missing from the .env.example files, causing Docker Compose to fail with 'variable is not set' errors.
Docker Compose Stacks
This directory contains Docker Compose templates for managing your homelab services. Each stack is organized in its own folder for better organization and maintainability.
Structure
docker-compose/
├── core/ # Core infrastructure (MUST DEPLOY FIRST)
│ ├── docker-compose.yml
│ ├── authelia/ # SSO configuration
│ ├── duckdns/ # DNS configuration
│ └── traefik/ # Reverse proxy configuration
│ └── dynamic/ # External routing YAML files (multi-server)
├── sablier/ # Lazy loading service (per-server)
├── dockge/ # Docker management web UI
├── infrastructure/ # Additional infrastructure (Pi-hole, etc.)
├── dashboards/ # Dashboard services (Homepage, Homarr)
├── media/ # Media services (Plex, Jellyfin, etc.)
├── media-management/ # *arr services (Sonarr, Radarr, etc.)
├── monitoring/ # Observability stack (Prometheus, Grafana, etc.)
├── homeassistant/ # Home Assistant stack
├── productivity/ # Productivity tools (Nextcloud, Gitea, etc.)
├── utilities/ # Utility services (Duplicati, FreshRSS, etc.)
├── wikis/ # Mediawiki, Dokuwiki, Bookstacks
└── vpn/ # VPN services (Gluetun, qBittorrent)
Multi-Server Architecture
EZ-Homelab supports two deployment models:
Single Server:
- Core + all other stacks on one machine
- Simplest setup for beginners
Multi-Server:
- Core Server: DuckDNS, Traefik (multi-provider), Authelia
- Remote Servers: Traefik (local-only), Sablier (local-only), application services
- All services accessed through unified domain
See docs/Ondemand-Remote-Services.md for multi-server setup.
Deployment
Use the unified setup script:
cd ~/EZ-Homelab
./scripts/ez-homelab.sh
Single Server Traefik service labels
services:
myservice:
labels:
# TRAEFIK CONFIGURATION
# ==========================================
# Service metadata
- "com.centurylinklabs.watchtower.enable=true"
- "homelab.category=category-name"
- "homelab.description=Brief service description"
# Traefik labels
- "traefik.enable=true"
# Router configuration
- "traefik.http.routers.myservice.rule=Host(`myservice.${DOMAIN}`)"
- "traefik.http.routers.myservice.entrypoints=websecure"
- "traefik.http.routers.myservice.tls.certresolver=letsencrypt"
- "traefik.http.routers.myservice.middlewares=authelia@docker" # SSO (remove to disable)
# Service configuration
- "traefik.http.services.myservice.loadbalancer.server.port=8080"
# Sablier configuration (lazy loading)
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-myservice"
- "sablier.start-on-demand=true"
Multi-Server Traefik
On Core Server
On Remote Server
Disabling SSO (Media Servers)
Remove or comment the authelia middleware line:
# SSO enabled (default):
- "traefik.http.routers.myservice.middlewares=authelia@docker"
# SSO disabled (for Plex, Jellyfin, etc.):
# - "traefik.http.routers.myservice.middlewares=authelia@docker"
Disabling Lazy Loading (Always-On Services)
Remove Sablier labels and use restart: unless-stopped:
services:
myservice:
restart: unless-stopped # Always running
# No sablier labels
Best Practices
- Pin Versions: Always specify image versions (e.g.,
nginx:1.25.3notnginx:latest) - Use Labels: Add labels for organization and documentation
- Health Checks: Define health checks for critical services
- Resource Limits: Set memory and CPU limits for resource-intensive services
- Logging: Configure log rotation to prevent disk space issues
- Restart Policies: Use
unless-stoppedfor most services - Comments: Document non-obvious configurations
Template
When creating a new service, use this template:
services:
service-name:
image: vendor/image:version
container_name: service-name
restart: unless-stopped
networks:
- homelab-network
- traefik-network
ports:
- "host_port:container_port"
volumes:
- ./config/service-name:/config
- service-data:/data
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:port/health"]
interval: 30s
timeout: 10s
retries: 3
labels:
- "homelab.category=category"
- "homelab.description=Service description"
volumes:
service-data:
driver: local
networks:
homelab-network:
external: true