Skip to main content

Chibisafe on GKE Autopilot

Chibisafe on GKE Autopilot

Chibisafe is a self-hosted file and image uploader with a modern dashboard, drag-and-drop uploads, albums, and a public API. This module deploys the complete Chibisafe stack — the web UI at /, the REST API under /api, the OpenAPI reference at /docs, and uploaded files served by name — as one workload on GKE Autopilot, on top of the App_GKE foundation, which provisions and manages the shared Google Cloud and Kubernetes infrastructure. Upstream ships Chibisafe as three containers (the chibisafe-server backend, a Next.js front-end and a Caddy reverse proxy); this module combines them into one custom-built image.

Status: the full-stack image has not yet been built or deployed, so the behaviour below is described from the module source and upstream's v6.5.5 release, not verified live.

This guide focuses on the cloud services Chibisafe 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 Chibisafe costs on RAD, and how that compares​

Chibisafe on RAD's GKE Autopilot module costs about US$42 a month in your own Google Cloud project, with no extra licence fee — Chibisafe is open source. In a project RAD manages for you, the same deployment is metered at 67 credits a day (about 2,010 a month, about US$201 at the top-up price). Or see the Cloud Run guide for the lower-cost option. If you only need Chibisafe occasionally — studying, a demo, a short-lived project — a RAD-managed project can be deleted and restored within 30 days for a few credits, so that monthly figure becomes a few dollars instead. See Pause it for free, below.

What you pay on RAD​

Chibisafe is open source, so there is no licence fee. You pay for three things:

In a Google Cloud project you ownIn a project RAD manages for you
Module fee, once per deployment75 credits (US$7.50 at the top-up price)67.5 credits (10% lower)
Build timeA few credits per build (roughly 3–6 credits)The same
Google Cloud running costBilled by Google to your own billing account, about US$42 a month for the default configuration (table below)Metered hourly in credits; RAD publishes 67 credits a day, about 2,010 a month (about US$201 at the top-up price)
Who owns whatYou own the project and its billing; RAD deploys and updates itRAD owns the project, with guardrails, quotas and budget alerts; you get console access, and a minimum purchased balance is held in reserve

10 credits cost US$1 on a one-off top-up, and less on a monthly plan. In a project RAD manages, the database, file server and network are shared by every application in the project, so a second application does not add a second database.

Default running cost in your own project (us-central1, Google list prices):

Resource (module default)Per month
GKE Autopilot pod, 1x vCPU / 1 GiBUS$36.08
Cloud NAT and networkingUS$5
Cloud Storage (add-ons, backups)US$1
GKE cluster management feeshared across every GKE app in the project; $0 if this is your only cluster, else ~73
Total (excluding the shared GKE cluster fee)about US$42

These prices are the same in africa-south1 (Johannesburg).

  • GKE Autopilot does not scale to zero. At least one pod always runs, so the cost above applies whether or not anyone is using the app; extra pods are added only under load.

How it compares, for a personal or small-team file host​

Chibisafe has no official hosted offering — it ships as a self-hosted stack, so the realistic comparison is a bare server:

  • A Hetzner CPX22 or DigitalOcean droplet (2 vCPU/4 GB, about US$24/month) or a GCP e2-standard-2 (2 vCPU/8 GB, about US$49/month) would run it comfortably — oversized for Chibisafe's own 1 vCPU/1 GiB footprint here, so a smaller, cheaper instance class would do just as well.
  • On a bare VPS you own the operating system, security patches and your own backup discipline. RAD's module gives you the compute, Secret Manager and Cloud Monitoring already wired up, for the module fee plus the Google Cloud usage above.

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

If Chibisafe runs in a project RAD manages for you, deleting the whole project — rather than deleting just this module — unlinks its billing first, then asks Google to delete the project outright. Google keeps it, recoverable, for 30 days, and because billing is already unlinked, nothing is charged while it waits. 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.

  • Restoring is a check, not a rebuild. Within 30 days, the project's owner can ask Google to undelete the project and reattach its billing account, then run Update on each deployment to confirm everything came back. Because nothing was individually destroyed, that Update finds the same resources already there, and an Update never charges the module fee again. For a typical 2–3-deployment chain this costs only a handful of credits in total (roughly 5–10 credits, under US$1).
  • What this needs. You must own the project (not one RAD only manages billing for), restore it yourself within 30 days — after that Google deletes it for good — and clear the tier's admission floor again (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 do not survive. Backups are written to a bucket inside the project, and that bucket has Cloud Storage's soft-delete turned off, so it is very likely gone as soon as the project is deleted — even though the project itself is recoverable for 30 days. Copy a backup out (to Google Drive, or a bucket outside the project) before deleting if there is anything in it worth keeping; for a default install with nothing irreplaceable, this does not matter.

Source: Delete and restore projects.

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

In your own project, or once the 30-day restore window above has passed, the way to stop paying is to delete the deployment and deploy it again when you need it.

  • What a redeploy costs. The module fee again, plus the builds: about 79 credits (about US$7.90) at the top-up price, and roughly 15–20 minutes of build time (RAD's own platform average). Deleting saves money only once Chibisafe would otherwise sit unused for about 3 days or more — in your own project that is about US$1.40 a day, and in a RAD-managed one it is 67 credits a day.
  • Most of the running cost here is usually the database and/or the shared file/cache VM or cluster. They stop only when nothing else in the project uses them, so deleting Chibisafe while another application shares the project saves only Chibisafe's own compute part.
  • 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 list prices from the Cloud Billing Catalog API; RAD fees and the daily-credit estimate from radmodules.dev/pricing; Delete and restore projects for the pause/restore window and backup-bucket caveat; prices change, check each source before relying on a figure.

1. Overview​

Chibisafe runs as a single workload — one container with Caddy in front of two Node.js processes (backend and front-end) — with no external database. The deployment wires together a focused set of Google Cloud services:

CapabilityGoogle Cloud serviceNotes
ComputeGKE AutopilotFull-stack pod (Caddy on port 8000 → backend + Next.js front-end on loopback), StatefulSet by default, 1 vCPU / 1 GiB by default
DatabaseNoneChibisafe keeps its SQLite database, uploads, and logs on the persistent volume — no Cloud SQL instance is created
Block storageGKE StatefulSet PVCDefault 20Gi standard-rwo PVC mounted at /data, holding the SQLite DB, uploads, and logs
Object storageCloud StorageA storage bucket is always provisioned; only mounted as a GCS FUSE volume when the StatefulSet PVC is disabled
SecretsSecret ManagerOptional ADMIN_PASSWORD (gated by enable_api_key, off by default)
IngressKubernetes Gateway / Cloud Load BalancingCustom domain + managed certificate enabled by default (enable_custom_domain = true)

Sensible defaults worth knowing up front:

  • SQLite is the only "database." database_type is fixed to NONE by Chibisafe_Common; the many database_*/db_* variables mirrored in variables.tf exist purely for Foundation-convention parity and have no effect.
  • StatefulSet + block PVC is the default. SQLite does not tolerate GCS FUSE's POSIX file-locking semantics, so stateful_pvc_enabled = true by default, which auto-resolves workload_type to StatefulSet with a 20Gi standard-rwo PVC at /data.
  • Single-writer, single replica. min_instance_count = 1, max_instance_count = 1 — Chibisafe is a single-writer SQLite app; do not scale beyond 1 without redesigning storage.
  • Custom-build image with an app-specific version pin. image_source = "custom" builds a Dockerfile based on chibisafe/chibisafe-server (backend at /app) that copies in the chibisafe/chibisafe Next.js front-end (/opt/chibisafe-web) and a static Caddy 2.11.4 binary. The build reads its own CHIBISAFE_VERSION build arg (not the generic APP_VERSION the Foundation injects; one tag pins backend and front-end); application_version = "latest" is pinned to v6.5.5 at build time.
  • No Redis, ever. The variant mirrors an enable_redis variable for Foundation convention parity, but main.tf always forwards enable_redis = false to App_GKE regardless of its value — Chibisafe has no Redis dependency.
  • Custom domain is on by default. Unlike most modules, enable_custom_domain = true out of the box; set application_domains for the managed certificate to actually attach to a hostname.
  • No mandatory secrets. enable_api_key = false by default — the backend creates the first-run owner account admin with the well-known upstream password admin; change it immediately after first login in the web UI. Flip enable_api_key to true to pre-seed a random ADMIN_PASSWORD from Secret Manager instead.
  • All state lives under one mount. The entrypoint symlinks the image's /app/database, /app/uploads, and /app/logs directories into subdirectories of the single persistent volume (/data), migrating any image-seeded contents on first boot.

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 Chibisafe workload​

Chibisafe pods are scheduled on Autopilot, which bills for the CPU/memory the pods actually request. With the default stateful_pvc_enabled = true, the workload is a StatefulSet with OrderedReady pod management and a stable per-pod PVC — a better fit than a Deployment for a single-writer SQLite app.

  • Console: Kubernetes Engine → Workloads → select the Chibisafe workload for pods, revisions, and events. Kubernetes Engine → Services & Ingress shows the external IP (if any).
  • CLI:
    kubectl get pods,svc -n "$NAMESPACE" --selector=app~chibisafe
    kubectl logs -n "$NAMESPACE" statefulset/<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. Persistent storage — block PVC and Cloud Storage​

Chibisafe has no database service to inspect — its state (SQLite database, uploaded files, and logs) lives entirely on the persistent volume mounted at /data. By default that volume is a per-pod block PersistentVolumeClaim (stateful_pvc_enabled = true, 20Gi standard-rwo), which gives the SQLite files the low-latency, POSIX-correct I/O they need. A Cloud Storage storage bucket is always provisioned by Chibisafe_Common, but it is only mounted as a GCS FUSE volume when the StatefulSet PVC is disabled (enable_gcs_storage_volume is computed as !stateful_pvc_enabled in main.tf) — avoiding a double-mount at the same path.

  • Console: Kubernetes Engine → Storage → PersistentVolumeClaims for the PVC; Cloud Storage → Buckets for the always-created storage bucket.
  • CLI:
    kubectl get pvc -n "$NAMESPACE"
    kubectl exec -n "$NAMESPACE" <pod-name> -- df -h /data
    gcloud storage buckets list --project "$PROJECT" --filter="name~chibisafe"

See App_GKE for StatefulSet PVC lifecycle, StorageClass options, and GCS FUSE mount details.

C. Secret Manager​

Chibisafe generates no secrets by default. The only optional secret is a random admin password, gated by enable_api_key (default false): when enabled, a 24-character random value is stored in Secret Manager (name suffix api-key) and delivered to the pod as a native Kubernetes Secret (via explicit_secret_values, not the usual Secret Manager → SecretSync path) injected as the ADMIN_PASSWORD environment variable — Chibisafe's backend seeds its first-run admin account from this value instead of the well-known upstream default.

  • Console: Security → Secret Manager.
  • CLI:
    gcloud secrets list --project "$PROJECT" --filter="name~chibisafe"
    gcloud secrets versions access latest --secret=<api-key-secret-name> --project "$PROJECT"

See App_GKE for the Secret Store CSI / native-Secret injection model and rotation.

D. Networking & ingress​

enable_custom_domain = true by default, exposing Chibisafe through a Kubernetes Gateway with a Google-managed certificate once application_domains is populated. The internal Service defaults to ClusterIP; switch service_type to LoadBalancer for a direct external IP instead of (or alongside) the Gateway path.

  • Console: Network services → Gateways, or Load balancing (if service_type = LoadBalancer); VPC network → IP addresses for the reserved static IP.
  • CLI:
    kubectl get svc,gateway,httproute -n "$NAMESPACE"
    gcloud compute addresses list --project "$PROJECT"

See App_GKE for custom domains, Cloud CDN, and static IP details.

E. Cloud Logging & Monitoring​

Pod stdout/stderr flow to Cloud Logging; GKE metrics flow to Cloud Monitoring. Optional uptime checks and alert policies are available but disabled by default (uptime_check_config.enabled = false).

  • 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

See App_GKE for uptime-check reachability requirements and alert wiring.


3. Chibisafe Application Behaviour​

  • No init or migration job. Chibisafe manages its own SQLite storage; Chibisafe_Common injects no db-init/migration job by default. The initialization_jobs variable is available for custom data-loading tasks only.

  • First-boot state relocation. The image keeps mutable state under three sibling directories in its WORKDIR — /app/database (SQLite), /app/uploads (files/thumbnails), and /app/logs. The entrypoint (entrypoint.sh) symlinks each of these into a subdirectory of the single persistent mount (/data by default), migrating any image-seeded contents into the empty volume on first boot. This is idempotent across restarts — already-symlinked directories are left alone.

  • Admin account. On first boot the backend creates the owner account admin. If enable_api_key = true, a random value is generated and injected as ADMIN_PASSWORD, which the backend uses as that account's password instead of the well-known upstream default (admin); otherwise log in with admin/admin and change it immediately. ADMIN_PASSWORD is passed only to the backend process — the entrypoint strips it from the front-end's and Caddy's environment.

  • No DB env-var aliasing. database_type = NONE — there is no DB_HOST/ DB_USER injection or aliasing to worry about; SQLite lives entirely on the /data volume.

  • Processes and ports. tini is PID 1; the entrypoint (after the state relocation above) starts three processes:

    ProcessListens onServes
    Caddy0.0.0.0:8000 (container_port)The only listener the Service routes to
    chibisafe-server backend127.0.0.1:18000 (loopback only)/api/*, /docs*
    Next.js front-end127.0.0.1:18001 (loopback only)The web UI

    They are supervised fail-fast: if any one exits, the others are stopped and the container exits with status 1, so Kubernetes restarts it (chosen over supervisord, which would keep a container looking healthy with a dead front-end).

  • Routing (upstream's v6.5.5 Caddyfile, same order): any path naming a file under /data/uploads is served directly by Caddy (the backend does not serve uploads in production); /api/* → backend (the REST API — see the api_url output); /docs* → backend (the Scalar OpenAPI reference); everything else → front-end (the web UI at /, e.g. /dashboard, /login). Two deviations from upstream: the Host header is preserved, so the file links the backend builds are correct without setting "Serve uploads from"; and X-Forwarded-For/ X-Real-IP are set to the client IP Caddy resolves itself (Google load-balancer ranges trusted, strict rightmost selection), so a client cannot spoof them.

  • Front-end → backend. The front-end's server-side rendering calls the backend directly at BASE_API_URL=http://127.0.0.1:18000, set by the entrypoint; the browser calls the same-origin /api.

  • Container environment. NODE_ENV=production is the only container-wide default; HOST/HOSTNAME/PORT for the two Node processes are set per process by the entrypoint (HOSTNAME must be overridden because Kubernetes sets it to the pod name). PORT is deliberately left unset by Chibisafe_Common; Caddy falls back to 8000, matching container_port.

  • Uploads. A LoadBalancer Service imposes no request-body cap, so Chibisafe's default upload chunk size (about 81 MB) works as is — unlike Chibisafe_CloudRun, where Cloud Run's 32 MiB limit requires lowering it.

  • Memory. The default 1Gi now holds two Node processes plus Caddy; this has not been measured live yet — raise memory_limit if the pod is OOM-killed.

  • Updating an existing deployment. An UPDATE of a deployment made with the earlier backend-only version rebuilds the image automatically (the scripts directory's content hash changes), keeps port 8000, removes the container-wide HOST=0.0.0.0 env var (now set per process) and leaves the data on the /data PVC untouched. / changes from a 404 JSON response to the web UI.

  • Health path. Both the startup and liveness probes are HTTP GET /api/health (startup_probe/liveness_probe default path = "/api/health", matching Chibisafe_CloudRun), sent through Caddy to the backend, which returns a literal 200 {"status":"yes"} once serving, no authentication required — also what the Gateway health check (mirroring the liveness probe) needs: exactly 200. / is the web UI, whose status code is the front-end's choice rather than a health signal. The alternate health_check_config/startup_probe_config variables now also default path = "/api/health" but are superseded — the foundation takes the probes from startup_probe/liveness_probe.

  • Single-writer scaling constraint. min_instance_count = max_instance_count = 1 by default; each StatefulSet pod owns its own PVC, so scaling beyond 1 without redesigning storage risks split SQLite writers.

  • Inspect the running config:

    kubectl get pods,pvc -n "$NAMESPACE"
    kubectl exec -n "$NAMESPACE" <pod-name> -- ls -la /app/database /app/uploads /app/logs
    kubectl exec -n "$NAMESPACE" <pod-name> -- env | grep -E 'HOST|NODE_ENV|PORT'

4. Configuration Variables​

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

Group 3 — Application Identity​

VariableDefaultDescription
application_namechibisafeBase name for resources. Do not change after first deploy.
application_versionlatestchibisafe/chibisafe-server image tag; latest is pinned to v6.5.5 at build time via the app-specific CHIBISAFE_VERSION build arg.
enable_api_keyfalseGenerates a random value in Secret Manager, injected as ADMIN_PASSWORD via a native Kubernetes Secret, seeding the first-run admin credential instead of the upstream default.

Group 4 — Runtime & Scaling​

VariableDefaultDescription
cpu_limit1000m1 vCPU default.
memory_limit1Gi1 GiB default, shared by two Node processes and Caddy; not yet measured live.
min_instance_count / max_instance_count1 / 1Keep at 1 — Chibisafe is a single-writer SQLite app.
container_port8000The Caddy proxy's port. Fixed by Chibisafe_Common; this variable is not forwarded to App_GKE and changing it has no effect.
enable_cloudsql_volumefalseChibisafe has no Cloud SQL database — leave false.
enable_image_mirroringtrueMirrors the built image into Artifact Registry.

Group 6 — GKE Backend & Cluster​

VariableDefaultDescription
service_typeLoadBalancerInternal by default; the Gateway path (Group 19) is the default route to external traffic.
workload_typenull → StatefulSetAuto-resolves because stateful_pvc_enabled = true by default.
session_affinityNoneNo client stickiness configured by default.

Group 7 — StatefulSet / PVC​

VariableDefaultDescription
stateful_pvc_enabledtrueRequired — SQLite does not tolerate GCS FUSE's POSIX file locking. Auto-resolves workload_type to StatefulSet.
stateful_pvc_size20GiSize the PVC to hold the SQLite DB plus all uploaded files.
stateful_pvc_mount_path/dataThe entrypoint symlinks /app/database, /app/uploads, and /app/logs into this mount.
stateful_pvc_storage_classstandard-rwoSSD-backed Balanced PD; draws the SSD_TOTAL_GB quota — override to standard (HDD) on quota-constrained projects.
stateful_fs_group3000Matches the Chibisafe Helm chart's UID 1000 / GID 2000 convention so the PVC is group-writable.

Group 10 — Observability​

VariableDefaultDescription
startup_probe / liveness_probepath = "/api/health"The live, effective probes (forwarded to App_GKE in main.tf). Sent through the Caddy proxy to the backend — a literal 200 {"status":"yes"}, no auth required.
health_check_config / startup_probe_configpath = "/api/health"Inert — declared for foundation-variable mirroring only, never forwarded to App_GKE. Do not rely on these to change the deployed probe.
uptime_check_configenabled = false, path = "/api/health"Enable to add a public uptime check and alert once the endpoint is publicly reachable.

Group 14 — Cloud Storage​

VariableDefaultDescription
create_cloud_storagetrueProvisions the always-present storage bucket (suffix storage).
gcs_volumes[]Additional GCS FUSE mounts. The Chibisafe storage bucket is auto-mounted at /data only when stateful_pvc_enabled = false; with the StatefulSet default it is created but left unmounted to avoid a double-mount at /data.

Group 15 — Redis Cache​

VariableDefaultDescription
enable_redistrue (mirrored, inert)Declared only for Foundation-convention parity — Chibisafe_GKE/main.tf always forwards enable_redis = false to App_GKE regardless of this value. Chibisafe has no Redis dependency.

Group 19 — Custom Domain, Static IP & Networking​

VariableDefaultDescription
enable_custom_domaintrueOn by default (unusual among modules) — Kubernetes Gateway + managed certificate.
application_domains[]Must be populated for the managed certificate to attach to a real hostname.
reserve_static_iptrueStable external IP across redeploys.

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 service_type = LoadBalancer and a static IP is reserved).
service_urlURL of the Chibisafe web UI (served at /). The same address serves the REST API under /api, the OpenAPI reference at /docs and uploaded files by name. External with a reserved LoadBalancer IP, otherwise the in-cluster URL.
api_urlBase URL of the REST API (<service_url>/api), for upload clients and scripts; GET <api_url>/health returns 200 {"status":"yes"}.
chibisafe_api_key_secret_idSecret Manager secret ID for the optional admin-password secret. Empty when enable_api_key = false.
storage_bucketsCreated Cloud Storage buckets.
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.
deployment_id / tenant_id / resource_prefixNaming identifiers.
project_id / project_numberProject identifiers.
initialization_jobsNames of any custom initialization jobs.
statefulset_nameName of the StatefulSet.
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 — pairing workload_type = "Deployment" with stateful_pvc_enabled = true, 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
stateful_pvc_enabledtrueCriticalDisabling it falls back to a GCS FUSE mount at /data, whose POSIX file-locking behaviour is unsafe for SQLite and risks database corruption.
stateful_pvc_mount_path/dataCriticalThe entrypoint's relocation symlinks (/app/database, /app/uploads, /app/logs) are hard-coded to this mount; changing it without also updating the image breaks state persistence.
workload_typenull (→ StatefulSet)CriticalForcing Deployment alongside stateful_pvc_enabled = true fails at plan time; forcing it via stateful_pvc_enabled = false instead trades SQLite integrity for GCS FUSE risk (see above).
max_instance_count1HighChibisafe is a single-writer SQLite app; scaling beyond 1 pod risks split writers and corrupted state even though each StatefulSet replica gets its own PVC.
stateful_fs_group3000HighA mismatched or unset fsGroup leaves the PVC mount without group-write access for the container's UID, causing write failures for the SQLite DB and uploads.
stateful_pvc_storage_classstandard-rwo (override to standard if constrained)MediumSSD-backed standard-rwo draws the tight SSD_TOTAL_GB quota; a campaign of stateful apps can exhaust it. Scale-to-zero does not release the PVC — only deletion does.
quota_memory_requests / _limitsbinary units (4Gi, 8192Mi)CriticalBare integers are treated as bytes and block all pod scheduling in the namespace (only relevant if enable_resource_quota = true).
enable_custom_domaintrue with application_domains setMediumLeft on with an empty application_domains, the Gateway/managed-certificate path has no hostname to attach to.
enable_redisany value (inert)Lowmain.tf always forwards enable_redis = false — changing this variable has no effect; do not rely on it to add Redis connectivity.
container_port8000 (fixed)LowThe variable is declared for convention parity but not forwarded to App_GKE; changing it does not change the Caddy proxy's actual listening port.
database_type / db_* variablesNONE / inertLowChibisafe has no SQL database; these exist only for Foundation-variable mirroring and are silently ignored.
enable_api_keytrue if the service is externally reachable; otherwise change the default password at first loginMediumWith it off, the admin account starts with the well-known upstream password admin — change it at first login, especially if the service is externally reachable. Per-request API keys are minted inside the app.

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. Chibisafe-specific application configuration shared with the Cloud Run variant is described in the Chibisafe_Common module (modules/Chibisafe_Common/README.md).

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