Sablier: Docker-Container bei Bedarf starten und stoppen
Sablier stoppt selten genutzte Docker-Container nach einer Leerlaufzeit und startet sie beim nächsten Aufruf automatisch. Die Anleitung richtet Sablier 1.19.1 mit Traefik per Docker Compose ein, zeigt Warteseite, Blocking-API, Sicherung, Wiederherstellung, Update und typische Fehler aus dem Labortest.
Geprüft am 31.10.2026 · für Sablier 1.19.1
Mit KI erstellt – redaktionelle Prüfung ausstehend
WerbelinksMit * markierte Links sind Werbelinks: Bei einem Kauf erhalten wir eine Provision, der Preis bleibt gleich. Als Amazon-Partner verdiene ich an qualifizierten Verkäufen. Mehr dazu

Viele selbst gehostete Dienste werden nur ab und zu gebraucht: ein Wiki für die Quartalsplanung, eine Testinstanz, ein Dashboard für den Monatsabschluss. Trotzdem belegen sie rund um die Uhr Arbeitsspeicher. Sablier stoppt solche Container nach einer einstellbaren Leerlaufzeit und startet sie automatisch, sobald wieder jemand die Adresse aufruft. Der Reverse Proxy zeigt in der Zwischenzeit eine Warteseite oder hält die Anfrage fest, bis der Dienst bereit ist.
Diese Anleitung richtet Sablier 1.19.1 mit dem Docker-Provider und dem Traefik-Plugin per Docker Compose ein. Alle Befehle, Ausgaben und Fehlermeldungen stammen aus einem Labortest vom 31.10.2026, inklusive Update von 1.18.0, Sicherung, Wiederherstellung nach Totalverlust und provozierten Fehlern.
Voraussetzungen
Sablier selbst ist sparsam: Im Test belegte der Sablier-Container rund 12 MiB RAM, Traefik etwa 30 MiB. Den Bedarf bestimmen die Dienste, die Sablier verwaltet. Sie brauchen:
- einen Linux-Server oder Mini-PC mit Docker Engine und Docker Compose Plugin (x86 oder ARM, 2 Kerne und 4 GB RAM reichen für Sablier, Traefik und einige kleinere Dienste), eingerichtet etwa wie in der Grundlagen-Anleitung Docker Compose unter Linux,
- Traefik 3.6 oder neuer, weil erst diese Version Routen zu gestoppten Containern kennt (Label
traefik.docker.allownonrunning), - ausgehenden Internetzugang für Traefik beim Start, denn Traefik lädt das Sablier-Plugin aus dem Plugin-Katalog,
- Dienste mit Healthcheck. Ohne Healthcheck kann Sablier laut Projekt einen gestarteten von einem bereiten Container nicht unterscheiden.
Im Test lief alles auf Debian 12 mit Docker 29.8.2. Beachten Sie: Über den Docker-Socket hat Sablier faktisch Root-Rechte auf dem Host (Eingrenzung in Schritt 6).
Schritt 1: Projektordner und Sablier-Konfiguration anlegen
Sablier liest seine Einstellungen aus einer Datei sablier.yaml, aus Umgebungsvariablen mit Präfix SABLIER_ oder aus Startparametern, in dieser Reihenfolge, spätere Quellen überschreiben frühere.
Die Eckdaten des getesteten Aufbaus im Überblick:
| Punkt | Wert im Test |
|---|---|
| Image | sablierapp/sablier:1.19.1 (auch ghcr.io/sablierapp/sablier) |
| Proxy | traefik:v3.7.17 mit Plugin sablier-traefik-plugin v1.4.0 |
| Port | 10000 (API, Warteseite, /health), nur intern bzw. an 127.0.0.1 |
| Volumes | /var/run/docker.sock, ./sablier.yaml, ./state (State-Datei) |
| Env | NO_COLOR=1, alle Optionen auch als SABLIER_* |
| Lizenz | AGPL-3.0 |
mkdir -p /opt/sablier/state && cd /opt/sablier
Legen Sie dort sablier.yaml an:
provider:
name: docker
auto-stop-on-startup: true
server:
port: 10000
storage:
file: /var/lib/sablier/state.json
sessions:
default-duration: 5m
expiration-interval: 20s
logging:
level: info
strategy:
dynamic:
default-theme: ghost
show-details-by-default: true
default-refresh-frequency: 5s
blocking:
default-timeout: 1m
Die wichtigsten Punkte: auto-stop-on-startup stoppt beim Start alle Container mit sablier.enable=true, die Sablier nicht selbst gestartet hat. storage.file sorgt dafür, dass laufende Sitzungen einen Neustart von Sablier überstehen. default-duration greift nur, wenn das Proxy-Plugin keine eigene Sitzungsdauer mitgibt; expiration-interval legt fest, wie oft Sablier abgelaufene Sitzungen prüft.
Verifizieren: ls /opt/sablier zeigt sablier.yaml und den leeren Ordner state.
Schritt 2: Compose-Datei mit Traefik, Sablier und Demo-App
Die Datei orientiert sich am offiziellen Docker-Beispiel des Traefik-Plugins, nutzt aber feste Versionen, einen Healthcheck für Sablier und als Demo-App ein nginx-Image. Speichern Sie sie als compose.yaml:
services:
traefik:
image: traefik:v3.7.17
restart: unless-stopped
command:
- --experimental.plugins.sablier.modulename=github.com/sablierapp/sablier-traefik-plugin
- --experimental.plugins.sablier.version=v1.4.0
- --entryPoints.http.address=:80
- --providers.docker=true
- --providers.docker.exposedbydefault=false
ports:
- "8080:80"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
sablier:
image: sablierapp/sablier:1.19.1
restart: unless-stopped
command:
- start
- --configFile=/etc/sablier/sablier.yaml
environment:
- NO_COLOR=1
ports:
- "127.0.0.1:10000:10000"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./sablier.yaml:/etc/sablier/sablier.yaml:ro
- ./state:/var/lib/sablier
healthcheck:
test: ["CMD", "/bin/sablier", "health"]
interval: 10s
timeout: 3s
retries: 3
app:
image: nginx:1.30.6-alpine
restart: "no"
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1/"]
interval: 5s
timeout: 3s
retries: 3
labels:
- sablier.enable=true
- sablier.group=demo
- traefik.enable=true
- traefik.docker.allownonrunning=true
- traefik.http.routers.app.rule=PathPrefix(`/`)
- traefik.http.routers.app.entrypoints=http
- traefik.http.routers.app.middlewares=app-sablier
- traefik.http.services.app.loadbalancer.server.port=80
- traefik.http.middlewares.app-sablier.plugin.sablier.sablierUrl=http://sablier:10000
- traefik.http.middlewares.app-sablier.plugin.sablier.group=demo
- traefik.http.middlewares.app-sablier.plugin.sablier.sessionDuration=1m
- traefik.http.middlewares.app-sablier.plugin.sablier.dynamic.displayName=Demo-App
- traefik.http.middlewares.app-sablier.plugin.sablier.dynamic.theme=ghost
So greifen die Teile ineinander: Die App trägt die Sablier-Labels (sablier.enable, sablier.group=demo) und gleichzeitig die Traefik-Labels für Router und Middleware. Die Middleware app-sablier fragt bei jeder Anfrage Sablier unter http://sablier:10000, ob die Gruppe demo läuft, und verlängert die Sitzung um sessionDuration. restart: "no" bei der App verhindert, dass Docker den Container nach einem Host-Neustart an Sablier vorbei hochfährt. Port 10000 hängt nur an 127.0.0.1.
Der Healthcheck nutzt den eingebauten Befehl sablier health, denn das Image basiert auf scratch und enthält weder Shell noch curl. Hintergründe zu Healthchecks und Rechten finden Sie in der Anleitung Docker Compose absichern: Secrets, Healthchecks, non-root.
Verifizieren: docker compose config --quiet gibt nichts aus. Jede Ausgabe ist ein Syntaxfehler in der Datei.
Schritt 3: Stack starten und Version prüfen
docker compose up -d --pull always
docker compose exec sablier /bin/sablier version
docker compose ps -a
Im Test meldete Sablier nach rund 12 Sekunden healthy. Die Demo-App stand direkt danach auf Exited, weil Sablier sie beim Start als nicht selbst gestartet erkannt und gestoppt hat:
(version=1.19.1, branch=HEAD, revision=bd75a54)
SERVICE STATUS
app Exited (0) 10 seconds ago
sablier Up 21 seconds (healthy)
traefik Up 41 seconds
INF docker/docker.go:52 connection established with docker provider=docker strategy=stop version=29.8.2
INF sablier/sablier.go:158 set groups old=map[] new=map[demo:[news-sablier-app-1]]
INF sablier/autostop.go:54 stopped unregistered instance instance=news-sablier-app-1 reason="instance is enabled but not started by Sablier"
Die Zeile set groups zeigt die erkannten Gruppen; fehlt ein Dienst, stimmen die Labels nicht. Den Gesundheitsstatus und die verfügbaren Themes liefert die API:
curl -s localhost:10000/health
curl -s localhost:10000/api/themes
OK
{"themes":["ghost","hacker-terminal","matrix","retro","shuffle"]}
Verifizieren: docker compose ps -a zeigt Sablier als healthy, Traefik als Up und die App als Exited. curl -s localhost:10000/health antwortet mit OK.
Schritt 4: Start bei Aufruf und Stopp nach Leerlauf testen
Rufen Sie die Adresse des Dienstes im Browser auf (im Beispiel Port 8080 des Servers). Statt der App erscheint die Warteseite von Sablier im Theme ghost mit dem Anzeigenamen aus dem Label dynamic.displayName, dem Container und seinem Zustand.

Im Test antwortete Traefik auf die erste Anfrage in 3 Millisekunden mit HTTP 200 und der Warteseite. Nach 6 Sekunden war nginx gestartet, der Healthcheck grün, und die Seite wechselte ohne Zutun zur App. Weitere Anfragen gingen direkt durch.

Danach haben wir die Seite ruhen lassen. Nach exakt 60 Sekunden ohne Anfrage stoppte Sablier den Container wieder:
app nach 60s Leerlauf: exited
INF sablier/instance_request.go:261 request to start instance dispatched instance=news-sablier-app-1 status=starting expiration=1m0s
INF sablier/instance_expired.go:34 instance expired instance=news-sablier-app-1
Für Dienste, die von Skripten oder anderen Programmen aufgerufen werden, passt die Warteseite nicht. Dafür gibt es die Strategie blocking: Die Anfrage wartet, bis der Dienst bereit ist. Sie lässt sich auch direkt über die API auslösen, etwa um einen Dienst vor einem nächtlichen Job zu wecken:
curl -s -D - -o /dev/null "localhost:10000/api/strategies/blocking?group=demo&session_duration=30m"
HTTP/1.1 200 OK
X-Sablier-Session-Status: ready
Die Antwort kam im Test nach 6,4 Sekunden, der Container lief da bereits mit Status healthy. Im Traefik-Plugin wählen Sie die Strategie, indem Sie statt der dynamic-Labels blocking.timeout setzen. Beide Strategien gleichzeitig erlaubt das Plugin nicht.
Verifizieren: Erster Aufruf zeigt die Warteseite, nach wenigen Sekunden die App. docker compose ps -a zeigt die App als Up (healthy), gut eine Minute nach dem letzten Aufruf als Exited; im Log steht instance expired.
Schritt 5: Sicherung und Wiederherstellung
Sablier hat keine Datenbank. Zu sichern sind compose.yaml, sablier.yaml und der Ordner state. In der State-Datei stehen die laufenden Sitzungen mit Ablaufzeit. Im Test war die Datei während des Betriebs leer ({}) und enthielt die Sitzung erst, nachdem Sablier gestoppt wurde. Sichern Sie deshalb mit gestopptem Sablier:
cd /opt/sablier
docker compose stop sablier
tar czf /backup/sablier-$(date +%F).tgz compose.yaml sablier.yaml state
docker compose start sablier
Für die Wiederherstellung haben wir einen Totalverlust simuliert: Stack mit docker compose down entfernt, compose.yaml, sablier.yaml und state gelöscht. Vorher lief die App mit einer 30-Minuten-Sitzung.
cd /opt/sablier
tar xzf /backup/sablier-2026-10-31.tgz
sha256sum state/state.json
docker compose up -d
docker compose logs --no-log-prefix sablier | grep -i state
08d9db8c392f... state/state.json (identisch mit dem Wert vor der Sicherung)
INF sabliercmd/storage.go:58 state restored from file file=/var/lib/sablier/state.json
app nach Restore: running healthy
Die Gegenprobe zeigt, warum die State-Datei in die Sicherung gehört: Ohne sie startete Sablier leer, hielt die laufende App für fremd gestartet und stoppte sie sofort (stopped unregistered instance), obwohl ihre Sitzung noch knapp 30 Minuten gültig gewesen wäre.
Verifizieren: Nach dem Zurückspielen steht im Log state restored from file, und Dienste mit gültiger Sitzung laufen weiter, statt gestoppt zu werden.
Schritt 6: Update und Absicherung
Den Update-Weg haben wir von 1.18.0 auf 1.19.1 getestet: Tag in der compose.yaml ändern, dann
docker compose pull sablier
docker compose up -d
docker compose exec sablier /bin/sablier version
Compose ersetzte nur den Sablier-Container (Recreate), Traefik lief weiter. Nach dem Start meldete Sablier version=1.19.1, Gruppen und Warteseite funktionierten unverändert. Version 1.19 bringt vor allem neue Provider für AWS ECS und Nomad; am Docker-Betrieb änderte sich nichts. Lesen Sie vor jedem Sprung die Release Notes; 1.18.0 etwa änderte den Pfad eigener Themes in Unterordnern. Benachrichtigungen über neue Tags liefert zum Beispiel Diun, siehe Container-Updates mit Diun und WUD.
Zur Absicherung: Der Docker-Socket ist das größte Risiko. Die Projektdoku beschreibt einen Socket-Proxy, der Sablier nur Container-Endpunkte, Ereignisse und Version erlaubt (CONTAINERS=1, EVENTS=1, VERSION=1, POST=1), auf einem internen Netz. Geben Sie Port 10000 nie öffentlich frei: Über die API kann jeder, der sie erreicht, jede bekannte Gruppe starten. Wie Sie einen Socket-Proxy praktisch einsetzen, zeigt auch die Anleitung zu OliveTin mit Socket-Proxy.
Verifizieren: sablier version zeigt die neue Version, docker compose ps meldet Sablier als healthy, und ein Aufruf des Dienstes zeigt wieder Warteseite und App.
Troubleshooting
Diese Fehler haben wir im Test absichtlich ausgelöst:
| Symptom | Meldung im Test | Ursache und Abhilfe |
|---|---|---|
| Sablier startet nicht, Container beendet sich mit Exit-Code 1 | cannot setup provider: cannot connect to docker host: ... dial unix /var/run/docker.sock: connect: no such file or directory | Socket nicht eingebunden. Volume /var/run/docker.sock ergänzen oder Socket-Proxy per DOCKER_HOST angeben. |
| Browser zeigt Fehlerseite, HTTP 500 nach rund 7 Sekunden | dial tcp: lookup sablier on 127.0.0.11:53: server misbehaving | Sablier ist gestoppt oder nicht im selben Netz wie Traefik. Mit failOpen=true reicht das Plugin Anfragen dann ungefiltert an den Dienst weiter, der dafür aber laufen muss. |
| API antwortet 404 | "title": "Group not found", "availableGroups": ["demo"] | Tippfehler in sablier.group oder im Middleware-Label. Die Antwort listet die bekannten Gruppen. |
| API antwortet 400 | 'names' or 'group' query parameter must be set | Aufruf ohne Gruppe, etwa ein falsch zusammengesetztes Skript. |
| Dienst wird nach Neustart von Sablier sofort gestoppt | stopped unregistered instance ... not started by Sablier | State-Datei fehlt oder wurde nicht gesichert. storage.file setzen und den Ordner sichern. |
Laut Doku braucht Traefik das Label traefik.docker.allownonrunning=true, sonst fehlt die Route zum gestoppten Container. Monitoring-Abfragen halten einen Dienst dauerhaft wach; das Plugin-Label ignoreUserAgent nimmt solche Clients per regulärem Ausdruck aus.
Häufige Fragen
Funktioniert Sablier auch mit Caddy oder nginx?
Ja. Für Caddy gibt es ein Modul, das in ein eigenes Caddy-Image gebaut werden muss, für nginx, Envoy, Istio und Apache APISIX ein Proxy-WASM-Plugin.
Kann Sablier mehrere Container gemeinsam starten?
Ja, über Gruppen. Alle Container mit demselben sablier.group starten und stoppen zusammen, etwa App und Datenbank. Beim Docker-Provider beachtet Sablier laut Doku auch depends_on und startet Abhängigkeiten zuerst.
Wie lange dauert der Kaltstart?
So lange, wie der Dienst bis zum grünen Healthcheck braucht. nginx war im Test nach 6 Sekunden bereit, Java- oder Datenbank-Stacks brauchen deutlich länger. Wählen Sie sessionDuration so, dass Nutzer nicht bei jeder Kaffeepause erneut warten.
Fazit
Selten genutzte Dienste verschwinden mit Sablier aus dem Speicher und kommen beim ersten Aufruf nach Sekunden zurück. Im Test arbeiteten Start, Leerlauf-Stopp, Update und Wiederherstellung zuverlässig. Die Schattenseiten sind der Zugriff auf den Docker-Socket, die Abhängigkeit vom Plugin-Download beim Traefik-Start und der Kaltstart für den ersten Nutzer. Für interne Werkzeuge in kleinen Teams und für Homelabs mit knappem RAM ist das ein guter Tausch, für Dienste mit Zugriffen im Minutentakt bringt Sablier keinen Gewinn.


