Introduce multi-server architecture documentation and reorganize README content. Top-level README now documents Core vs Remote server roles, links to local docs instead of wiki pages, and highlights Traefik/Sablier multi-server behavior. docker-compose/README.md was rewritten to be a template-style reference with single- and multi-server deployment guidance, Traefik label examples, and sablier usage; dockge README was moved into docker-compose/dockge/. docker-compose/core/README.md was updated to describe core responsibilities, shared CA artifacts, and startup order for multi-server deployments. Several obsolete/duplicated docs and action reports were removed and a new multi-server deployment doc was added to centralize on-demand/remote service guidance. Overall this cleans up legacy docs and documents the multi-server workflow and TLS/shared-CA requirements.
16 KiB
Sablier - Lazy Loading Service
Table of Contents
- Overview
- What is Sablier?
- Why Use Sablier?
- How It Works
- Configuration in AI-Homelab
- Official Resources
- Educational Resources
- Docker Configuration
- Using Sablier
- Advanced Topics
- Troubleshooting
Overview
Category: Resource Management
Docker Image: acouvreur/sablier
Default Stack: sablier (separate stack, deployed on each server)
Web UI: https://sablier.${DOMAIN} (on core server)
Authentication: Protected by Authelia (SSO)
Purpose: On-demand container startup and resource management
Multi-Server Note: Each server runs its own Sablier instance that only manages local containers. This eliminates the need for remote Docker API connections and creates a more resilient architecture.
What is Sablier?
Sablier is a lightweight service that enables lazy loading for Docker containers. It automatically starts containers when they're accessed through Traefik and stops them after a period of inactivity, helping to conserve system resources and reduce power consumption.
In EZ-Homelab's multi-server architecture, each server runs its own Sablier instance managing only local containers, providing:
- Decentralized Control: No single point of failure
- Simplified Networking: No remote Docker API connections needed
- Better Security: Each Sablier only accesses local Docker socket
- Independent Operation: Remote servers function even if core server is down
Key Features
- On-Demand Startup: Containers start automatically when accessed
- Automatic Shutdown: Containers stop after configurable inactivity periods
- Traefik Integration: Works seamlessly with Traefik reverse proxy
- Resource Conservation: Reduces memory and CPU usage for unused services
- Group Management: Related services can be managed as groups
- Health Checks: Waits for services to be ready before forwarding traffic
- Minimal Overhead: Lightweight with low resource requirements
Why Use Sablier?
- Resource Efficiency: Save memory and CPU by only running services when needed
- Power Savings: Reduce power consumption on always-on systems
- Faster Boot: Services start quickly when accessed vs. waiting for full system startup
- Scalability: Handle more services than would fit in memory simultaneously
- Cost Effective: Lower resource requirements mean smaller/fewer servers needed
- Environmental: Reduce energy consumption and carbon footprint
How It Works
User Request → Traefik → Sablier Check → Container Start → Health Check → Forward Traffic
↓
Container Stop (after timeout)
When a request comes in for a service with Sablier enabled:
- Route Detection: Sablier monitors Traefik routes for configured services
- Container Check: Verifies if the target container is running
- Startup Process: If not running, starts the container via Docker API
- Health Verification: Waits for the service to report healthy
- Traffic Forwarding: Routes traffic to the now-running service
- Timeout Monitoring: Tracks inactivity and stops containers after timeout
Configuration in AI-Homelab
Sablier is deployed as a separate stack (/opt/stacks/sablier/) on each server and requires no additional configuration for basic operation. It automatically discovers services with the appropriate labels.
Deployment Location
Core Server: /opt/stacks/sablier/docker-compose.yml
Remote Servers: /opt/stacks/sablier/docker-compose.yml
Each Sablier instance:
- Runs independently on its server
- Connects only to local Docker socket (
/var/run/docker.sock) - Manages containers on the same server only
- Has its own web dashboard (if enabled)
Service Integration
Add these labels to any service that should use lazy loading:
Local Service (same server as Sablier):
services:
myservice:
# ... other configuration ...
labels:
- "sablier.enable=true"
- "sablier.group=${SERVER_HOSTNAME}-myservice" # Include server hostname
- "sablier.start-on-demand=true"
- "traefik.enable=true"
- "traefik.http.routers.myservice.rule=Host(`myservice.${DOMAIN}`)"
# ... other Traefik labels ...
Note on Group Naming: Always prefix group names with ${SERVER_HOSTNAME} to avoid conflicts between servers:
- Core server:
core-myservice - Remote Pi:
pi-myservice - Remote NAS:
nas-myservice
Advanced Configuration
For services requiring custom timeouts or group management:
labels:
- "sablier.enable=true"
- "sablier.group=media-services" # Group name for related services
- "sablier.timeout=300" # 5 minutes inactivity timeout (default: 300)
- "sablier.theme=dark" # Optional: theme for Sablier UI (if used)
Official Resources
- GitHub Repository: https://github.com/sablierapp/sablier
- Docker Hub: https://hub.docker.com/r/sablierapp/sablier
- Documentation: https://sablierapp.github.io/sablier/
Educational Resources
- Traefik Integration: https://doc.traefik.io/traefik/middlewares/http/forwardauth/
- Docker Lazy Loading: Search for "docker lazy loading" or "container on-demand"
- Resource Management: Linux container resource management best practices
Docker Configuration
Environment Variables
| Variable | Description | Default | Required |
|---|---|---|---|
SABLIER_PROVIDER |
Container runtime provider | docker |
Yes |
SABLIER_DOCKER_API_VERSION |
Docker API version | 1.53 |
No |
SABLIER_DOCKER_NETWORK |
Docker network for containers | traefik-network |
Yes |
SABLIER_LOG_LEVEL |
Logging level (debug, info, warn, error) | debug |
No |
DOCKER_HOST |
Docker socket endpoint | tcp://docker-proxy:2375 |
Yes |
Ports
- 10000 - Sablier API endpoint (internal use only)
Volumes
None required - Sablier communicates with Docker via API
Networks
- traefik-network - Required for communication with Traefik
- homelab-network - Required for Docker API access
Using Sablier
Basic Usage
- Enable on Service: Add
sablier.enable=truelabel to any service - Access Service: Navigate to the service URL in your browser
- Automatic Startup: Sablier detects the request and starts the container
- Wait for Ready: Service starts and health checks pass
- Use Service: Container is now running and accessible
- Automatic Shutdown: Container stops after 5 minutes of inactivity
Monitoring Lazy Loading
Check which services are managed by Sablier:
# View all containers with Sablier labels
docker ps --filter "label=sablier.enable=true" --format "table {{.Names}}\t{{.Status}}"
# Check Sablier logs
docker logs sablier
# View Traefik routes that trigger lazy loading
docker logs traefik | grep sablier
Service Groups
Group related services that should start/stop together:
# Database and web app in same group
services:
myapp:
labels:
- "sablier.enable=true"
- "sablier.group=myapp-stack"
myapp-db:
labels:
- "sablier.enable=true"
- "sablier.group=myapp-stack"
Custom Timeouts
Set different inactivity timeouts per service:
labels:
- "sablier.enable=true"
- "sablier.timeout=600" # 10 minutes
Advanced Topics
Performance Considerations
- Startup Time: Services take longer to respond on first access
- Resource Spikes: Multiple services starting simultaneously can cause load
- Health Checks: Ensure services have proper health checks for reliable startup
Troubleshooting Startup Issues
- Container Won't Start: Check Docker logs for the failing container
- Health Check Fails: Verify service health endpoints are working
- Network Issues: Ensure containers are on the correct Docker network
Integration with Monitoring
Sablier works with existing monitoring:
- Prometheus: Can monitor Sablier API metrics
- Grafana: Visualize container start/stop events
- Dozzle: View logs from lazy-loaded containers
Troubleshooting
Service Won't Start Automatically
Symptoms: Accessing service URL shows connection error
Solutions:
# Check if Sablier is running
docker ps | grep sablier
# Verify service has correct labels
docker inspect container-name | grep sablier
# Check Sablier logs
docker logs sablier
# Test manual container start
docker start container-name
Containers Not Stopping
Symptoms: Containers remain running after inactivity timeout
Solutions:
# Check timeout configuration
docker inspect container-name | grep sablier.timeout
# Verify Sablier has access to Docker API
docker exec sablier curl -f http://docker-proxy:2375/_ping
# Check for active connections
netstat -tlnp | grep :port
Traefik Routing Issues
Symptoms: Service accessible but Sablier not triggering
Solutions:
# Verify Traefik labels
docker inspect container-name | grep traefik
# Check Traefik configuration
docker logs traefik | grep "Creating router"
# Test direct access (bypass Sablier)
curl http://container-name:port/health
Common Issues
Issue: Services start but are not accessible
Fix: Ensure services are on the traefik-network
Issue: Sablier can't connect to Docker API
Fix: Verify DOCKER_HOST environment variable and network connectivity
Issue: Containers start but health checks fail Fix: Add proper health checks to service configurations
Issue: High resource usage during startup Fix: Stagger service startups or increase system resources
Performance Tuning
- Increase Timeouts: For services that need longer inactivity periods
- Group Services: Related services can share startup/shutdown cycles
- Monitor Resources: Use Glances or Prometheus to track resource usage
- Optimize Health Checks: Ensure health checks are fast and reliable
Getting Help
- GitHub Issues: https://github.com/sablierapp/sablier/issues
- Community: Check Traefik and Docker forums for lazy loading discussions
- Logs: Enable debug logging with
SABLIER_LOG_LEVEL=debug- "sablier.start-on-demand=true" # Enable lazy loading
### Traefik Middleware
Configure Sablier middleware in Traefik dynamic configuration:
```yaml
http:
middlewares:
sablier-service:
plugin:
sablier:
sablierUrl: http://sablier-service:10000
group: core-service-name
sessionDuration: 2m # How long to keep service running after access
ignoreUserAgent: curl # Don't start service for curl requests
dynamic:
displayName: Service Name
theme: ghost
show-details-by-default: true
Examples
Basic Service with Lazy Loading
services:
my-service:
image: my-service:latest
container_name: my-service
restart: "no" # Important: Must be "no" for Sablier to control start/stop
networks:
- traefik-network
labels:
- "traefik.enable=true"
- "traefik.http.routers.my-service.rule=Host(`my-service.${DOMAIN}`)"
- "traefik.http.routers.my-service.entrypoints=websecure"
- "traefik.http.routers.my-service.tls.certresolver=letsencrypt"
- "traefik.http.routers.my-service.middlewares=authelia@docker"
- "traefik.http.services.my-service.loadbalancer.server.port=8080"
# Sablier lazy loading
- "sablier.enable=true"
- "sablier.group=core-my-service"
- "sablier.start-on-demand=true"
Remote Service Proxy
For services on remote servers, configure Traefik routes with Sablier middleware:
# In /opt/stacks/core/traefik/dynamic/remote-services.yml
http:
routers:
remote-service:
rule: "Host(`remote-service.${DOMAIN}`)"
entryPoints:
- websecure
service: remote-service
tls:
certResolver: letsencrypt
middlewares:
- sablier-remote-service@file
services:
remote-service:
loadBalancer:
servers:
- url: "http://remote-server-ip:port"
middlewares:
sablier-remote-service:
plugin:
sablier:
sablierUrl: http://sablier-service:10000
group: remote-server-group
sessionDuration: 5m
displayName: Remote Service
Troubleshooting
Service Won't Start
Check Sablier logs:
cd /opt/stacks/core
docker compose logs sablier-service
Verify container permissions:
# Check if Sablier can access Docker API
docker exec sablier-service curl -f http://localhost:10000/health
Services Not Starting on Demand
Check Traefik middleware configuration:
# Verify middleware is loaded
docker logs traefik | grep sablier
Check service labels:
# Verify Sablier labels are present
docker inspect service-name | grep sablier
Services Stop Too Quickly
Increase session duration:
middlewares:
sablier-service:
plugin:
sablier:
sessionDuration: 10m # Increase from default
Performance Issues
Check resource usage:
docker stats sablier-service
Monitor Docker API calls:
docker logs sablier-service | grep "API call"
Best Practices
Resource Management
- Use lazy loading for services that aren't accessed frequently
- Set appropriate session durations based on usage patterns
- Monitor resource usage to ensure adequate system capacity
Configuration
- Always set
restart: "no"for Sablier-managed services to allow full lifecycle control - Group related services together for coordinated startup
- Use descriptive display names for the loading page
- Configure appropriate timeouts for your use case
Security
- Sablier runs with Docker API access - ensure proper network isolation
- Use Docker socket proxy for additional security
- Monitor Sablier logs for unauthorized access attempts
Integration with Other Services
Homepage Dashboard
Add Sablier status to Homepage:
# In homepage config
- Core Infrastructure:
- Sablier:
icon: docker.png
href: http://sablier-service:10000
description: Lazy loading service
widget:
type: iframe
url: http://sablier-service:10000
Monitoring
Monitor Sablier with Prometheus metrics (if available) or basic health checks:
# Health check
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:10000/health"]
interval: 30s
timeout: 10s
retries: 3
Advanced Configuration
Custom Themes
Sablier supports different loading page themes:
dynamic:
displayName: My Service
theme: ghost # Options: ghost, hacker, ocean, etc.
show-details-by-default: true
Group Management
Services can be grouped for coordinated startup:
# All services in the same group start together
labels:
- "sablier.group=media-stack"
- "sablier.enable=true"
- "sablier.start-on-demand=true"
API Access
Sablier provides a REST API for programmatic control:
# Get service status
curl http://sablier-service:10000/api/groups
# Start a service group
curl -X POST http://sablier-service:10000/api/groups/media-stack/start
# Stop a service group
curl -X POST http://sablier-service:10000/api/groups/media-stack/stop
Migration from Manual Management
When adding Sablier to existing services:
- Change restart policy to
"no"in the compose file (critical for Sablier control) - Add Sablier labels to the service compose file
- Configure Traefik middleware for the service
- Stop the service initially (let Sablier manage it)
- Test access - service should start automatically
- Monitor logs to ensure proper operation
Important
: Services managed by Sablier must have
restart: "no"to allow Sablier full control over container lifecycle. Do not useunless-stopped,always, oron-failurerestart policies.
Related Documentation
- Traefik Documentation - Reverse proxy configuration
- Authelia Documentation - SSO authentication
- On-Demand Remote Services - Remote service setup guide