On-demand Container Scaling - Sablier and Home Assistant

Running a homelab usually means a lot of containers that only get used occasionally but still sit there consuming RAM, CPU, storage and IO.

Sablier solves that problem by turning those services into on-demand workloads that spin up when you need them and shut down again when idle. I combine it with Home Assistant, which I already use as my main homelab dashboard. It is far more convenient to open a single app on my phone and access everything than to maintain separate homepage services.

This post walks through how I use Sablier with Docker to scale a Draw.io container to zero, and how Home Assistant wakes it up through a button in my dashboard.

What Sablier is and what "on-demand containers" means

Sablier is an open source service that starts workloads on demand and stops them again after a period of inactivity. It integrates with container providers like Docker, Docker Swarm, and Kubernetes, and can plug into reverse proxies such as Nginx, Traefik, and Caddy.

This means:

You tag certain containers as "managed by Sablier".

When Sablier receives a session request for a group, it:

Starts all containers in that group.

Waits until they are healthy.

Keeps them running for a configured session duration.

Stops them when the session expires or after inactivity.

This pattern is often called scale-to-zero or STZ. It is ideal for infrequently used tools such as Draw.io, CyberChef, StirlingPDF, etc.

Deploying Sablier with Docker

I run Sablier as a simple Docker Compose service with the Docker provider and access to the Docker socket.

version: "3.8"

services:
sablier:
image: sablierapp/sablier:1.10.5
container_name: sablier
command:
- start
- --provider.name=docker
# optional: global default for dynamic strategy timeout
- --strategy.dynamic.timeout=10m
ports:
- "10000:10000"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
restart: always

Notes:

/var/run/docker.sock lets Sablier start and stop containers directly on the host.

Port 10000 exposes the Sablier API, which is what Home Assistant will call.

In a homelab I am fine exposing this only on a trusted VLAN. If you expose it more widely, protect it with firewall rules or another reverse proxy (more on this below).

Making a container sleep-enabled

Next, mark the Draw.io container as managed by Sablier, using the labels.

services:
drawio:
image: jgraph/drawio:latest
container_name: drawio
ports:
- "2392:8443"
labels:
- "sablier.enable=true"
- "sablier.group=draw"
restart: unless-stopped

Sablier looks for:

sablier.enable=true to know that this container is under its control.

sablier.group=draw so that multiple containers can share the same logical group. The group name is what we will pass to the API (group=draw).

You should also add a proper healthcheck so Sablier can tell when the service is ready:

healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:8443"]
interval: 10s
timeout: 3s
retries: 3

Without a healthcheck Sablier can only see that the container started, not that the app is actually ready to accept traffic.

Controlling session duration

By default Sablier will keep a group alive for the duration you request in the API call. You can also tune strategy-specific defaults with command line flags. In this setup I keep it simple and let the API decide.

The Compose service for Sablier already contains:

command:
- start
- --provider.name=docker
- --strategy.dynamic.timeout=10m

That strategy.dynamic.timeout is for the dynamic strategy. In this post I use the blocking strategy from Home Assistant, which waits until services are ready, but the core idea is the same, a session has a lifetime, and Sablier shuts things down when it expires.

You can test it manually from the host:

curl -v "http://localhost:10000/api/strategies/blocking?group=draw&session_duration=10m"

Expected response header:

X-Sablier-Session-Status: ready

This single call does all of the following:

Starts all containers with sablier.group=draw.

Waits until their healthchecks pass.

Keeps them running for 10 minutes.

Stops them automatically after the session expires.

Why I use Home Assistant instead of Nginx Proxy Manager to wake containers

Sablier has native integrations for several reverse proxies, including standard Nginx via either an NJS script or a WASM module. These act as middleware between the proxy and the backend service so that a regular HTTP request can transparently trigger Sablier, show a waiting page, and then forward traffic once the container is ready.

Nginx Proxy Manager is a pre-packaged Nginx instance with a UI that exposes only a limited subset of the Nginx configuration. It does not let you install custom NJS or WASM modules or insert the Sablier middleware blocks into the underlying nginx.conf.

That means NPM cannot trigger Sablier automatically on an incoming request in the official way. You could work around this with custom hacks like forking and rebuilding NPM, but it goes against what NPM is trying to be.

Since I already use Home Assistant as my main homelab launcher, I simply let Home Assistant call the Sablier API first with a hold tap, then open the real service URL with a single tap.

Wiring Sablier into Home Assistant

1. REST command to wake the container

In configuration.yaml:

rest_command:
wake_draw:
url: "http://[docker-ip]:10000/api/strategies/blocking?group=draw&session_duration=10m"
method: GET

Replace docker-ip with the host that runs Sablier in your environment.

When this command runs, Sablier starts the draw group, waits for it to become healthy, and keeps it running for 10 minutes.

2. Lovelace card: tap to open, hold to wake

I use Mushroom cards in Lovelace. The button behaves as follows:

Tap: go straight to the Draw.io URL (via Nginx Proxy Manager, Cloudflare, or whatever you use).

Long press: call the REST command to wake the container via Sablier.

Example card:

type: custom:mushroom-template-card
entity: sensor.uptimekuma_draw
icon: mdi:draw
primary: Draw.io
icon_color: >-
{{ 'green' if is_state('sensor.uptimekuma_draw', 'up') else 'red' }}
tap_action:
action: url
url_path: https://draw.domain.uk
hold_action:
action: call-service
service: rest_command.wake_draw

Here:

sensor.uptimekuma_draw comes from the Uptime Kuma integration, pointed at the Draw.io container.

Icon color reflects the current status reported by Uptime Kuma.

If the service is stopped, long-pressing the card triggers Sablier to start the container, waits until it is ready, then you can tap to open it.

Home Assistant becomes a unified launcher for your homelab: one app, one dashboard, and both local and remote services managed in one place.

Bonus: cleaner status display with mod-card and Uptime Kuma

If you want tighter control over the card styling, mod-card lets you strip the background and treat the app tile as a very minimal launcher.

This version focuses only on the Draw.io service, with the same semantics as above:

type: custom:mod-card
card_mod:
style: |
ha-card {
background: transparent !important;
box-shadow: none !important;
border-radius: 16px;
padding: 4px;
margin: 4px;
}
card:
type: custom:mushroom-template-card
entity: sensor.uptimekuma_draw
icon: mdi:draw
primary: Flowcharts
icon_color: >-
{{ 'green' if is_state('sensor.uptimekuma_draw', 'up') else 'red' }}
tap_action:
action: url
url_path: https://draw.domain.uk
hold_action:
action: call-service
service: rest_command.wake_draw

Now the card:

Shows green when Draw.io is up, red when it is down.

Wakes the Sablier group on long press.

Opens the service on tap.

Summary

The full flow looks like this:

Sablier watches Docker and manages any containers labeled with sablier.enable=true.

Draw.io is labeled into the draw Sablier group and has a healthcheck.

Home Assistant exposes a rest_command that calls Sablier’s blocking strategy API for that group.

A Mushroom card on the dashboard:

Long press → hits Sablier, wakes Draw.io for 10 minutes.

Tap → opens https://draw.domain.uk through Nginx Proxy Manager.

The result is on-demand container scaling controlled from the same Home Assistant dashboard that already runs the rest of the smart home and homelab. No extra homepage app, fewer always-on containers, plus a workflow that feels native on both desktop and mobile.