nikarh/healthmon

A primitive tool to monitor health of Docker containers

★ 0Forks 0GoGitHub ↗Compare

README

healthmon

CI Release License: MIT License: Apache-2.0

Healthmon watches Docker containers via the Docker socket, detects restart loops, healing, and container recreation/image changes, and exposes a real-time dashboard with REST + WebSocket updates. Alerts are pushed to Telegram.

Features

  • Detect restart loops (red), healed restart loops (green), image change or other recreate events (blue).
  • Keeps full event history and container metadata in SQLite.
  • REST API + WebSocket updates for live UI.
  • Single static binary and scratch Docker image.

Configuration

Env var Default Description
HM_DB_PATH ./healthmon.db SQLite DB path
HM_DOCKER_HOST unix:///var/run/docker.sock Docker host URL (e.g. unix:///var/run/docker.sock or tcp://socket-proxy:2375)
HM_HTTP_ADDR :8080 HTTP bind address
HM_TG_ENABLED false Enable Telegram alerts
HM_TG_TOKEN (empty) Telegram bot token (required if enabled)
HM_TG_CHAT_ID (empty) Telegram chat ID (required if enabled)
HM_RESTART_WINDOW_SECONDS 300 Restart loop window
HM_RESTART_THRESHOLD 3 Restart loop threshold

Container labels

Healthmon can separate always-on services from one-shot tasks in the UI.

  • healthmon.role=service (default): treated as a service.
  • healthmon.role=task: treated as a one-shot task/sidecar.

Run with Docker

Recommended: use a Docker socket proxy like https://github.com/11notes/docker-socket-proxy instead of mounting the raw socket.

docker run --rm \
  -p 8080:8080 \
  -e HM_DB_PATH=/data/healthmon.db \
  -e HM_TG_ENABLED=true \
  -e HM_TG_TOKEN=YOUR_TOKEN \
  -e HM_TG_CHAT_ID=YOUR_CHAT_ID \
  -e HM_DOCKER_HOST=tcp://socket-proxy:2375 \
  -e TZ=Etc/UTC \
  -v $(pwd)/data:/data \
  --read-only \
  --cap-drop ALL \
  --security-opt no-new-privileges \
  ghcr.io/nikarh/healthmon:latest

Run with docker-compose

services:
  socket-proxy:
    image: ghcr.io/11notes/docker-socket-proxy:stable
    restart: unless-stopped
    environment:
      CONTAINERS: 1
      EVENTS: 1
      INFO: 1
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro

  healthmon:
    image: ghcr.io/nikarh/healthmon:latest
    ports:
      - "8080:8080"
    environment:
      HM_DB_PATH: /data/healthmon.db
      HM_TG_ENABLED: true
      HM_TG_TOKEN: YOUR_TOKEN
      HM_TG_CHAT_ID: YOUR_CHAT_ID
      HM_DOCKER_HOST: tcp://socket-proxy:2375
      TZ: Etc/UTC
    user: "65534:65534"
    volumes:
      - ./data:/data
    read_only: true
    cap_drop:
      - ALL
    security_opt:
      - no-new-privileges:true
    depends_on:
      - socket-proxy

Local development

Backend (Go):

go run -tags dev ./cmd/healthmon

Frontend (Vite + hot reload):

cd web
npm install
npm run dev

Then open http://localhost:5173 for the UI (Vite dev server) while the backend runs on http://localhost:8080.

One-command dev (hot reload front + back):

mise run dev

Production build note: the backend embeds the UI from cmd/healthmon/web/dist. Run npm run build in web/ before go build ./cmd/healthmon (non-dev builds).

Static checks and formatting

Backend:

gofmt -w .
go vet ./...

Frontend:

cd web
npm run lint
npm run format

One-command check:

mise run check

REST API

  • GET /api/containers returns all containers with current status and last event.
  • GET /api/containers/{name}/events?before_id={id}&limit={n} returns paginated events.
  • GET /api/events?before_id={id}&limit={n} returns paginated events across all containers.
  • GET /api/events/stream WebSocket pushes live updates.

License

Licensed under either MIT (LICENSE-MIT) or Apache-2.0 (LICENSE-APACHE).

Contributors

dependabot[bot]nikarh

Issues