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.
140 lines
5.6 KiB
Markdown
Executable File
140 lines
5.6 KiB
Markdown
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.yml` without 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`](./INSTALL.md). TL;DR:
|
||
|
||
```bash
|
||
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`](./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 (requires `database.enabled: true`).
|
||
- `/settings` — forms for every top-level config section plus one card
|
||
per container. Saves preserve comments and key order in `config.yml`
|
||
and 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](./LICENSE).
|