- Added ARCANE_ENCRYPTION_KEY and ARCANE_JWT_SECRET to .env.example - Created deploy_arcane() function in ez-homelab.sh - Auto-generate Arcane secrets after Authelia secrets - Deploy Arcane in both Option 2 (Core Server) and Option 3 (Additional Server) - Added Arcane docker-compose.yml configuration
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