Google Cloud Run
Deploy Openfuse on Google Cloud Run with Cloud SQL, Cloud Run Jobs for the Config Importer, and Cloud Load Balancing for hostname-based routing.
This guide covers deploying Openfuse on Google Cloud Run. For the single-server Docker Compose setup, see Docker Compose.
Prerequisites
- A Google Cloud project with Cloud Run, Cloud SQL, and Secret Manager enabled
- A managed PostgreSQL 17+ instance (Cloud SQL) with two databases:
openfuseandkeycloak - A domain with wildcard DNS records
- A global external Application Load Balancer for hostname-based routing
Architecture
| Component | Cloud Run Resource | Notes |
|---|---|---|
| API | Service | Stateless, auto-scales |
| Keycloak | Service | Min instances: 1 (avoid cold starts) |
| UI | Service | Static SPA, or use Cloud CDN |
| Config Importer | Job | Execute during deployments |
Load balancer routing
Cloud Run services get individual URLs by default, but Openfuse requires hostname-based routing. Use a global external Application Load Balancer with URL maps:
| Host rule | Path | Backend service |
|---|---|---|
*.api.<ROOT_DOMAIN> | /* | API (serverless NEG) |
sso.<ROOT_DOMAIN> | /* | Keycloak (serverless NEG) |
| Default | /* | UI (serverless NEG) |
TLS terminates at the load balancer using Google-managed certificates.
Secret Manager
Store secrets in Google Secret Manager:
echo -n "your-db-password" | gcloud secrets create openfuse-db-password --data-file=-
echo -n "your-session-secret" | gcloud secrets create openfuse-session-secret --data-file=-
# ... repeat for each secretReference in Cloud Run services:
gcloud run services update openfuse-api \
--set-secrets=DATABASE_PASSWORD=openfuse-db-password:latest,SESSION_SECRET=openfuse-session-secret:latestConfig Importer
Run the Config Importer as a Cloud Run Job:
# Create the job
gcloud run jobs create openfuse-config-importer \
--image ghcr.io/openfuseio/openfuse-config-importer:1.0.0 \
--region us-central1 \
--set-env-vars KEYCLOAK_URL=http://keycloak-internal:8080 \
--set-env-vars IMPORT_VARSUBSTITUTION_ENABLED=true \
--set-env-vars IMPORT_VARSUBSTITUTION_UNDEFINEDISTERROR=true \
--set-secrets KEYCLOAK_PASSWORD=openfuse-kc-admin-password:latest \
# ... remaining env vars and secrets
# Execute it
gcloud run jobs execute openfuse-config-importer \
--region us-central1 \
--waitThe importer waits up to 120s for Keycloak to be ready. Run on first deployment and on upgrades that include realm config changes.
API service
gcloud run deploy openfuse-api \
--image ghcr.io/openfuseio/openfuse-api:1.0.0 \
--region us-central1 \
--port 3000 \
--min-instances 1 \
--set-env-vars ROOT_DOMAIN=openfuse.example.com \
--set-env-vars DATABASE_HOST=/cloudsql/project:region:instance \
--set-env-vars DATABASE_SSL=true \
--set-env-vars KEYCLOAK_URL=http://keycloak-internal:8080 \
--set-env-vars KEYCLOAK_EXTERNAL_URL=https://sso.openfuse.example.com \
--set-secrets=DATABASE_PASSWORD=openfuse-db-password:latest,SESSION_SECRET=openfuse-session-secret:latest \
--add-cloudsql-instances project:region:instanceThe API is stateless — Cloud Run auto-scales based on traffic. All instances must share the same SESSION_SECRET. Database migrations use an advisory lock, so concurrent startups won't conflict.
Keycloak service
gcloud run deploy keycloak \
--image ghcr.io/openfuseio/openfuse-keycloak:1.0.0 \
--region us-central1 \
--port 8080 \
--min-instances 1 \
--args start \
--set-env-vars KC_DB=postgres \
--set-env-vars KC_HOSTNAME=sso.openfuse.example.com \
--set-env-vars KC_PROXY_HEADERS=xforwarded \
--set-env-vars KC_HTTP_ENABLED=true \
--set-env-vars KC_HEALTH_ENABLED=true \
--set-secrets KC_DB_PASSWORD=openfuse-db-password:latest \
--add-cloudsql-instances project:region:instanceSet --min-instances 1 to avoid cold start delays on the login page.
Next steps
AWS ECS
Deploy Openfuse on AWS ECS with Fargate, ALB hostname-based routing, Secrets Manager, and CDK examples for the API, Keycloak, UI, and Config Importer.
Azure Container Apps
Deploy Openfuse on Azure Container Apps with Azure Database for PostgreSQL, Key Vault for secrets, and hostname-based routing via custom domains.