Zero dependencies · 6 MB binary

HTTP endpoint prober.
Dead simple.

Configure the endpoints you care about, set an interval, and get a Telegram message the moment something goes down — and another when it recovers. No agents, no dashboards, no YAML sprawl.

cactus — config.yaml
2026/06/02 09:00:00 cactus started with 3 probe(s)
2026/06/02 09:00:00 [public-api] OK
2026/06/02 09:00:00 [auth-api] OK
2026/06/02 09:00:00 [payment-api] OK

2026/06/02 09:01:00 [public-api] OK
2026/06/02 09:01:00 [auth-api] OK
2026/06/02 09:01:00 [payment-api] FAIL got status 503, want 200
→ Telegram  [FIRING] payment-api is down · URL: https://pay.example.com/health

2026/06/02 09:02:00 [payment-api] OK
→ Telegram  [RESOLVED] payment-api is back up
What's in the box

Everything you need. Nothing you don't.

One binary, one config file. Every probe runs in its own goroutine — no probe blocks another.

Fully parallel

Each probe runs in its own goroutine with its own ticker. A slow or hanging endpoint never delays the others.

Alert on transition only

You get one message when something breaks and one when it recovers. No repeated noise for sustained failures.

YAML config

Method, URL, interval, headers, Basic Auth, and expected status — all per probe, all in one readable file.

Telegram receiver

Plug in a bot token and chat ID and you're done. The notifier interface makes it easy to add more receivers later.

Follows redirects

The HTTP client follows up to 10 redirects automatically. What you configure is the final resolved status code.

Tiny static binary

6 MB stripped, built on scratch. Runs on any Linux host or in a minimal Docker container with no runtime deps.

Architecture

One loop per probe. Four packages.

Each probe goroutine is independent. State transitions (up→down, down→up) are detected locally and fan out to all configured receivers.

📄
Config
config.Load()
🔁
Probe
prober.Run()
🔔
Alert
notifier.Notifier
Telegram
Bot API
Quick start

Running in under a minute.

Pull the image or build from source — then point it at your config.

# Docker (recommended) $ docker pull ghcr.io/alileza/cactus:latest $ docker run -v $(pwd)/config.yaml:/config.yaml ghcr.io/alileza/cactus # Or build from source (requires Go 1.26+) $ git clone git@github.com:alileza/cactus.git $ cd cactus $ go build -ldflags="-s -w" -o cactus . $ ./cactus --config config.yaml
# config.yaml probes: - name: public-api url: https://example.com/health method: GET interval: 30s expected_status: 200 - name: protected-api url: https://example.com/admin method: GET interval: 60s auth: username: user password: pass expected_status: 200 receivers: telegram: bot_token: "YOUR_BOT_TOKEN" chat_id: "YOUR_CHAT_ID"