TwiN/gatus
Automated developer-oriented status page with alerting and incident support
Healthy across the board
weakest axisPermissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 6d ago
- ✓29+ active contributors
- ✓Distributed ownership (top contributor 32% of recent commits)
Show all 6 evidence items →Show less
- ✓Apache-2.0 licensed
- ✓CI configured
- ✓Tests present
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/twin/gatus)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/twin/gatus on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: TwiN/gatus
Generated by RepoPilot · 2026-05-09 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/TwiN/gatus shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
GO — Healthy across the board
- Last commit 6d ago
- 29+ active contributors
- Distributed ownership (top contributor 32% of recent commits)
- Apache-2.0 licensed
- CI configured
- Tests present
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live TwiN/gatus
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/TwiN/gatus.
What it runs against: a local clone of TwiN/gatus — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in TwiN/gatus | Confirms the artifact applies here, not a fork |
| 2 | License is still Apache-2.0 | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | Last commit ≤ 36 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of TwiN/gatus. If you don't
# have one yet, run these first:
#
# git clone https://github.com/TwiN/gatus.git
# cd gatus
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of TwiN/gatus and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "TwiN/gatus(\\.git)?\\b" \\
&& ok "origin remote is TwiN/gatus" \\
|| miss "origin remote is not TwiN/gatus (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(Apache-2\\.0)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"Apache-2\\.0\"" package.json 2>/dev/null) \\
&& ok "license is Apache-2.0" \\
|| miss "license drift — was Apache-2.0 at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 36 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~6d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/TwiN/gatus"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
Gatus is a developer-oriented health dashboard that monitors services via HTTP, ICMP, TCP, and DNS queries, evaluating results against conditions (status codes, response times, certificate expiration, body content, etc.) and triggering alerts through Slack, Teams, PagerDuty, Discord, Twilio, and 20+ integrations. It's built in Go with a Vue.js frontend and provides a self-hosted alternative to commercial uptime monitoring. Monolithic Go binary with internal packages for health checks, alerting, storage, and web serving. Frontend is Vue.js (142K lines) compiled into the binary. Configuration driven via YAML files (see .examples/ for docker-compose, postgres, sqlite, mTLS, Grafana setups). Storage backends are pluggable (SQLite, PostgreSQL). Alerting integrations are factory-pattern modules in internal/alerting/.
👥Who it's for
DevOps engineers and backend developers who need to monitor internal and external service health with custom alerting rules and want to self-host rather than use SaaS platforms. Teams running Kubernetes clusters or Docker environments who need a lightweight, configurable status page.
🌱Maturity & risk
Actively maintained and production-ready. The codebase is 1.6M lines of Go with comprehensive test coverage (codecov badge present), established CI/CD via GitHub Actions (test.yml workflow), and a large Docker Hub presence (badge indicates thousands of pulls). Recent updates to Go 1.25.5 and active example configurations suggest ongoing development.
Single maintainer (TwiN) creates continuity risk, though the project is well-documented with multiple deployment examples. High external dependency count (AWS SDK, Prometheus, gRPC, OIDC libraries) increases attack surface. The codebase is mature with no apparent dormancy, but monitor the maintainer's bandwidth—this is not a corporate-backed project.
Active areas of work
Project appears actively maintained with recent dependency updates (Go 1.25.5, latest client libraries). The .examples/ directory shows ongoing support for multiple deployment patterns (Grafana/Prometheus integration, mTLS, multi-config files, Postgres storage). No specific breaking changes visible, but check GitHub releases for the latest milestone work.
🚀Get running
git clone https://github.com/TwiN/gatus.git && cd gatus && make build (or docker run -p 8080:8080 ghcr.io/twin/gatus:stable for quickstart). See .examples/docker-compose/config/config.yaml for minimal configuration structure.
Daily commands: make build produces a binary. For development: create a config.yaml, then ./gatus (binary) or docker-compose up -d (using .examples/docker-compose/compose.yaml). The service listens on :8080 by default. See .examples/ for different storage/monitoring setups.
🗺️Map of the codebase
- internal/core/endpoint.go: Core health check logic: defines Endpoint struct and result evaluation against conditions
- internal/config/config.go: YAML configuration parsing for all services, endpoints, alerting, and UI settings
- internal/alerting/alert.go: Alert handler routing to provider-specific implementations; critical for understanding how alerts flow
- main.go: Application entry point; initializes config, storage, web server, and health check scheduler
- .examples/docker-compose/config/config.yaml: Concrete example of minimal configuration; reference for first-time configuration
- web/: Vue.js frontend source; UI components for dashboard, status visualization, and settings
- internal/storage/: Storage abstraction layer; handles persistence for SQLite and PostgreSQL backends
🛠️How to make changes
Start with internal/core/ for health check logic. Add new alert providers in internal/alerting/provider/ (copy an existing provider like Discord). Configuration parsing is in internal/config/. Frontend changes go in web/ (Vue components). Add new check types (e.g., new protocol) in internal/endpoint/. Tests follow Go convention (*_test.go files in same package).
🪤Traps & gotchas
Configuration is YAML-based and loaded from a single file (or multiple files via config globbing) before startup—no hot-reload. WebSocket connections require special handling in proxies (see mTLS example for Nginx config in .examples/docker-compose-mtls/nginx/). External endpoints can pull configs from URLs, but they're parsed once at startup. DNS and ICMP checks require appropriate OS permissions (CAP_NET_RAW for ICMP in containers). Storage backend choice (SQLite vs PostgreSQL) must be set at config time; switching requires data migration logic outside Gatus.
💡Concepts to learn
- Health Check Conditions (CEL-like DSL) — Gatus evaluates arbitrary conditions on response data (status code, latency, body regex, certificate expiration) to determine health; understanding the condition syntax is critical for configuring meaningful checks
- Provider Pattern for Alerting — Each alert channel (Slack, Discord, PagerDuty, etc.) is a pluggable provider with a common Alert() interface; new contributors need this pattern to add alert integrations
- WebSocket Real-Time Updates — The Vue.js dashboard receives live health check updates via WebSocket (gorilla/websocket); understanding this enables debugging UI sync issues and real-time features
- ICMP Ping (pro-bing library) — Gatus can monitor host reachability via ICMP (ping), not just HTTP; this requires raw socket access and special handling in containerized environments
- Certificate Expiration Monitoring (x509 parsing) — One of Gatus's unique features is evaluating TLS certificate expiration as a condition; this uses Go's crypto/x509 package and requires HTTPS endpoint checks
- Multi-Config File Loading (YAML Globbing) — Gatus can merge multiple YAML config files at startup (see .examples/docker-compose-multiple-config-files/); understanding deepmerge behavior is crucial for modular deployments
- DNS Query Monitoring (miekg/dns) — Gatus can perform DNS lookups and evaluate response codes/records; this enables monitoring of DNS infrastructure health, not just HTTP endpoints
🔗Related repos
Primetheus/prometheus— Gatus exports metrics in Prometheus format and can be visualized alongside Prometheus-scraped data; the docker-compose-grafana-prometheus example uses bothgrafana/grafana— Gatus metrics integrate with Grafana dashboards; .examples/docker-compose-grafana-prometheus includes a pre-built Gatus dashboarduptimerobot/api— Direct competitor in the uptime monitoring space; Gatus is the self-hosted open alternativestatping-ng/statping— Alternative self-hosted status page/uptime monitor written in Go; similar feature set but different codebaseTwiN/g8— Lightweight HTTP client library by the same author, used internally by Gatus for efficient HTTP health checks
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add integration tests for Docker Compose examples with validation
The repo contains 7+ Docker Compose examples (.examples/docker-compose-*) but there's no automated validation that they actually work. A new contributor could add a GitHub Actions workflow that spins up each compose stack, validates Gatus starts correctly, performs basic health checks, and verifies expected endpoints are reachable. This catches configuration drift and breaking changes early.
- [ ] Create .github/workflows/test-compose-examples.yml workflow file
- [ ] Add a test script that iterates through .examples/docker-compose-* directories
- [ ] For each compose.yaml: validate syntax, spin up with docker-compose, wait for service health, make test HTTP requests to verify functionality
- [ ] Test at least: docker-compose, docker-compose-postgres-storage, docker-compose-sqlite-storage, and docker-compose-grafana-prometheus examples
- [ ] Add step to tear down containers and report results
Add unit tests for YAML config parsing across multiple config files
The .examples/docker-compose-multiple-config-files example shows config splitting (global.yaml, backend.yaml, frontend.yaml), but there's likely no test coverage for the deepmerge config loading logic mentioned in go.mod (github.com/TwiN/deepmerge). A contributor should add tests for config merging edge cases: duplicate keys, nested structures, override behavior, and validation of the final merged config.
- [ ] Identify the config loading/merging code in the main source tree
- [ ] Create tests/config_merge_test.go with test cases for: simple key override, nested object merging, list concatenation vs replacement behavior
- [ ] Add test case specifically matching the multiple-config-files example structure (global → backend → frontend)
- [ ] Test error scenarios: conflicting values, invalid YAML in files, missing required fields after merge
- [ ] Verify deepmerge library behavior matches documentation
Add mTLS/certificate validation tests for docker-compose-mtls example
The .examples/docker-compose-mtls directory contains pre-generated certificates (client.crt/key, server.crt/key, ca.crt) but there's no apparent test validating the mTLS setup actually works. A contributor could add tests that verify the cert chain is valid, test mutual authentication scenarios, and ensure certificate validation rejects invalid certs—improving security posture and catching cert rotation issues.
- [ ] Create tests/mtls_validation_test.go to validate certificate structure and chain
- [ ] Test scenarios: valid mTLS connection, missing client cert, expired cert (or create one in tests), invalid server cert, CA verification
- [ ] Add integration test that starts the mTLS compose stack and verifies bidirectional cert validation works
- [ ] Document the certificate generation method used in .examples/docker-compose-mtls/certs so others can regenerate if needed
- [ ] Verify Gatus properly handles certificate validation errors and logs them appropriately
🌿Good first issues
- Add integration tests for the PostgreSQL storage backend in internal/storage/ (currently only unit tests exist; docker-compose-postgres-storage shows the setup but no tests reference it)
- Document the placeholders and functions available in condition evaluation (README mentions them in the Table of Contents but the actual list is incomplete; inspect internal/core/conditions.go and add a reference table to docs/conditions.md)
- Create a Prometheus alerting example in .examples/ that shows how to trigger Gatus health checks from Prometheus rules (docker-compose-grafana-prometheus exists but lacks a Prometheus alerts config; this would be valuable for users bridging both systems)
⭐Top contributors
Click to expand
Top contributors
- @dependabot[bot] — 32 commits
- @TwiN — 20 commits
- @PythonGermany — 18 commits
- @Copilot — 3 commits
- @GiamPy5 — 2 commits
📝Recent commits
Click to expand
Recent commits
fba833f— chore(deps): bump modernc.org/sqlite from 1.48.2 to 1.50.0 (#1647) (dependabot[bot])834bfab— chore(deps): bump github.com/aws/aws-sdk-go-v2/credentials from 1.19.13 to 1.19.15 (#1645) (dependabot[bot])f9e03cb— chore(deps): bump codecov/codecov-action from 5.5.3 to 6.0.0 (#1601) (dependabot[bot])760b753— chore(deps): bump modernc.org/sqlite from 1.47.0 to 1.48.2 (#1627) (dependabot[bot])447c7ad— docs: Document remote.client configuration (#1637) (surdaft)bc43316— fix(storage): close rows before nested queries to prevent PostgreSQL driver error (#1503) (osalloum)42b51f5— fix(test): Remove t.Parallel() from tests racing on injectedHTTPClient (#1630) (Copilot)48056de— chore(deps): bump google.golang.org/api from 0.265.0 to 0.273.1 (#1613) (dependabot[bot])f06c4f1— chore(deps): bump actions/github-script from 8 to 9 (#1624) (dependabot[bot])64116ce— docs(ai): Add AGENTS.md (TwiN)
🔒Security observations
- High · Outdated Go Cryptography Library —
go.mod - golang.org/x/crypto v0.49.0. The dependency 'golang.org/x/crypto v0.49.0' is outdated. The current stable version is significantly newer (v0.31.0+). Using outdated cryptographic libraries may expose the application to known security vulnerabilities and cryptographic weaknesses. Fix: Update to the latest version of golang.org/x/crypto by running 'go get -u golang.org/x/crypto' and thoroughly test the application for compatibility. - High · Outdated OAuth2 Library —
go.mod - golang.org/x/oauth2 v0.36.0. The dependency 'golang.org/x/oauth2 v0.36.0' is significantly outdated. OAuth2 security patches and improvements are critical for authentication security. Using outdated versions may expose the application to authentication bypass or token handling vulnerabilities. Fix: Update to the latest version of golang.org/x/oauth2 by running 'go get -u golang.org/x/oauth2' and test authentication flows thoroughly. - Medium · Hardcoded Default Config Path in Docker Image —
Dockerfile - COPY --from=builder /app/config.yaml ./config/config.yaml. The Dockerfile includes a default configuration file 'config.yaml' copied into the image at '/app/config/config.yaml'. If this file contains any sensitive information or default credentials, it would be exposed in the container image. Fix: Ensure the config.yaml file does not contain any hardcoded secrets, credentials, or sensitive information. Use environment variables or external secret management systems for sensitive configuration. Consider not including default configs in production images. - Medium · Empty GATUS_CONFIG_PATH Environment Variable —
Dockerfile - ENV GATUS_CONFIG_PATH="". The Dockerfile sets 'ENV GATUS_CONFIG_PATH=""' with an empty value. This could lead to configuration loading from unexpected locations or default paths if the application doesn't handle empty config paths securely. Fix: Set a specific default configuration path or ensure the application properly validates and handles empty config path values. Document expected behavior when this variable is not set. - Medium · Exposed Metrics Port via Prometheus —
go.mod - github.com/prometheus/client_golang v1.23.2. The project integrates Prometheus client library (prometheus/client_golang v1.23.2) which typically exposes metrics on an accessible port. If metrics endpoints are not properly authenticated or restricted, they could leak sensitive information about the system's internal state, performance metrics, or service configuration. Fix: Ensure Prometheus metrics endpoints are authenticated, rate-limited, or restricted to trusted networks only. Use network policies or reverse proxy authentication to protect metrics exposure. - Medium · WebSocket Implementation Lacks Security Controls —
go.mod - github.com/gorilla/websocket v1.5.3. The codebase uses gorilla/websocket v1.5.3 for WebSocket functionality. WebSocket connections can be vulnerable to CSRF attacks, message injection, or privilege escalation if not properly validated and authenticated. Fix: Implement proper WebSocket origin validation, CSRF tokens, message authentication, and rate limiting. Validate all incoming WebSocket messages and authenticate users before establishing WebSocket connections. - Medium · DNS Query Functionality May Enable DNS Enumeration —
go.mod - github.com/miekg/dns v1.1.72. The project uses miekg/dns v1.1.72 and offers DNS query monitoring capabilities. This could potentially be abused as a DNS proxy or for DNS enumeration attacks if not properly rate-limited and validated. Fix: Implement rate limiting on DNS queries, validate query types and domains, restrict DNS query functionality to authorized users, and monitor for suspicious DNS query patterns. - Medium · OIDC Implementation Complexity —
go.mod - github.com/coreos/go-oidc/v3 v3. The project uses coreos/go-oidc/v3 v3.17.0 for OpenID Connect authentication. OIDC implementations are complex and prone to misconfigurations such as insufficient token validation, redirect URI validation, or state parameter handling. Fix: undefined
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.