Docker-watchdog with per-container restart rules, Gotify/Pushover notifications, and an embedded dashboard + web settings page. See README.md for an overview and INSTALL.md for the Docker quickstart.
5.6 KiB
Executable File
Inspector
Inspector is a small, opinionated Docker-watchdog. It polls the Docker daemon, applies per-container restart rules, pings Gotify and/or Pushover when things go wrong, and gives you a dashboard that shows what's happening right now and what happened earlier today.
Built for home-lab and small-fleet operators who want "it just works" container recovery without standing up a full observability stack.
What Inspector does
- Polls each configured container on a fixed interval and classifies it:
HEALTHY,UNHEALTHY,STARTING,NOT RUNNING,ERROR,UNREACHABLE,CONTAINER NOT FOUND,NO HEALTH CHECK,UNKNOWN. - Restarts a container when it crosses a configured error threshold — with cooldowns, grace periods, and an hourly restart cap so a flapping container doesn't DDoS your host.
- Opt-in HTTP reachability checks per container (useful for VPN-routed containers whose tunnel drops while Docker still reports "healthy").
- Opt-in Uptime Kuma integration as a second reachability source.
- Advanced recovery via Portainer stack redeploy for containers whose network namespace is tied to a VPN sidecar.
- Sends notifications on transitions, not on every poll — one line when something breaks, one line when it recovers.
- Optional SQLite event history + a daily/weekly digest.
- Scheduled maintenance windows (don't act during 2–6 AM).
- Manual notification mute per container, from the dashboard.
- Embedded web dashboard + events timeline + web settings page for
editing
config.ymlwithout SSH.
What Inspector is not
- Not a metrics system. It doesn't scrape Prometheus or push dashboards; use Grafana / Netdata / your real monitoring stack for that.
- Not an orchestrator. It only acts on containers you've explicitly
listed in
config.yml. - Not multi-host. One Inspector per Docker socket.
Install
See INSTALL.md. TL;DR:
mkdir -p ~/docker/inspector && cd ~/docker/inspector
curl -L -o compose.yml https://gitea.euronvault.com/euronvault/inspector/raw/branch/main/compose.yml
curl -L -o config.yml https://gitea.euronvault.com/euronvault/inspector/raw/branch/main/config.example.yml
$EDITOR config.yml
echo "DOCKER_GID=$(getent group docker | cut -d: -f3)" > .env
docker compose up -d
Configuration
Everything lives in config.yml next to the compose file. Start from
config.example.yml — every key is commented.
Highlights:
inspector.interval_seconds— poll cadence.inspector.dry_run— classify + log, never restart.notifications.gotify/notifications.pushover— enable either, both, or neither.containers.<name>.max_error_count/cooldown_seconds/grace_period_seconds/max_restarts_per_hour— the restart knobs.containers.<name>.restart_on— which statuses trigger a restart (leave empty for observe-only).containers.<name>.http_check— opt-in HTTP ping.containers.<name>.recovery_action—restart_container(default) or the advanced Portainer-based options.
Dashboard and settings page
If dashboard.enabled: true, Inspector exposes a small web UI on
:8080:
/— container cards with current status, error bar, phase (cooldown / grace / failing / observe only / maintenance), and maintenance / mute toggles./events— per-day timeline of status changes, restarts, recoveries, and failures (requiresdatabase.enabled: true)./settings— forms for every top-level config section plus one card per container. Saves preserve comments and key order inconfig.ymland keep a.bak. Fields that take effect on the next loop iteration (per-container thresholds,dry_run,heartbeat,interval_seconds) hot-apply; fields bound at startup are labeled requires restart.
Note on .bak inside Docker: when config.yml is bind-mounted as a
single file (the compose default), the .bak lives in the container's
overlay fs — the live file still updates cleanly, but the backup is
lost when the container is removed. To keep the .bak on the host,
bind-mount the directory instead of the single file.
Notifications
Both channels are independent. If both are enabled, every alert goes to both. Inspector sends on transitions:
🚨 first failure threshold crossed
🔁 container restart triggered
✅ restart / start completed
✅ container recovered
🛑 restart failed / hourly limit exceeded
❓ configured container not found
Gotify messages are Markdown; Pushover doesn't render Markdown so the
**bold** passthrough is cosmetic — bodies are identical.
Pushover priorities map from Inspector's Gotify-style scale (default 5)
to Pushover's -2..2 range: <=2 → -1, 3..4 → 0, 5..6 → 1,
>=7 → 2. Priority 2 (emergency) ships default retry / expire and
your Pushover client prompts for acknowledgement.
Docker socket security
Inspector talks to /var/run/docker.sock. That socket is effectively
root on your host: anything that can write to it can start, stop,
inspect, and (through bind mounts) read any file as root. Inspector
mounts it read-write because it needs to restart containers.
Follow the usual home-lab precautions:
- Don't publish the dashboard port on an untrusted network. Use a reverse proxy with auth, a tailnet, or SSH tunneling.
- Set a strong
dashboard.password. - Store Portainer / Gotify / Pushover tokens in the config file on a
host-only path with permissions
600.
Versioning
Semantic versioning (MAJOR.MINOR.PATCH). Image tags are published for
every release; latest tracks the newest tag. Pin a specific version
in production — see INSTALL.md.
License
MIT.