Gatus Common — Shared Application Configuration
Gatus_Common is the shared application layer for Gatus. It is not deployed on
its own; instead it supplies the Gatus-specific configuration that both
Gatus_GKE and Gatus_CloudRun build on, so the
two platform variants behave identically where it matters. End users never
configure this layer directly — it has no deployment UI inputs of its own — but
understanding what it provides explains the defaults you see in the platform docs.
For the infrastructure that actually provisions and runs Gatus, see the platform guides (Gatus_GKE, Gatus_CloudRun) and the foundation guides (App_GKE, App_CloudRun, App_Common).
1. What this layer provides
| Area | Provided by Gatus_Common | Where it surfaces |
|---|---|---|
| Container image | Wraps the official ghcr.io/twin/gatus image — a genuinely distroless static binary — with a baked-in config.yaml and an empty writable /data directory; builds via Cloud Build | container_image output of the platform deployment |
| Database engine | None — database_type = "NONE". Gatus has no external database; its optional history store is a local SQLite file | §Database in the platform guides |
| Database bootstrap | None — no init job is injected. initialization_jobs is passed through unchanged (empty by default) | initialization_jobs output |
| Cryptographic secrets | None — secret_ids is empty. Gatus needs no deploy-time credentials; optional basic-auth/OIDC protection is configured directly in config.yaml | — |
| Object storage | None — storage_buckets is empty | storage_buckets output |
| Core settings | Fixes container_port = 8080; endpoints/alerting/storage are entirely file-based (config.yaml), not env-var driven | Application behaviour in the platform guides |
| Health checks | Supplies the default startup/liveness probe targeting /health | §Observability in the platform guides |
The shape of the config output (the object both variants consume) is fixed here:
container_port = 8080, database_type = "NONE", image_source = "custom",
enable_image_mirroring = true, and an empty initialization_jobs /
secret_ids / storage_buckets set.
2. No secrets, no database, no buckets
Unlike most application modules, Gatus_Common generates nothing in Secret
Manager and provisions no Cloud SQL instance or GCS bucket:
secret_ids = {}andsecret_values = {}— there are no auto-generated credentials to inject. Gatus has no built-in user-account system; it does not connect to an external database and needs no bootstrap password or encryption key.storage_buckets = []— Gatus keeps everything it needs (its optional history store) in a local SQLite file, not object storage.database_type = "NONE"— no Cloud SQL for PostgreSQL/MySQL is created. The database-related variables that appear in the platform guides (db_name,db_user,enable_cloudsql_volume,database_password_length, …) are inert unless you explicitly opt in to an external database, which Gatus does not require.
Access control is a config-file step, not a post-deploy step. If you want to
require authentication to view the status page, configure Gatus's security block
(basic auth or OIDC) directly in modules/Gatus_Common/scripts/config.yaml and
rebuild the image — there is no runtime API or admin UI for this.
3. Container image — a genuinely distroless base, no entrypoint wrapper
The custom image is a thin wrapper over the official Gatus server image:
ARG GATUS_VERSION=v5.36.0
FROM alpine:3.20 AS builder
RUN mkdir -p /data
FROM ghcr.io/twin/gatus:${GATUS_VERSION}
COPY config.yaml /config/config.yaml
COPY --from=builder /data /data
EXPOSE 8080
- App-specific build ARG. The base tag is driven by
GATUS_VERSION, not the genericAPP_VERSIONthat the foundation injects. Gatus publishesv-prefixed tags (e.g.v5.36.0) and has nolatest-<x>variant, soapplication_version = "latest"maps to a pinned recent release (v5.36.0) — a fresh build never resolves a non-existent tag. This is set inGatus_Commonviagatus_image_version = var.application_version == "latest" ? "v5.36.0" : var.application_version. - Built via Cloud Build and mirrored.
image_source = "custom"withenable_image_mirroring = true, so the built image lands in the project's Artifact Registry rather than being pulled from GHCR at runtime. - No shell, no entrypoint wrapper — confirmed via
docker export. Unlike every other custom-build module in this catalogue,ghcr.io/twin/gatusis genuinely distroless: the final image contains nothing but the/gatusstatic binary,/config/config.yaml, and standardpasswd/group/hostsfiles — no shell, no busybox, no dynamic linker. ARUNstep against the final stage would fail outright, and there is no way (and no need) to graft a shell-based entrypoint. The base image's ownEXPOSE 8080andENTRYPOINT ["/gatus"]are left completely untouched; this Dockerfile only adds twoCOPYlayers. A tiny Alpine builder stage exists purely to create an empty/datadirectory thatCOPY --from=buildercan carry into the distroless final image (there is no shell in the final stage to runmkdiritself).
4. Configuration is entirely file-based — config.yaml, not environment variables
Unlike almost every other application module in this catalogue, Gatus has no
per-setting environment variable convention. Every monitored endpoint, alerting
integration, and storage setting lives in one YAML file —
modules/Gatus_Common/scripts/config.yaml — baked into the image at Cloud Build
time:
storage:
type: sqlite
path: /data/data.db
endpoints:
- name: example
url: "https://example.org"
interval: 5m
conditions:
- "[STATUS] == 200"
- "[RESPONSE_TIME] < 5000"
- No runtime config-reload API and no admin UI for editing checks. To add, remove, or change a monitored endpoint, edit this file and redeploy (which rebuilds the custom image via Cloud Build) — there is no way to do this through the running application.
environment_variables(forwarded from the platform variables) is for Gatus's own${VAR}-style substitutions referenced insideconfig.yaml(e.g. an alerting webhook token), not for per-setting overrides the way most other modules use it.
5. The SQLite history store — hardcoded WAL journal mode, a real persistence caveat
Gatus's optional history store (storage.type: sqlite) is confirmed (via a live
sqlite3 PRAGMA journal_mode; check against a running container) to hardcode WAL
journal mode — no config.yaml setting or SQLite connection-string parameter
(?_journal_mode=DELETE, tested and confirmed ineffective) disables it. SQLite's own
documentation states that WAL is not supported on network filesystems.
This has a direct consequence for persistence options:
- Default: ephemeral.
/datais a plain writable directory baked into the image with nothing mounted — history resets on every restart/redeploy. This is the module default on both platforms, deliberately, rather than risking silent corruption. - Cloud Run: the only optional persistence mechanism is NFS (
enable_nfs = true), which carries the WAL-on-network-filesystem risk described above. There is no block-PVC option on Cloud Run, so there is no fully safe way to persist Gatus history on Cloud Run. - GKE:
stateful_pvc_enabled = trueprovisions a real block device (not gcsfuse) — this is the one option in this catalogue verified safe for Gatus's WAL-mode SQLite file. Pair it withstateful_pvc_storage_class = "standard"(HDD) since Gatus's history store needs no SSD IOPS, and HDD avoids the tight regionalSSD_TOTAL_GBquota that the SSD-backed default class draws on.
6. Health probe behaviour
The default startup and liveness probes target /health — Gatus's built-in
health endpoint, which returns HTTP 200 as soon as the Fiber HTTP server binds its
port. Because Gatus has no database migrations or heavy initialisation, it becomes
healthy within seconds of boot.
For the Gatus-specific, user-facing configuration (variables by group, outputs, and how to explore each service from the Console and CLI), see the platform guides: Gatus_GKE and Gatus_CloudRun.