Scale-to-Zero with Sablier¶
This guide explains how to enable automatic scale-to-zero for applications in the homelab. Apps will automatically shut down after a period of inactivity and start back up when someone visits them.
How It Works¶
- Idle State: App runs with 0 replicas (no resources used)
- User Visits: Sablier shows a friendly "Starting Up" page
- Auto Scale-Up: Sablier scales the deployment to 1 replica
- Ready: Once the pod is healthy, traffic flows to the app
- Auto Scale-Down: After 30 minutes of no activity, scales back to 0
Components¶
- Sablier Server (
sabliernamespace): Manages scaling and sessions - Traefik Plugin: Shows the loading page and triggers scale-up
- Middleware: Configured per-app to connect Traefik to Sablier
Quick Setup for a New App¶
Step 1: Add Labels to Your Deployment¶
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
namespace: myapp
labels:
# Enable Sablier for this deployment
sablier.enable: "true"
sablier.group: "myapp" # Must match middleware group
spec:
# Start scaled to 0
replicas: 0
# ... rest of deployment spec
template:
spec:
containers:
- name: myapp
# IMPORTANT: Add a readiness probe so Sablier knows when app is ready
readinessProbe:
httpGet:
path: /
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
Step 2: Create a Sablier Middleware¶
Create middleware.yaml in your app's folder:
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: myapp-sablier
namespace: myapp
spec:
plugin:
sablier:
sablierUrl: http://sablier-sablier.sablier.svc.cluster.local:10000
group: myapp # Must match deployment label sablier.group
sessionDuration: 30m # Time before auto scale-down
dynamic:
displayName: "My App - Starting Up" # Shown on loading page
showDetails: true
theme: ghost # Options: ghost, shuffle, hacker-terminal, matrix
refreshFrequency: 3s
Step 3: Add Middleware to Ingress¶
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp
namespace: myapp
annotations:
traefik.ingress.kubernetes.io/router.middlewares: myapp-myapp-sablier@kubernetescrd
spec:
# ... ingress rules
Middleware reference format: <namespace>-<middleware-name>@kubernetescrd
Step 4: Update Kustomization¶
Add the middleware to your kustomization.yaml:
resources:
- namespace.yaml
- deployment.yaml
- service.yaml
- ingress.yaml
- middleware.yaml # Add this
Step 5: Disable Gatus Checks (Optional)¶
If you have Gatus monitoring, disable checks for scale-to-zero apps:
- Internal checks: Will fail when scaled down (bypasses Sablier)
- External checks: Will trigger scale-up every check interval
Comment out both in infrastructure/base/gatus/release.yaml.
Theme Options¶
| Theme | Description | Best For |
|---|---|---|
ghost | Clean, minimal white design | Family/general users |
shuffle | Animated card shuffle | Fun, playful apps |
hacker-terminal | Green terminal style | Technical users |
matrix | Matrix rain effect | Fun, technical |
Configuration Options¶
| Option | Description | Default |
|---|---|---|
sablierUrl | Sablier API endpoint | Required |
group | Group name matching deployment label | Required |
sessionDuration | Time before auto scale-down | 30m |
dynamic.displayName | Title shown on loading page | Middleware name |
dynamic.showDetails | Show scaling progress details | true |
dynamic.theme | Loading page theme | hacker-terminal |
dynamic.refreshFrequency | How often page checks status | 5s |
GitOps Considerations¶
Since Flux manages deployments:
- Keep
replicas: 0in your deployment.yaml - Sablier handles scaling - Flux won't fight Sablier because Sablier only scales up temporarily
- On next Flux reconciliation, it will scale back to 0 (which is fine)
Troubleshooting¶
App won't scale up¶
- Check Sablier logs:
kubectl logs -n sablier deployment/sablier-sablier - Verify deployment has correct labels:
sablier.enable: "true"andsablier.group - Check middleware group matches deployment label
Loading page shows but app never becomes ready¶
- Check pod logs:
kubectl logs -n <namespace> deployment/<name> - Verify readiness probe is configured and passing
- Check if pod is stuck in CrashLoopBackOff
App immediately scales back down¶
- Check for health checks hitting the endpoint (Gatus, uptime monitors)
- Session duration might be too short
404 when scaled to 0¶
- Verify Traefik has
allowEmptyServices: truein config - Check ingress has correct middleware annotation
Example: BentoPDF¶
See apps/base/bento/ for a complete working example:
deployment.yaml- Has Sablier labels andreplicas: 0middleware.yaml- Sablier plugin configurationingress.yaml- References the middleware
Infrastructure¶
The Sablier infrastructure is in infrastructure/base/sablier/:
- Helm release deploys Sablier server
- Traefik config in
infrastructure/base/controllers/traefik/traefik-config.yamlenables the plugin
experimental:
plugins:
sablier:
moduleName: github.com/sablierapp/sablier-traefik-plugin
version: v1.1.0