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.5release, 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 own | In a project RAD manages for you | |
|---|---|---|
| Module fee, once per deployment | 75 credits (US$7.50 at the top-up price) | 67.5 credits (10% lower) |
| Build time | A few credits per build (roughly 3–6 credits) | The same |
| Google Cloud running cost | Billed 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 what | You own the project and its billing; RAD deploys and updates it | RAD 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 GiB | US$36.08 |
| Cloud NAT and networking | US$5 |
| Cloud Storage (add-ons, backups) | US$1 |
| GKE cluster management fee | shared 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:
| Capability | Google Cloud service | Notes |
|---|---|---|
| Compute | GKE Autopilot | Full-stack pod (Caddy on port 8000 → backend + Next.js front-end on loopback), StatefulSet by default, 1 vCPU / 1 GiB by default |
| Database | None | Chibisafe keeps its SQLite database, uploads, and logs on the persistent volume — no Cloud SQL instance is created |
| Block storage | GKE StatefulSet PVC | Default 20Gi standard-rwo PVC mounted at /data, holding the SQLite DB, uploads, and logs |
| Object storage | Cloud Storage | A storage bucket is always provisioned; only mounted as a GCS FUSE volume when the StatefulSet PVC is disabled |
| Secrets | Secret Manager | Optional ADMIN_PASSWORD (gated by enable_api_key, off by default) |
| Ingress | Kubernetes Gateway / Cloud Load Balancing | Custom domain + managed certificate enabled by default (enable_custom_domain = true) |
Sensible defaults worth knowing up front:
- SQLite is the only "database."
database_typeis fixed toNONEbyChibisafe_Common; the manydatabase_*/db_*variables mirrored invariables.tfexist 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 = trueby default, which auto-resolvesworkload_typetoStatefulSetwith a 20Gistandard-rwoPVC 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 onchibisafe/chibisafe-server(backend at/app) that copies in thechibisafe/chibisafeNext.js front-end (/opt/chibisafe-web) and a static Caddy2.11.4binary. The build reads its ownCHIBISAFE_VERSIONbuild arg (not the genericAPP_VERSIONthe Foundation injects; one tag pins backend and front-end);application_version = "latest"is pinned tov6.5.5at build time. - No Redis, ever. The variant mirrors an
enable_redisvariable for Foundation convention parity, butmain.tfalways forwardsenable_redis = falseto App_GKE regardless of its value — Chibisafe has no Redis dependency. - Custom domain is on by default. Unlike most modules,
enable_custom_domain = trueout of the box; setapplication_domainsfor the managed certificate to actually attach to a hostname. - No mandatory secrets.
enable_api_key = falseby default — the backend creates the first-run owner accountadminwith the well-known upstream passwordadmin; change it immediately after first login in the web UI. Flipenable_api_keytotrueto pre-seed a randomADMIN_PASSWORDfrom Secret Manager instead. - All state lives under one mount. The entrypoint symlinks the image's
/app/database,/app/uploads, and/app/logsdirectories 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
storagebucket. - 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_Commoninjects nodb-init/migration job by default. Theinitialization_jobsvariable 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 (/databy 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. Ifenable_api_key = true, a random value is generated and injected asADMIN_PASSWORD, which the backend uses as that account's password instead of the well-known upstream default (admin); otherwise log in withadmin/adminand change it immediately.ADMIN_PASSWORDis 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 noDB_HOST/DB_USERinjection or aliasing to worry about; SQLite lives entirely on the/datavolume. -
Processes and ports.
tiniis PID 1; the entrypoint (after the state relocation above) starts three processes:Process Listens on Serves Caddy 0.0.0.0:8000(container_port)The only listener the Service routes to chibisafe-server backend 127.0.0.1:18000(loopback only)/api/*,/docs*Next.js front-end 127.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.5Caddyfile, same order): any path naming a file under/data/uploadsis served directly by Caddy (the backend does not serve uploads in production);/api/*→ backend (the REST API — see theapi_urloutput);/docs*→ backend (the Scalar OpenAPI reference); everything else → front-end (the web UI at/, e.g./dashboard,/login). Two deviations from upstream: theHostheader is preserved, so the file links the backend builds are correct without setting "Serve uploads from"; andX-Forwarded-For/X-Real-IPare 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=productionis the only container-wide default;HOST/HOSTNAME/PORTfor the two Node processes are set per process by the entrypoint (HOSTNAMEmust be overridden because Kubernetes sets it to the pod name).PORTis deliberately left unset byChibisafe_Common; Caddy falls back to8000, matchingcontainer_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
1Ginow holds two Node processes plus Caddy; this has not been measured live yet — raisememory_limitif 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-wideHOST=0.0.0.0env var (now set per process) and leaves the data on the/dataPVC 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_probedefaultpath = "/api/health", matchingChibisafe_CloudRun), sent through Caddy to the backend, which returns a literal200 {"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 alternatehealth_check_config/startup_probe_configvariables now also defaultpath = "/api/health"but are superseded — the foundation takes the probes fromstartup_probe/liveness_probe. -
Single-writer scaling constraint.
min_instance_count = max_instance_count = 1by 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
| Variable | Default | Description |
|---|---|---|
application_name | chibisafe | Base name for resources. Do not change after first deploy. |
application_version | latest | chibisafe/chibisafe-server image tag; latest is pinned to v6.5.5 at build time via the app-specific CHIBISAFE_VERSION build arg. |
enable_api_key | false | Generates 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
| Variable | Default | Description |
|---|---|---|
cpu_limit | 1000m | 1 vCPU default. |
memory_limit | 1Gi | 1 GiB default, shared by two Node processes and Caddy; not yet measured live. |
min_instance_count / max_instance_count | 1 / 1 | Keep at 1 — Chibisafe is a single-writer SQLite app. |
container_port | 8000 | The Caddy proxy's port. Fixed by Chibisafe_Common; this variable is not forwarded to App_GKE and changing it has no effect. |
enable_cloudsql_volume | false | Chibisafe has no Cloud SQL database — leave false. |
enable_image_mirroring | true | Mirrors the built image into Artifact Registry. |
Group 6 — GKE Backend & Cluster
| Variable | Default | Description |
|---|---|---|
service_type | LoadBalancer | Internal by default; the Gateway path (Group 19) is the default route to external traffic. |
workload_type | null → StatefulSet | Auto-resolves because stateful_pvc_enabled = true by default. |
session_affinity | None | No client stickiness configured by default. |
Group 7 — StatefulSet / PVC
| Variable | Default | Description |
|---|---|---|
stateful_pvc_enabled | true | Required — SQLite does not tolerate GCS FUSE's POSIX file locking. Auto-resolves workload_type to StatefulSet. |
stateful_pvc_size | 20Gi | Size the PVC to hold the SQLite DB plus all uploaded files. |
stateful_pvc_mount_path | /data | The entrypoint symlinks /app/database, /app/uploads, and /app/logs into this mount. |
stateful_pvc_storage_class | standard-rwo | SSD-backed Balanced PD; draws the SSD_TOTAL_GB quota — override to standard (HDD) on quota-constrained projects. |
stateful_fs_group | 3000 | Matches the Chibisafe Helm chart's UID 1000 / GID 2000 convention so the PVC is group-writable. |
Group 10 — Observability
| Variable | Default | Description |
|---|---|---|
startup_probe / liveness_probe | path = "/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_config | path = "/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_config | enabled = false, path = "/api/health" | Enable to add a public uptime check and alert once the endpoint is publicly reachable. |
Group 14 — Cloud Storage
| Variable | Default | Description |
|---|---|---|
create_cloud_storage | true | Provisions 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
| Variable | Default | Description |
|---|---|---|
enable_redis | true (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
| Variable | Default | Description |
|---|---|---|
enable_custom_domain | true | On 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_ip | true | Stable 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.
| Output | Description |
|---|---|
service_name | Kubernetes Service name. |
namespace | Namespace the workload runs in. |
service_cluster_ip | In-cluster ClusterIP. |
stage_service_cluster_ips | Map of ClusterIPs for stage-specific services. |
service_external_ip | External LoadBalancer IP (when service_type = LoadBalancer and a static IP is reserved). |
service_url | URL 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_url | Base 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_id | Secret Manager secret ID for the optional admin-password secret. Empty when enable_api_key = false. |
storage_buckets | Created Cloud Storage buckets. |
network_name / network_exists / regions | VPC network, presence, available regions. |
container_image / container_registry | Deployed image and Artifact Registry repo. |
monitoring_enabled / monitoring_notification_channels | Monitoring status and channels. |
deployment_id / tenant_id / resource_prefix | Naming identifiers. |
project_id / project_number | Project identifiers. |
initialization_jobs | Names of any custom initialization jobs. |
statefulset_name | Name of the StatefulSet. |
cicd_enabled / cicd_configuration | CI/CD status and details (repo, trigger, registry). |
github_repository_url / github_repository_owner / github_repository_name | CI/CD GitHub details. |
artifact_registry_repository / cloudbuild_trigger_name / cloudbuild_trigger_id | Registry and build trigger. |
kubernetes_ready | Whether the cluster/workload is ready. |
vpc_sc_enabled / vpc_sc_perimeter_name / vpc_sc_dry_run_mode | VPC-SC status. |
audit_logging_enabled / artifact_registry_cmek_enabled | Audit 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"withstateful_pvc_enabled = true,quota_memory_*given as bare integers, an out-of-rangecontainer_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.
| Setting | Sensible value | Risk | Consequence if wrong |
|---|---|---|---|
stateful_pvc_enabled | true | Critical | Disabling 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 | /data | Critical | The 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_type | null (→ StatefulSet) | Critical | Forcing 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_count | 1 | High | Chibisafe 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_group | 3000 | High | A 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_class | standard-rwo (override to standard if constrained) | Medium | SSD-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 / _limits | binary units (4Gi, 8192Mi) | Critical | Bare integers are treated as bytes and block all pod scheduling in the namespace (only relevant if enable_resource_quota = true). |
enable_custom_domain | true with application_domains set | Medium | Left on with an empty application_domains, the Gateway/managed-certificate path has no hostname to attach to. |
enable_redis | any value (inert) | Low | main.tf always forwards enable_redis = false — changing this variable has no effect; do not rely on it to add Redis connectivity. |
container_port | 8000 (fixed) | Low | The 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_* variables | NONE / inert | Low | Chibisafe has no SQL database; these exist only for Foundation-variable mirroring and are silently ignored. |
enable_api_key | true if the service is externally reachable; otherwise change the default password at first login | Medium | With 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).
Related guides
- Hands-on lab: Chibisafe on GKE Autopilot — deploy it step by step, with the console screens and commands at each stage.
- Chibisafe on Google Cloud Run — the same application on Cloud Run, for when you need the other deployment target.
- Chibisafe Common — Shared Application Configuration — the configuration shared by both deployment targets.
Need RAD to do something it does not do yet? Request it on the roadmap, or vote on what is already there.