Release v0.8.0 — Portainer-first install, in-app guide

- Install from Portainer with no command line: paste the compose, set a
  folder and a password, deploy. Inspector creates its own config and
  detects Docker socket permissions by itself.
- Illustrated how-to guide inside the app (Help tab) and in the repo.
- Containers added in the UI are watched right away, no restart.
- maintenance_window switch on the container form.
- README with logo and screenshots; INSTALL rewritten for Portainer.
This commit is contained in:
Europium 63 committed 2026-10-27 15:45:33 -07:00
1 parent 4c05a4d565
commit c603e86e75
21 files changed
+789 -202

No files matched your search

+77 -112
View File
@@ -1,139 +1,104 @@
# Inspector
<p align="center">
<img src="docs/logo.png" alt="Inspector logo" width="140">
</p>
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.
<h1 align="center">Inspector</h1>
Built for home-lab and small-fleet operators who want "it just works"
container recovery without standing up a full observability stack.
<p align="center"><b>Monitor. Restart. Report.</b><br>
A small Docker watchdog for home servers: it watches the containers you pick,
restarts them when they break, and tells your phone about it.</p>
## What Inspector does
<p align="center">
<a href="./INSTALL.md">Install with Portainer</a> ·
<a href="./src/inspector/assets/guide/guide.html">How-to guide</a> ·
<a href="./CHANGELOG.md">Changelog</a>
</p>
- 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.
![Inspector status page](src/inspector/assets/guide/status.png)
## What Inspector is not
## What it does
- 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.
- **Watches the containers you choose.** Each check sorts a container into
healthy, unhealthy, not running, starting, and so on.
- **Restarts them when they break**, with sensible brakes: a container has to fail
several checks in a row first, there's a cooldown between restarts, a grace
period while it boots, and an hourly cap so a crash-looping app can't take over
your server.
- **Alerts you** through [Gotify](https://gotify.net) and/or
[Pushover](https://pushover.net): once when something breaks, once when it's
restarted, once when it recovers. Not on every check.
- **Is set up entirely in the browser.** Add, edit, and remove containers, set up
notifications (with a **Send test** button), and change every setting from the
dashboard. No YAML editing needed.
- **Keeps a history.** The Events page shows a day-by-day timeline of failures,
restarts, and recoveries, and an optional digest summarizes it for you.
- **Stays out of the way when you're working.** Put a container in maintenance or
mute its alerts with one click, or set a nightly maintenance window for backups
and updates.
## Install
See [`INSTALL.md`](./INSTALL.md). TL;DR:
Inspector is built to be installed from **Portainer**: paste one compose file into
**Stacks → Add stack**, set a folder and a password, deploy. Inspector creates its
own config and sets up Docker access by itself.
```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
```
**→ [Step-by-step Portainer install](./INSTALL.md)**
## Configuration
## Using it
Everything lives in `config.yml` next to the compose file. Start from
[`config.example.yml`](./config.example.yml) — every key is commented.
Highlights:
Once it's running, click **Help** in the dashboard header for the illustrated
guide (the same guide is in this repo at
[`src/inspector/assets/guide/guide.html`](./src/inspector/assets/guide/guide.html);
download it and open it in a browser to read it here).
- `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.
| Add a container | Restart rules |
|---|---|
| ![New container form](src/inspector/assets/guide/container-new.png) | ![Container settings](src/inspector/assets/guide/container-edit.png) |
### Dashboard and settings page
| Notifications | Events history |
|---|---|
| ![Notification settings](src/inspector/assets/guide/settings-notifications.png) | ![Events timeline](src/inspector/assets/guide/events.png) |
If `dashboard.enabled: true`, Inspector exposes a small web UI on
`:8080`:
## What it isn't
- `/` — 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**.
- **Not a monitoring/metrics system.** No graphs of CPU or memory; use Grafana,
Netdata, or Uptime Kuma for that.
- **Not an orchestrator.** It only touches the containers you add, and only to
restart them.
- **One Docker host per Inspector.** Run one copy on each server.
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.
## Advanced options
### Notifications
Most people never need these. They live in `config.yml` (in your
`INSPECTOR_DATA/config` folder) rather than the dashboard; see
[`config.example.yml`](./config.example.yml) for every option with comments.
Both channels are independent. If both are enabled, every alert goes to
both. Inspector sends on transitions:
- **HTTP checks**: mark a container `UNREACHABLE` when a URL stops answering,
even if Docker says it's healthy (useful for apps behind a VPN container).
- **Uptime Kuma**: use a Kuma status page as an extra reachability signal.
- **Dependencies** (`depends_on`): don't restart an app while the container it
relies on (e.g. a VPN) is down.
- **Portainer stack redeploy**: for containers that share a VPN container's
network, recover by redeploying the whole stack instead of restarting one
container.
```
🚨 first failure threshold crossed
🔁 container restart triggered
✅ restart / start completed
✅ container recovered
🛑 restart failed / hourly limit exceeded
❓ configured container not found
```
## Security
Gotify messages are Markdown; Pushover doesn't render Markdown so the
`**bold**` passthrough is cosmetic — bodies are identical.
Inspector needs the Docker socket (`/var/run/docker.sock`) to restart containers,
and that socket is effectively root on your server. So:
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.
- Keep the dashboard on your home network, or put it behind a VPN or a reverse
proxy with authentication. Don't expose port 8080 to the internet.
- Use a real dashboard password.
- Inspector itself runs as an unprivileged user; it starts as root only to detect
the socket's permissions and fix ownership of its own folders.
## Docker socket security
## Versions
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`.
Releases follow `MAJOR.MINOR.PATCH`. Every release is published as an image tag;
`latest` is the newest. See the [CHANGELOG](./CHANGELOG.md) for what changed, and
[INSTALL.md](./INSTALL.md#4-updating) for updating, pinning, and rolling back.
## License
[MIT](./LICENSE).
[MIT](./LICENSE) © 2026 Europium 63