A lightweight and safe container to automate start/stop of Docker containers via Portainer API, base
10K+
SleeperStack is a lightweight automation container that safely starts or stops Docker containers managed via Portainer, using labels.
It's designed to work especially well with Portainer Community Edition, offering full functionality even without access to advanced stack metadata.
night, weekend)Starting the container without MODE=oneshot launches a small web application
(FastAPI) on port 8000, backed by an internal scheduler (APScheduler) and a
SQLite database persisted in /data. A single instance manages all your
Portainer environments โ no need to run one container per endpoint anymore.
| Page | Purpose |
|---|---|
/login | Sign in (single admin account, bootstrapped from env vars on first boot) |
/dashboard | Live status of labeled containers per endpoint, manual stop/start |
/rules | Create/enable/disable/delete scheduled rules (label + action + cron) |
/rules/import | Paste your existing crontab lines and import them as rules |
/endpoints | Manage Portainer connections (URL, API key, endpoint ID), test connectivity |
/history | Log of every scheduled and manual run, with status and dry-run flag |
/inventory | Full container census per endpoint โ stack, image, ports, IP, uptime, labels |
| Variable | Description |
|---|---|
SECRET_KEY | Long random string used to sign sessions and encrypt stored Portainer API keys |
ADMIN_USERNAME | Username for the first admin account (default admin) |
ADMIN_PASSWORD | Password for the first admin account, required only on first boot |
SLEEPERSTACK_DB_PATH | (Optional) SQLite file path, default /data/sleeperstack.db |
docker run -d --name sleeperstack \
-p 8000:8000 \
-v sleeperstack-data:/data \
-e SECRET_KEY=$(openssl rand -hex 32) \
-e ADMIN_USERNAME=admin \
-e ADMIN_PASSWORD=change_me \
gfsolone/sleeperstack
Then open http://localhost:8000, log in, add your Portainer endpoint(s) and
create rules โ or use /rules/import to migrate the crontab lines you already
have (see below).
Paste your existing lines (the same ones you used with docker run +
host/Portainer cron) into /rules/import. SleeperStack parses the cron
schedule, label, action and endpoint from each line, matches it against a
configured endpoint, and lets you review before creating the equivalent rule
โ nothing is imported silently.
Portainer Community Edition does not expose stack-level labels or tags via API.
To ensure compatibility:
com.docker.compose.project to associate containers with their stack nameThis makes it safe and accessible for all setups โ even without Portainer Business features.
Set MODE=oneshot to keep using SleeperStack exactly like before: a single
run that stops/starts containers for one label on one Portainer endpoint,
then exits. Useful if you already have external cron jobs and don't want to
migrate yet.
| Variable | Description |
|---|---|
PORTAINER_URL | Portainer API base URL (e.g. http://localhost:9000/api) |
PORTAINER_API_KEY | API key from your Portainer user account |
PORTAINER_ENDPOINT_ID | ID of the target Docker environment |
TARGET_LABEL | Label to match containers, e.g. autoshutdown=night or autoshutdown=night,weekend |
ACTION | Either stop or start |
DRY_RUN | (Optional) Set to true to simulate actions without executing |
PORTAINER_URL=http://dockerlab.local:9002/api
PORTAINER_API_KEY=your_api_key
PORTAINER_ENDPOINT_ID=2
ACTION=stop
TARGET_LABEL=autoshutdown=night,weekend
DRY_RUN=true
Then run:
python3 main.py
SleeperStack is available on:
gfsolone/sleeperstackโ ghcr.io/gioxx/sleeperstackโ You can pull it with:
docker pull ghcr.io/gioxx/sleeperstack:latest
docker run --rm --env-file .env -e MODE=oneshot gfsolone/sleeperstack
In your docker-compose.yml, add:
services:
myapp:
image: my/image
labels:
autoshutdown: "night"
You can group containers using different values:
autoshutdown: "night"autoshutdown: "weekend"autoshutdown: "testlab"Then run:
TARGET_LABEL=autoshutdown=night,weekend ACTION=stop python3 main.py
To preview what would happen:
DRY_RUN=true ACTION=stop python3 main.py
No containers will actually be stopped or started.
You can run this tool via:
cronSet different TARGET_LABEL and ACTION values to automate multiple groups.
?all=true to support stopped container discovery.You can automate SleeperStack with multiple cronjobs to control different groups of containers based on their labels.
0 22 * * * docker run --rm -e MODE=oneshot -e PORTAINER_URL=... -e PORTAINER_API_KEY=... -e PORTAINER_ENDPOINT_ID=2 -e TARGET_LABEL=autoshutdown=night -e ACTION=stop gfsolone/sleeperstack
0 7 * * * docker run --rm -e MODE=oneshot -e PORTAINER_URL=... -e PORTAINER_API_KEY=... -e PORTAINER_ENDPOINT_ID=2 -e TARGET_LABEL=autoshutdown=night -e ACTION=start gfsolone/sleeperstack
0 19 * * 5 docker run --rm -e MODE=oneshot -e PORTAINER_URL=... -e PORTAINER_API_KEY=... -e PORTAINER_ENDPOINT_ID=2 -e TARGET_LABEL=autoshutdown=weekend -e ACTION=stop gfsolone/sleeperstack
30 8 * * 1 docker run --rm -e MODE=oneshot -e PORTAINER_URL=... -e PORTAINER_API_KEY=... -e PORTAINER_ENDPOINT_ID=2 -e TARGET_LABEL=autoshutdown=weekend -e ACTION=start gfsolone/sleeperstack
๐ Tip: You can extract shared env vars into a .env file and reuse with --env-file.
A ready-to-use docker-compose.yml is included in the repo:
services:
sleeperstack:
image: gfsolone/sleeperstack:latest
container_name: sleeperstack
restart: unless-stopped
ports:
- "8000:8000"
volumes:
- sleeperstack-data:/data
environment:
SECRET_KEY: ${SECRET_KEY:?set a long random string, e.g. openssl rand -hex 32}
ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}
ADMIN_PASSWORD: ${ADMIN_PASSWORD:?set the initial admin password}
volumes:
sleeperstack-data:
Create a .env file next to it with SECRET_KEY, ADMIN_USERNAME and
ADMIN_PASSWORD, then:
docker compose up -d
The scheduler, all Portainer endpoints and every rule live inside this one long-running container โ no separate cron sidecar needed anymore.
services:
sleeperstack-night:
image: gfsolone/sleeperstack
restart: "no"
environment:
MODE: oneshot
PORTAINER_URL: http://dockerlab.local:9002/api
PORTAINER_API_KEY: your_api_key
PORTAINER_ENDPOINT_ID: "2"
TARGET_LABEL: autoshutdown=night
ACTION: stop
Run it manually:
docker compose run --rm sleeperstack-night
services:
sleeperstack-nightly:
image: gfsolone/sleeperstack
environment:
MODE: oneshot
PORTAINER_URL: http://dockerlab.local:9002/api
PORTAINER_API_KEY: your_api_key
PORTAINER_ENDPOINT_ID: "2"
TARGET_LABEL: autoshutdown=night
ACTION: stop
cron:
image: aptible/docker-cron
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
CRON_TIME: "0 22 * * *"
CRON_COMMAND: "docker compose run --rm sleeperstack-nightly"
๐ Note: docker-cron triggers commands in its environment, so keep docker.sock mounted and docker compose installed if required. This whole setup (a second container just to trigger cron) is what the built-in scheduler in server mode replaces.
MIT โ free to use, modify and distribute.
Pull requests welcome!
SleeperStack is built for responsible automation in all environments, including Community users.
Content type
Image
Digest
sha256:42517264dโฆ
Size
61.8 MB
Last updated
8 months ago
docker pull gfsolone/sleeperstack