Dockwatch monitors Docker containers with healthchecks, restarts containers that become unhealthy, and sends webhook alerts when restarts happen or a restart loop is detected.
It is designed to run as a small sidecar service on a Docker host. By default, it only manages containers that explicitly opt in with a label.
Dockwatch is a lightweight Docker healthcheck monitor and Docker autoheal alternative for self-healing containers, container monitoring, Discord webhook alerts, and restart-loop detection.
- Restarts unhealthy Docker containers automatically.
- Opt-in by label, so unrelated containers are left alone.
- Sends webhook notifications for restarts, failures, and restart loops.
- Supports Discord webhooks out of the box.
- Detects restart loops and pauses further restarts for a cooldown period.
- Uses the Docker Engine API through
/var/run/docker.sock. - Runs without required environment variables; all settings have safe defaults.
Run Dockwatch with Docker Compose:
services:
dockwatch:
image: mochazizz/dockwatch:v1.0.0
container_name: dockwatch
restart: unless-stopped
environment:
WEBHOOK_URL: "https://example.com/webhook/dockwatch"
WEBHOOK_FORMAT: "auto"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
labels:
docker-monitor.ignore: "true"Start it:
docker compose up -dView logs:
docker logs -f dockwatchThe monitor will only restart containers with this label:
labels:
docker-monitor.restart: "true"Dockwatch depends on Docker healthchecks. A container must define a healthcheck before Docker can mark it as unhealthy.
services:
app:
image: nginx:alpine
labels:
docker-monitor.restart: "true"
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1"]
interval: 30s
timeout: 5s
retries: 3
start_period: 20sUse docker-compose.prod.yml as a starting point. Set WEBHOOK_URL only when you want notifications:
services:
dockwatch:
image: mochazizz/dockwatch:v1.0.0
container_name: dockwatch
restart: unless-stopped
environment:
WEBHOOK_URL: "${WEBHOOK_URL:-}"
WEBHOOK_FORMAT: "auto"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
labels:
docker-monitor.ignore: "true"Run it:
docker compose -f docker-compose.prod.yml up -dBuild a local image if you do not want to use Docker Hub:
docker build -t dockwatch:latest .This repository includes a GitHub Actions workflow that builds and pushes Docker images to Docker Hub.
Required repository secrets:
| Secret | Description |
|---|---|
DOCKERHUB_USERNAME |
Docker Hub username or organization. |
DOCKERHUB_TOKEN |
Docker Hub access token. |
Published image tags:
| Trigger | Tags |
|---|---|
Push to main |
latest, sha-<commit> |
Push tag vX.Y.Z |
vX.Y.Z, sha-<commit> |
| Manual workflow run | sha-<commit> |
Create a release tag:
git tag v1.0.0
git push origin v1.0.0After the workflow completes, users can run:
services:
dockwatch:
image: mochazizz/dockwatch:v1.0.0
container_name: dockwatch
restart: unless-stopped
volumes:
- /var/run/docker.sock:/var/run/docker.sock
labels:
docker-monitor.ignore: "true"Use latest only if you intentionally want the newest build from main:
image: mochazizz/dockwatch:latestDocker monitor, Docker healthcheck monitor, Docker autoheal, restart unhealthy Docker containers, self-healing Docker containers, container monitoring, Docker webhook alerts, Discord webhook Docker alert, Docker restart loop detection.
All configuration is optional. If a variable is not set, Dockwatch uses the default below.
| Environment variable | Default | Description |
|---|---|---|
CHECK_INTERVAL_SECONDS |
30 |
Interval between Docker health checks. |
RESTART_TIMEOUT_SECONDS |
10 |
Docker restart timeout in seconds. |
RESTART_COOLDOWN_SECONDS |
300 |
Minimum delay before the same container can be restarted again. |
LOOP_RESTART_THRESHOLD |
3 |
Number of restarts that triggers restart-loop detection. |
LOOP_RESTART_WINDOW_SECONDS |
900 |
Time window used to count restart-loop restarts. |
LOOP_ALERT_COOLDOWN_SECONDS |
900 |
Minimum delay before sending another loop alert for the same container. |
LOOP_RESTART_COOLDOWN_SECONDS |
180 |
Pause restarts after a restart loop is detected. Use 120 for 2 minutes or 180 for 3 minutes. |
COOLDOWN_ALERT_INTERVAL_SECONDS |
300 |
Minimum delay between cooldown notifications for the same container. |
MONITOR_SCOPE |
label |
label monitors only opt-in containers; all monitors all unhealthy containers. |
MONITOR_LABEL |
docker-monitor.restart=true |
Label required when MONITOR_SCOPE=label. |
EXCLUDE_LABEL |
docker-monitor.ignore=true |
Label used to exclude containers from monitoring. |
DRY_RUN |
false |
Log and notify without restarting containers. |
NOTIFY_UNHEALTHY_BEFORE_RESTART |
false |
Send a pre-restart container_unhealthy event. Disabled by default to avoid duplicate notifications. |
NOTIFY_LOOP_COOLDOWN |
false |
Send notifications while a container is skipped due to restart-loop cooldown. Disabled by default to avoid noisy alerts. |
WEBHOOK_URL |
empty | Webhook URL. If empty, webhook notifications are disabled. |
WEBHOOK_FORMAT |
auto |
auto, json, or discord. Discord webhook URLs are detected automatically. |
WEBHOOK_TIMEOUT_SECONDS |
10 |
Webhook request timeout. |
WEBHOOK_HEADERS |
{} |
Additional webhook headers as a JSON object. |
LOG_LEVEL |
INFO |
Python log level. |
Set WEBHOOK_URL to enable notifications:
WEBHOOK_URL=https://example.com/webhook/dockwatch
WEBHOOK_FORMAT=auto
WEBHOOK_HEADERS={"Authorization":"Bearer your-token"}Discord webhooks are supported directly:
WEBHOOK_URL=https://discord.com/api/webhooks/...
WEBHOOK_FORMAT=discordFor generic webhooks, Dockwatch sends JSON:
{
"event": "container_restarted",
"severity": "warning",
"message": "Container app was restarted because it was unhealthy",
"host": "dockwatch",
"container": {
"id": "abc123def456",
"name": "app",
"image": "nginx:alpine",
"state": "running",
"status": "Up 2 minutes (unhealthy)",
"labels": {
"docker-monitor.restart": "true"
}
},
"timestamp": "2026-07-07T14:00:00Z"
}| Event | Severity | Description |
|---|---|---|
container_restarted |
warning |
A container was restarted because it was unhealthy. |
container_unhealthy |
warning |
Optional pre-restart event. Sent only when NOTIFY_UNHEALTHY_BEFORE_RESTART=true. |
container_restart_planned |
warning |
Dry-run mode: a container would have been restarted. |
restart_failed |
critical |
Docker failed to restart a container. |
restart_cooldown |
warning |
A container is still unhealthy, but normal restart cooldown is active. |
restart_loop_detected |
critical |
A container crossed the restart-loop threshold. |
restart_loop_cooldown |
critical |
Optional event while a restart-loop cooldown is active. Sent only when NOTIFY_LOOP_COOLDOWN=true. |
By default, if the same container is restarted 3 times within 900 seconds, Dockwatch sends restart_loop_detected and pauses restarts for that container for 180 seconds.
After the loop cooldown expires, restart counting starts again. This prevents tight restart loops while still allowing the service to retry later.
Dockwatch mounts /var/run/docker.sock. This gives the container control over the Docker host. Run it only on hosts where you trust the service and its image.
Recommended production practices:
- Pin image versions instead of using
latest. - Keep
MONITOR_SCOPE=labelunless you intentionally want to manage all containers. - Do not commit real webhook URLs or tokens.
- Use
DRY_RUN=truebefore enabling automatic restarts on a new host.