Skip to main content

Uptime Kuma on GKE Autopilot

Uptime Kuma on GKE Autopilot

Uptime Kuma is a self-hosted uptime monitoring tool for websites, APIs, TCP ports, DNS records, and more, with a clean dashboard, public status pages, and 90+ notification channels. This module deploys Uptime Kuma on GKE Autopilot on top of the App_GKE foundation, which provisions and manages the shared Google Cloud and Kubernetes infrastructure.

Uptime Kuma v1 is unusual among the applications in this repository: it stores all state in an embedded SQLite database under /app/data — there is no external database, no Redis cache, and no application secret to manage.

This guide focuses on the cloud services Uptime Kuma uses and how to explore and operate them from the Google Cloud Console and the command line. For the mechanics that are common to every GKE application — Workload Identity, ingress, autoscaling, CI/CD, Cloud Armor, IAP, Binary Authorization, VPC Service Controls, backups, and the deployment lifecycle — refer to the App_GKE foundation guide rather than repeating them here.


What Uptime Kuma costs on RAD, and how that compares​

Running Uptime Kuma on GKE Autopilot in your own Google Cloud project costs about US$53.72/month in Google Cloud charges (about US$126.72 if this isn't your only Autopilot cluster), on top of a one-off 75-credit RAD module fee (US$7.50) — higher than the Cloud Run module's fee because this variant runs no shared NFS volume on top of the GKE pod itself. GKE Autopilot suits Uptime Kuma that must run beside other Kubernetes workloads; for the lowest cost, see the Cloud Run guide instead. In a RAD-managed project the module fee drops to 67.5 credits (10% lower) — see Pause it for free below.

What you pay on RAD​

Own projectRAD-managed project
Module fee (one-off)75 credits67.5 credits (10% lower)
Build time~3-6 credits per build, either way~3-6 credits per build, either way
Google Cloud running costUS$53.72/month, billed by Google at list price~69 credits/day (about 2070/month, US$207 at the top-up price), metered at list price plus RAD's margin

10 credits cost US$1 on a one-off top-up, and less on a monthly plan.

Default running cost in your own project

Resource (module default)Per month
GKE Autopilot pod, 1x vCPU / 0.5 GiBUS$34.29
NFS/cache file server (small VM)US$13.43
Cloud NAT and networkingUS$5
Cloud Storage (add-ons, backups)US$1
TotalUS$53.72

The GKE cluster management fee is excluded from the total above because it is shared across every GKE app in the project — $0 if this is the only one, otherwise roughly $73/month split across however many you run.

How it compares​

  • Uptime Kuma has no official hosted cloud version — it is distributed only as self-hosted software, so there is no vendor SaaS plan to compare against.
  • A self-managed VPS comparison, sized to Uptime Kuma's 1 vCPU / 0.5 GiB default: a Hetzner CPX11 or DigitalOcean 1 vCPU/2GB Droplet runs about $6-12/month — plus your own time for backups and patching, and no Kubernetes control plane to run.
  • Most of this module's cost is the GKE Autopilot pod and its share of the cluster management fee; the Cloud Run variant runs the same always-on workload for less.

Pause it for free: delete a RAD-managed project, restore it when you need it​

This is the headline advantage of a RAD-managed project, and it costs nothing while paused. Deleting a RAD-managed project unlinks its billing first, then asks Google to delete the project outright — Google's own 30-day recoverable soft delete. Unlike deleting one module, this does not tear down Cloud SQL, any VM, or the compute resource one by one: the whole project simply stops, and nothing is charged while it waits, because billing is already unlinked.

Restoring, within 30 days and only by the project's owner, asks Google to undelete the project and reattaches its billing account, then asks you to run Update on each deployment to confirm everything came back. Because nothing was individually destroyed, that Update finds the same resources already there — it is a check, not a rebuild, and an Update never charges the module fee again. This costs only a handful of credits (under US$1) in total for a typical 2-3-deployment chain.

What this needs: you must own the project (not one RAD only manages billing for), you must restore it yourself within 30 days — after that Google deletes it for good — and restoring is admitted like creating a new project, so your purchased credit balance must still clear the tier's floor (100 credits for the sandbox tier most study/demo use fits). Google says most services are fully working again within 36 hours of a restore.

One real gap: nightly backups are written to a bucket inside the project, and that bucket has Cloud Storage's soft-delete explicitly turned off, so it is very likely gone as soon as you delete the project — even though the project itself is recoverable for 30 days. If you've customised Uptime Kuma and want to keep that work, copy a backup out (to Google Drive, or a bucket outside the project) before deleting. For a default install with nothing irreplaceable in it, this does not matter.

Pay only while you use it, the other way: delete and redeploy​

In your own project, or once 30 days have passed on a RAD-managed one, there is no free pause — deleting removes the resources for good, and bringing Uptime Kuma back means redeploying from scratch. That costs about 78-81 credits in your own project, or about 70.5-73.5 credits in a RAD-managed one.

Deleting only saves money once Uptime Kuma would otherwise sit unused long enough to clear that redeploy cost against its own running cost — about 4 days or more in your own project (about US$1.79 a day), or about 1 days or more in a RAD-managed one (69 credits a day).

Keep data first: nightly backups go to a bucket inside the deployment and are deleted with it, so copy the latest backup out before deleting if you want to keep it.

Lab sessions and Managed Environments​

Lab sessions, for training: a trainer runs a session for a class. Each participant gets the app in their own Google Cloud project for 15 minutes to 24 hours, within an allowance the trainer sets. Either the trainer funds every place, or each participant pays for their own. Everything is deleted when the session ends and unused credits go back to the trainer.

Managed Environments, for consultancies: a partner runs the app for a client from a ring-fenced wallet it funds, and settles with the client directly. If the wallet runs low, billing pauses and the data is kept, so nobody receives an unexpected charge. At the end the partner hands the project over and the deployments become the client's own.

Credits can be bought in more than 20 currencies, including XAF, XOF, NGN, GHS, KES and ZAR, by card, bank transfer or mobile money.

Sources (8 October 2026): Google Cloud Billing Catalog API list prices; radmodules.dev/pricing for RAD's own fees and daily-credit estimates; Google's project delete/restore documentation for the pause/restore claims.

1. Overview​

Uptime Kuma runs as a single Node.js web workload pulled directly from the official Docker Hub image. The deployment wires together a deliberately small set of Google Cloud services:

CapabilityGoogle Cloud serviceNotes
ComputeGKE AutopilotCustom-built louislam/uptime-kuma-based pods on port 3001, 1 vCPU / 512Mi by default
DatabaseNone (embedded SQLite)database_type = "NONE" — no Cloud SQL instance is provisioned
File persistenceCloud Filestore (NFS)The SQLite database and uploads persist under /app/data, shared across pods
Object storageCloud StorageNone provisioned by default — storage_buckets = []
SecretsSecret ManagerNone — Uptime Kuma has no application secret; admin credentials live in its own SQLite DB
IngressCloud Load BalancingExternal LoadBalancer with a reserved static IP; optional custom domain + managed certificate

Sensible defaults worth knowing up front:

  • No external database. database_type = "NONE" is fixed by UptimeKuma_Common; enable_cloudsql_volume = false and no db-init job runs. Uptime Kuma creates its SQLite schema on first boot.
  • NFS is mandatory for persistence. enable_nfs = true, mounted at /app/data (the container path is fixed — do not change it). Without the NFS volume, the SQLite database and all monitor history are ephemeral and lost on pod recreation. Alternatively, stateful_pvc_enabled = true (off by default) moves the same /app/data path onto a per-pod block PVC, the stronger backing for SQLite; the NFS mount is then dropped, because one path cannot have two volume mounts.
  • No Redis, no application secrets. UptimeKuma_Common outputs secret_ids = {}; there is nothing to inject from Secret Manager.
  • Custom build patches SQLite for NFS safety. container_image_source = "custom" builds a thin image FROM louislam/uptime-kuma:<application_version> (default tag 1, the v1 stable/SQLite line) via Cloud Build. Uptime Kuma unconditionally sets PRAGMA journal_mode = WAL on every boot (hardcoded in server/database.js, not configurable via env var); WAL relies on shared-memory byte-range locking between the DB file and its -wal sidecar, which the NFS-backed /app/data volume does not reliably provide and has produced observed SQLITE_CORRUPT errors. The build patches that PRAGMA to DELETE mode, which only needs standard whole-file locking that NFS handles correctly. The built image is then mirrored into Artifact Registry by default (enable_image_mirroring = true) to avoid Docker Hub rate limits.
  • container_port = 3001 — Uptime Kuma's native port.
  • Single replica by default and required. min_instance_count = 1, max_instance_count = 1. SQLite is a single-writer database; do not scale beyond 1 replica sharing the same NFS-mounted database file.
  • tenant_id gets a -gke suffix when the variant calls UptimeKuma_Common, so a CloudRun and GKE variant on the same tenant_id do not collide on Common-owned naming.
  • First-run setup is entirely in-app. There is no default admin account — Uptime Kuma prompts you to create one on first access.

2. Google Cloud Services & How to Explore Them​

All commands assume you have run gcloud container clusters get-credentials <cluster> --region <region> --project <project> and that PROJECT, REGION, and NAMESPACE are set. The namespace and other identifiers are reported in the deployment Outputs.

A. GKE Autopilot — the Uptime Kuma workload​

Uptime Kuma pods are scheduled on Autopilot, which bills for the CPU/memory the pods actually request. The workload deploys as a Deployment (workload_type defaults to Deployment; a StatefulSet also works with the NFS volume if selected).

  • Console: Kubernetes Engine → Workloads → select the Uptime Kuma workload for pods, revisions, and events. Kubernetes Engine → Services & Ingress shows the external IP.
  • CLI:
    kubectl get pods,svc -n "$NAMESPACE"
    kubectl logs -n "$NAMESPACE" deploy/<service-name> --tail=100
    kubectl describe pod -n "$NAMESPACE" -l app=<service-name>

See App_GKE for how Autopilot, scaling, and the workload type (Deployment vs StatefulSet) are managed.

B. Cloud Filestore (NFS) — the only persistence layer​

Because Uptime Kuma has no external database, all durable state — monitors, check history, notification configuration, status pages, and the admin account — lives in a single SQLite file on the NFS volume mounted at /app/data. This makes the NFS mount the single most important resource to protect for this module: losing it loses everything.

  • Console: Filestore → Instances.
  • CLI:
    gcloud filestore instances list --project "$PROJECT"
    kubectl get pvc -n "$NAMESPACE"
    kubectl exec -n "$NAMESPACE" deploy/<service-name> -- ls -la /app/data

See App_GKE for NFS provisioning, discovery, and the shared vs. inline NFS VM model.

C. Cloud Storage​

No GCS bucket is provisioned for Uptime Kuma by default (storage_buckets = [] in UptimeKuma_Common); all persistence is on NFS. Set create_cloud_storage/storage_buckets explicitly if you need a bucket for exported backups or automation.

  • Console: Cloud Storage → Buckets.
  • CLI:
    gcloud storage buckets list --project "$PROJECT" --filter="name~uptimekuma"

D. Secret Manager​

Uptime Kuma requires no application secrets — secret_ids = {}. The database password output surfaced by the Foundation is unused (there is no Cloud SQL instance). Only Foundation-level secrets you explicitly add via secret_environment_variables will appear here.

  • Console: Security → Secret Manager.
  • CLI:
    gcloud secrets list --project "$PROJECT" --filter="name~uptimekuma"

E. Networking & ingress​

By default the workload is exposed through an external Cloud Load Balancing IP (service_type = LoadBalancer, reserve_static_ip = true so the address survives redeploys). A custom domain with a Google-managed certificate can be enabled via enable_custom_domain/application_domains.

  • Console: Network services → Load balancing; VPC network → IP addresses.
  • CLI:
    kubectl get svc,ingress -n "$NAMESPACE"
    gcloud compute addresses list --project "$PROJECT"

See App_GKE for custom domains, Cloud CDN, and static IP details. Also confirm the GKE egress path allows the pod to reach whatever external endpoints you configure Uptime Kuma to monitor.

F. Cloud Logging & Monitoring​

Pod stdout/stderr flow to Cloud Logging. Optional Cloud Monitoring uptime checks and alert policies are available (uptime_check_config.enabled = false by default) — note this is a Google Cloud uptime check on the Uptime Kuma service itself, separate from the monitors you configure inside Uptime Kuma.

  • Console: Logging → Logs Explorer; Monitoring → Dashboards / Alerting.
  • CLI:
    gcloud logging read 'resource.type="k8s_container" AND resource.labels.namespace_name="'"$NAMESPACE"'"' \
    --project "$PROJECT" --limit 50

3. Uptime Kuma Application Behaviour​

  • No initialization job. initialization_jobs is empty by default — Uptime Kuma creates its SQLite schema itself on first boot against the empty /app/data volume. User-supplied jobs are still honoured if provided.
  • First-run setup is manual and in-app. On first access to the service URL, Uptime Kuma serves its setup wizard to create the initial admin account — there are no default or auto-generated credentials to retrieve from Secret Manager.
  • Health path. Both the default startup and liveness probes are HTTP GET /api/entry-page on port 3001 — / is always a 302, which the Gateway's health check treats as unhealthy (startup: 30 s initial delay, 10 s period, failure threshold 30; liveness: 30 s initial delay, 30 s period, failure threshold 3). The optional Cloud Monitoring uptime check also targets GET /.
  • Single-writer SQLite over NFS. Running more than one replica against the same /app/data SQLite file risks database-lock contention or corruption; keep min_instance_count = max_instance_count = 1 unless the NFS server's file-locking behaviour under concurrent SQLite writers has been separately verified.
  • Inspect the running config and data volume:
    kubectl exec -n "$NAMESPACE" deploy/<service-name> -- env | grep -i uptime
    kubectl exec -n "$NAMESPACE" deploy/<service-name> -- ls -la /app/data

4. Configuration Variables​

Variables are grouped exactly as they appear on the deployment platform. Only settings specific to or notable for Uptime Kuma are listed; every other input is inherited from App_GKE with its standard behaviour and defaults.

Group 2 — Application & Database Identity​

VariableDefaultDescription
application_nameuptimekumaBase name for resources. Do not change after first deploy.
application_version1louislam/uptime-kuma image tag; "1" is the v1 stable line (embedded SQLite).

Group 3 — Runtime & Scaling​

VariableDefaultDescription
container_image_sourcecustomBuilds a thin custom image via Cloud Build that patches SQLite's hardcoded journal_mode from WAL to DELETE for NFS safety (see Overview). Keep custom.
container_port3001Uptime Kuma's native port.
enable_cloudsql_volumefalseUnused — Uptime Kuma has no external database.
min_instance_count / max_instance_count1 / 1Keep both at 1 — single SQLite writer.
container_resources{ cpu_limit="1000m", memory_limit="512Mi" }Per-pod CPU/memory limits.

Group 6 — GKE Cluster​

VariableDefaultDescription
service_typeLoadBalancerExternal IP for the Uptime Kuma dashboard.
workload_typenull → DeploymentDeployment; StatefulSet also works with the NFS volume if explicitly selected.
session_affinity(Foundation default)No app-specific override; Uptime Kuma has no per-session server state beyond the SQLite DB.

Group 10 — Observability & Health​

VariableDefaultDescription
startup_probe_config{ enabled=true, path="/api/entry-page" } (HTTP, port 3001)Startup probe.
health_check_config{ enabled=true, path="/api/entry-page" } (HTTP, port 3001)Liveness probe. Must return a literal 200 — it is mirrored into the Gateway health check.
uptime_check_config{ enabled=false, path="/" }Cloud Monitoring uptime check on the service itself (not an Uptime Kuma monitor).

Group 13 — NFS​

VariableDefaultDescription
enable_nfstrueRequired. The sole persistence mechanism for the embedded SQLite database.
nfs_mount_path/app/dataFixed by the app's storage layout — do not change.

Group 16 — Database​

VariableDefaultDescription
database_type"NONE"Fixed by UptimeKuma_Common. No Cloud SQL instance is provisioned.

All other inputs follow standard App_GKE behaviour.


5. Outputs​

These values are returned on a successful deployment and are the quickest way to locate and explore the running resources.

OutputDescription
service_nameKubernetes Service name.
namespaceNamespace the workload runs in.
service_cluster_ipIn-cluster ClusterIP.
stage_service_cluster_ipsMap of ClusterIPs for stage-specific services.
service_external_ipExternal LoadBalancer IP (when a static IP is reserved).
service_urlURL to reach Uptime Kuma.
database_instance_name / database_name / database_user / database_password_secret / database_host / database_portPresent for output parity with other modules; not meaningful for Uptime Kuma — no Cloud SQL instance is provisioned (database_type = "NONE").
storage_bucketsCreated Cloud Storage buckets (empty by default).
network_name / network_exists / regionsVPC network, presence, available regions.
container_image / container_registryDeployed image and Artifact Registry repo.
monitoring_enabled / monitoring_notification_channelsMonitoring status and channels.
initialization_jobs / db_import_jobCreated init job names (empty by default) and optional import job.
deployment_id / tenant_id / resource_prefixNaming identifiers.
project_id / project_numberProject identifiers.
cicd_enabled / cicd_configurationCI/CD status and details (repo, trigger, registry).
github_repository_url / github_repository_owner / github_repository_nameCI/CD GitHub details.
artifact_registry_repository / cloudbuild_trigger_name / cloudbuild_trigger_idRegistry and build trigger.
kubernetes_readyWhether the cluster/workload is ready.
vpc_sc_enabled / vpc_sc_perimeter_name / vpc_sc_dry_run_modeVPC-SC status.
audit_logging_enabled / artifact_registry_cmek_enabledAudit logging and CMEK status.

6. Configuration Pitfalls & Sensible Defaults​

Risk: Critical (data loss / outage / security) — High (service degraded) — Medium (cost or partial degradation) — Low (minor).

Inherited plan-time validation. This module passes its configuration through the App_GKE foundation engine, which validates values and combinations at plan time — a StatefulSet forced alongside a stateless setting, IAP with no authorized identities, quota_memory_* given as bare integers, an out-of-range container_port/ backup_retention_days. Invalid configuration fails the plan with a clear, named error before any resource is created, so most mistakes below are caught up front rather than at apply or runtime.

SettingSensible valueRiskConsequence if wrong
enable_nfstrueCriticalDisabling it removes the only persistence layer — the embedded SQLite database (all monitors, history, and the admin account) is ephemeral and lost on every pod recreation.
nfs_mount_path/app/dataCriticalChanging it points Uptime Kuma's own hard-coded data path away from the persisted volume; the app writes SQLite to a path that is not actually the mounted NFS share.
max_instance_count1HighSQLite is single-writer; running >1 replica against the same NFS-mounted database file risks lock contention or corruption.
database_type"NONE"LowUptime Kuma ignores this — it never connects to Cloud SQL — but changing it will still provision an unused, billed Cloud SQL instance via the Foundation.
container_port3001HighUptime Kuma listens on 3001; pointing the Service/probes at any other port makes the workload unreachable and probes fail.
quota_memory_requests / _limitsbinary units (4Gi, 8192Mi)CriticalBare integers are treated as bytes and block all pod scheduling in the namespace.
reserve_static_iptrueMediumWithout it, the external IP can change across redeploys, breaking DNS, bookmarks, and any external status-page embed.
First-run admin setupComplete immediately after deployMediumThe setup wizard is reachable by anyone who finds the URL before an admin account is created — do not leave a freshly deployed instance with a public IP unconfigured for long.
backup_retention_days7 (raise for prod)MediumApplies to Foundation-managed backups; since Uptime Kuma's real state is the NFS-hosted SQLite file, verify NFS/Filestore backup coverage separately rather than relying solely on this setting.
container_image_sourcecustom (default)CriticalSetting "prebuilt" skips the Cloud Build step and deploys the unpatched upstream image — Uptime Kuma then writes SQLite in WAL mode over NFS, which has produced observed SQLITE_CORRUPT database corruption.

For the foundation behaviour referenced throughout — IAM and Workload Identity, autoscaling, ingress and certificates, CI/CD, Cloud Armor, IAP, Binary Authorization, VPC-SC, backups, and image mirroring — see App_GKE. Uptime Kuma-specific application configuration shared with the Cloud Run variant is described in UptimeKuma_Common.

Need RAD to do something it does not do yet? Request it on the roadmap, or vote on what is already there.