Skip to main content

Gatus

A self-hosted uptime and health monitoring dashboard.

Gatus is an open-source health dashboard that periodically checks HTTP, TCP, and DNS endpoints and displays uptime status. It stores historical data in PostgreSQL and supports alerting via various channels. Self-hosting means no usage limits and full control over which internal services are monitored.

Alternatives considered​

Cloud Hosted

ToolOpen SourceFree TierMonthly Cost
UptimeRobotNoLimitedFrom $7/mo
PingdomNoNoFrom $15/mo

Self Hosted

ToolOpen SourceFull FeaturesNotes
Uptime KumaYesYesSimpler UI, less config flexibility

Installation​

Architecture​

  • Deployment: Single gatus deployment in the gatus namespace; NetBird sidecar for VPN connectivity
  • Images: ghcr.io/twin/gatus, netbirdio/netbird, both digest-pinned via Renovate
  • Database: CNPG PostgreSQL cluster for uptime history
  • Config: Multiple ConfigMaps with endpoint definitions (arr services, internal tools, public web services)
  • Networking: HTTPRoute via public gateway

Security​

  • Gatus container: readOnlyRootFilesystem: true, allowPrivilegeEscalation: false, capabilities dropped
  • NetBird sidecar adds NET_ADMIN and NET_RAW on top of drop-all (VPN tunnel; NetBird 0.75+ opens a raw socket when bringing up the interface). It is not privileged
  • runAsNonRoot: false on the pod level (namespace PSS set to privileged)

Updates​

Managed by Renovate. Both images are digest-pinned.

Data Management​

  • Database: CNPG PostgreSQL cluster (Longhorn-encrypted PVCs) for uptime history
  • Backups: k8up Schedules to Hetzner and Backblaze via restic (workload-talos-gatus-f4b5c644), covering the database dump from the backups-cnpg PreBackupPod. Retention: last 5, 7 daily, 4 weekly, 12 monthly, 5 yearly.

User Management​

OIDC configured — OPENID_CLIENT_ID and OPENID_CLIENT_SECRET injected from SOPS secret. Issuer and redirect URL set in the Gatus config ConfigMap.

Configuration Management​

  • Endpoint definitions from multiple ConfigMaps (arr services, internal tools, public web)
  • OIDC credentials from SOPS-encrypted secret
  • Database connection string from CNPG-generated secret

Usage​

View the uptime dashboard to see current status of all monitored endpoints grouped by category (Arr, Int, Web, Talos). Configure new endpoints by editing the ConfigMap YAML files. Alerts can be triggered via the configured channels when checks fail.

Cluster-specific deviations from the above live in the per-cluster README — see k8s/apps/gatus/talos/README.md.

Cluster Deployment​

Gatus — Talos cluster

Kubernetes Metadata
  • Image: ghcr.io/twin/gatus:v5.37.0@sha256:094eb186e55235db367e90e9d56140e5897b7044c41de23cde4cc18e6da1242e
  • Image: netbirdio/netbird:0.81.2@sha256:6242a1fbaf6b611c00c26a914cbbea512c30c18a45de0646ce7b0e5d93a21e67
Rendered manifests (kustomize build)
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
kustomize.toolkit.fluxcd.io/force: enabled
labels:
app.kubernetes.io/name: gatus
name: gatus
namespace: gatus
spec:
replicas: 1
revisionHistoryLimit: 2
selector:
matchLabels:
app.kubernetes.io/name: gatus
strategy:
type: Recreate
template:
metadata:
labels:
app.kubernetes.io/name: gatus
spec:
automountServiceAccountToken: false
containers:
- env:
- name: GATUS_CONFIG_PATH
value: /config
- name: POSTGRES_PATH
valueFrom:
secretKeyRef:
key: uri
name: cnpg-app
- name: SMTP_HOST
valueFrom:
secretKeyRef:
key: host
name: allinkl-smtp-credentials
- name: SMTP_PORT
valueFrom:
secretKeyRef:
key: port
name: allinkl-smtp-credentials
- name: SMTP_USERNAME
valueFrom:
secretKeyRef:
key: username
name: allinkl-smtp-credentials
- name: SMTP_PASSWORD
valueFrom:
secretKeyRef:
key: password
name: allinkl-smtp-credentials
- name: SMTP_FROM
valueFrom:
secretKeyRef:
key: from
name: allinkl-smtp-credentials
envFrom:
- secretRef:
name: gatus
image: ghcr.io/twin/gatus:v5.37.0@sha256:094eb186e55235db367e90e9d56140e5897b7044c41de23cde4cc18e6da1242e
livenessProbe:
failureThreshold: 5
httpGet:
path: /
port: 8080
initialDelaySeconds: 15
periodSeconds: 5
successThreshold: 1
timeoutSeconds: 5
name: gatus
ports:
- containerPort: 8080
name: web
protocol: TCP
readinessProbe:
failureThreshold: 5
httpGet:
path: /
port: 8080
initialDelaySeconds: 15
periodSeconds: 5
successThreshold: 1
timeoutSeconds: 5
resources:
limits:
memory: 128Mi
requests:
cpu: 25m
memory: 64Mi
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
privileged: false
readOnlyRootFilesystem: true
startupProbe:
failureThreshold: 5
httpGet:
path: /
port: 8080
initialDelaySeconds: 15
periodSeconds: 5
successThreshold: 1
timeoutSeconds: 5
volumeMounts:
- mountPath: /config
name: gatus-config
readOnly: true
initContainers:
- env:
- name: NB_SETUP_KEY
valueFrom:
secretKeyRef:
key: NB_SETUP_KEY
name: gatus-netbird
image: netbirdio/netbird:0.81.2@sha256:6242a1fbaf6b611c00c26a914cbbea512c30c18a45de0646ce7b0e5d93a21e67
name: sidecar-netbird
resources:
limits:
memory: 128Mi
requests:
cpu: 25m
memory: 64Mi
restartPolicy: Always
securityContext:
allowPrivilegeEscalation: false
capabilities:
add:
- NET_ADMIN
- NET_RAW
drop:
- ALL
startupProbe:
exec:
command:
- sh
- -c
- netbird status | grep -q Connected
failureThreshold: 30
periodSeconds: 2
priorityClassName: tier-2
volumes:
- configMap:
name: gatus-config-594c4k9588
name: gatus-config