Telemetry, System Uptime, & Network Data Engine for Rapid Evaluation
A lightweight, agent-based monitoring system. It's not like it was built because Uptime Kuma chokes on many collection points or anything… b-baka.
- Tiny footprint — two static Go binaries + SQLite. Runs happily on the cheapest VPS you can find.
- Agent-based — agents pull their monitor config from the server and push results back. No inbound ports on monitored hosts, only outbound HTTPS.
- Dark mode only. No flashbangs. Ever.
| Type | What it does |
|---|---|
docker |
Container running/healthy, or Swarm service task count vs. desired replicas — via docker.sock |
ping |
ICMP ping to an IP/host (uses the system ping, no root needed) |
dns |
Queries a name against a specific DNS server (A/AAAA/CNAME/MX/NS/TXT, optional expected answer) |
https |
HTTP(S) check with status code, optional keyword match, and TLS certificate expiry detection |
- Status pages like Uptime Kuma's: friendly name, 30-day uptime percentage, and green
bars for the last 30 minutes. Create as many pages as you like, each with its own monitor
selection, at
/status/<slug>. A per-page "Display host name" option shows the agent's hostname under each monitor — handy when several hosts run identically named containers (e.g. a PG-HA cluster). - Incidents — publish/resolve incidents per status page (info/minor/major/critical).
- Maintenance windows — schedule them, pick the affected monitors; their alerts are paused during the window and the window is announced on the status page.
- Alerts via Discord webhook and/or SMTP mail on every up/down transition.
- Docker mapping — agents report their container & Swarm service inventory, so creating a docker monitor is: pick agent → pick container/service from a dropdown → give it a friendly name. Done.
- Admin auth via GitHub OAuth, allow-listed by GitHub username.
- Read-only API at
/api/v1for external dashboards (e.g. the TSUNDERE Portal), gated by API keys you mint in the admin UI. It's strictly GET-only — seedocs/API.md. - Everything except OAuth is configured in the admin web UI.
GitHub → Settings → Developer settings → OAuth Apps → New.
Callback URL: https://your-server/auth/callback.
cp .env.example .env # fill in OAuth credentials + your GitHub username
docker compose up -d serverOr without Docker:
go build ./cmd/tsundere-server
TSUNDERE_BASE_URL=https://status.example.com \
TSUNDERE_GITHUB_CLIENT_ID=… \
TSUNDERE_GITHUB_CLIENT_SECRET=… \
TSUNDERE_ADMIN_USERS=4G0NYY \
./tsundere-serverPut it behind your reverse proxy of choice for TLS. It listens on :8420 by default.
In the admin UI: Agents → + New agent. Copy the token (shown once!), then on each host:
tsundere-agent -server https://status.example.com -token tsa_…or via Docker (gives the agent access to the host's Docker daemon):
docker run -d --restart unless-stopped --name tsundere-agent \
-e TSUNDERE_SERVER_URL=https://status.example.com \
-e TSUNDERE_AGENT_TOKEN=tsa_… \
-e TSUNDERE_HOSTNAME="$(hostname)" \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
ghcr.io/4g0nyy/tsundere-agent:latestHostname in Docker. By default the agent reports its OS hostname, but inside a container that's the container ID — not the host you actually care about. Set
TSUNDERE_HOSTNAME(e.g. to$(hostname), evaluated on the host as above) to report a sensible name. This is what the status page's "Display host name" option shows.
Images for the agent and server are built automatically for amd64/arm64 on every push
to main (see .github/workflows/docker.yml). The images contain nothing but the
compiled binary — tokens and settings are passed in at runtime, so they're safe to
keep public.
The agent phones home every 30 seconds for its monitor list, so new/edited monitors are picked up automatically. If an agent stops reporting, its monitors are marked down after ~2 missed intervals and you get alerted.
| Variable | Default | Purpose |
|---|---|---|
TSUNDERE_LISTEN |
:8420 |
listen address |
TSUNDERE_DB |
tsundere.db |
SQLite file path |
TSUNDERE_BASE_URL |
http://localhost:8420 |
public URL (OAuth callback, cookie security) |
TSUNDERE_GITHUB_CLIENT_ID |
— | GitHub OAuth app client ID |
TSUNDERE_GITHUB_CLIENT_SECRET |
— | GitHub OAuth app client secret |
TSUNDERE_ADMIN_USERS |
— | comma-separated GitHub usernames allowed as admins |
TSUNDERE_DEV_NO_AUTH |
— | set to 1 to disable auth. Local development only. |
Everything else — site title, Discord webhook, SMTP host/port/credentials/recipients — lives in Settings in the admin UI, with test buttons for both alert channels.
| Flag | Env | Default | Purpose |
|---|---|---|---|
-server |
TSUNDERE_SERVER_URL |
— | server base URL |
-token |
TSUNDERE_AGENT_TOKEN |
— | agent token from the admin UI |
-docker |
TSUNDERE_DOCKER_HOST |
/var/run/docker.sock |
docker socket path or tcp://host:2375; off disables docker checks |
-hostname |
TSUNDERE_HOSTNAME |
OS hostname | hostname reported to the server; set this in Docker, where the OS hostname is the container ID |
┌────────────┐ GET /api/agent/config (Bearer token) ┌──────────────────┐
│ agent │ ───────────────────────────────────────► │ server │
│ (per host) │ ◄─────────────────────────────────────── │ SQLite + web UI │
│ docker.sock│ POST /api/agent/results, /inventory │ alerts, engine │
└────────────┘ └──────────────────┘
│ │
/admin (OAuth) /status/<slug>
Heartbeats are retained for 90 days and pruned automatically.
TSUNDERE_DEV_NO_AUTH=1 go run ./cmd/tsundere-server
# admin UI at http://localhost:8420/admin — no login required in dev modeIt's not like this README was written for you specifically or anything.