Backup freshness monitor with ntfy alerts
  • Python 98.8%
  • Dockerfile 1.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Vela 6081aeecfe
All checks were successful
CI / test (push) Successful in 9s
Only start alert cooldown after a successful send
A failed ntfy delivery (e.g. ntfy not yet up after boot) set the 24h
cooldown anyway, delaying the alert by a day.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-21 19:32:00 -03:00
.forgejo/workflows Initial commit: Anchor backup freshness monitor 2026-08-17 10:05:31 -04:00
.github/workflows Initial commit: Anchor backup freshness monitor 2026-08-17 10:05:31 -04:00
.gitignore Initial commit: Anchor backup freshness monitor 2026-08-17 10:05:31 -04:00
anchor.py Only start alert cooldown after a successful send 2026-10-21 19:32:00 -03:00
Dockerfile Initial commit: Anchor backup freshness monitor 2026-08-17 10:05:31 -04:00
LICENSE Initial commit: Anchor backup freshness monitor 2026-08-17 10:05:31 -04:00
README.md Add NTFY_MAX_PRIORITY to cap alert priority 2026-10-20 14:35:55 -03:00
test_anchor.py Only start alert cooldown after a successful send 2026-10-21 19:32:00 -03:00

Anchor

CI Release Container

Backup freshness monitor with ntfy alerts. Watches backup files and directories, alerts when they go stale or missing.

Zero dependencies. Single Python file, stdlib only. Docker-native.

Part of the Harbor self-hosted monitoring suite: Lookout (container lifecycle) · Beacon (status page) · Bosun (log alerts) · Sextant (TLS certs) · Drift (image updates) · Anchor (backup freshness)

Quick Start

services:
  anchor:
    image: ghcr.io/agent-cyanez/anchor
    volumes:
      - /path/to/backups:/backups:ro
    environment:
      BACKUP_TARGETS: "daily-db:/backups/db:24h,weekly-photos:/backups/photos:168h"
      NTFY_URL: http://ntfy:80
      NTFY_TOPIC: backups

How It Works

Anchor periodically checks the modification time of backup files and directories. If a backup hasn't been updated within its expected interval, Anchor sends an alert via ntfy.

  • Files: Checks the file's modification time directly
  • Directories: Finds the newest file recursively and checks its modification time
  • Missing paths: Alerts immediately if the path doesn't exist

Configuration

Variable Default Description
BACKUP_TARGETS (required) Comma-separated targets: label:path:max_age
NTFY_URL http://localhost:80 ntfy server URL
NTFY_TOPIC backups ntfy topic for alerts
NTFY_MAX_PRIORITY (none) Ceiling for alert priority (min, low, default, high, urgent). Set to default to keep high/urgent free for messages a human must see
CHECK_INTERVAL 3600 Seconds between checks
ALERT_COOLDOWN 86400 Seconds before re-alerting for same issue
HEALTH_PORT 8586 HTTP port for health/API endpoint

Target Format

Each target is label:path:max_age where:

  • label — human-readable name (e.g. daily-db, weekly-photos)
  • path — file or directory to check (must be mounted in the container)
  • max_age — maximum acceptable age: 30m, 24h, 7d, or seconds

Examples

# Single daily database backup
BACKUP_TARGETS="postgres:/backups/db/latest.sql.gz:24h"

# Multiple schedules
BACKUP_TARGETS="db:/backups/db:24h,photos:/backups/photos:168h,config:/backups/config:48h"

# Hourly log archives
BACKUP_TARGETS="logs:/backups/logs:2h"

API

GET /health

Returns ok — for Docker healthcheck and Beacon integration.

GET /api/status

Returns JSON with current backup status:

{
  "targets": [
    {
      "label": "daily-db",
      "path": "/backups/db",
      "status": "fresh",
      "message": "backup is 3h 15m old",
      "max_age": 86400,
      "age": 11700
    }
  ],
  "checked_at": "2026-08-17T14:00:00Z"
}

Status values: fresh (within max_age), stale (exceeded max_age), missing (path not found).

License

MIT