Deploy on Google Cloud

Google Cloud Run and Cloud SQL provide a conventional autoscaling container deployment with managed Postgres, IAM, private networking, logs, and rollout controls.

Architecture#

Prerequisites#

  • A Google Cloud project with billing.
  • Artifact Registry, Cloud Run, Cloud SQL Admin, Secret Manager, and Cloud Build APIs enabled.
  • A region selected for all compute and database resources.
  • Service accounts for web, API, and deployment automation.

Database#

Create Postgres 16 in Cloud SQL, preferably with private IP and automated backups. Create separate doso and doso_auth databases and a least-privilege application user.

Use the Cloud SQL Unix socket or private IP:

1DATABASE_URL=postgresql://doso:PASSWORD@/doso?host=/cloudsql/PROJECT:REGION:INSTANCE2BETTER_AUTH_DATABASE_URL=postgresql://doso:PASSWORD@/doso_auth?host=/cloudsql/PROJECT:REGION:INSTANCE

Store URLs and keys in Secret Manager. Attach the Cloud SQL instance to each Cloud Run service that needs it.

Build images#

From the repository root:

1REGION=us-central12PROJECT=your-project3REPOSITORY=doso4 5gcloud artifacts repositories create "$REPOSITORY" \6  --repository-format=docker --location="$REGION"7 8gcloud builds submit \9  --tag "$REGION-docker.pkg.dev/$PROJECT/$REPOSITORY/api" \10  --file crates/doso-api/Dockerfile .11 12gcloud builds submit web \13  --tag "$REGION-docker.pkg.dev/$PROJECT/$REPOSITORY/web" \14  --file web/Dockerfile \15  --substitutions=_NEXT_PUBLIC_DOSO_AUTH_MODE=session

Deploy API#

1gcloud run deploy doso-api \2  --image "$REGION-docker.pkg.dev/$PROJECT/$REPOSITORY/api" \3  --region "$REGION" \4  --no-allow-unauthenticated \5  --add-cloudsql-instances "PROJECT:REGION:INSTANCE" \6  --set-env-vars "HTTP_ADDR=:8080,DOSO_AUTH_MODE=jwks,DOSO_AUTH_ISSUER=https://app.example.com,DOSO_AUTH_AUDIENCE=https://app.example.com,DOSO_PUBLIC_API_URL=https://app.example.com,DOSO_POSTGRES_MAX_CONNECTIONS=5" \7  --set-env-vars "DOSO_JWKS_URL=https://app.example.com/api/auth/jwks" \8  --set-secrets "DATABASE_URL=doso-database-url:latest,DOSO_SETTINGS_KEY_HEX=doso-settings-key:latest"

Grant only the web service account permission to invoke the API, or route both behind an external Application Load Balancer. Keep minimum instances at one when background work must remain alive, and keep maximum instances at one until Doso supports distributed run ownership/events.

Deploy web#

1gcloud run deploy doso-web \2  --image "$REGION-docker.pkg.dev/$PROJECT/$REPOSITORY/web" \3  --region "$REGION" \4  --allow-unauthenticated \5  --add-cloudsql-instances "PROJECT:REGION:INSTANCE" \6  --set-env-vars "NEXT_PUBLIC_DOSO_AUTH_MODE=session,NEXT_PUBLIC_API_URL=,BETTER_AUTH_URL=https://app.example.com,DOSO_AUTH_ISSUER=https://app.example.com,DOSO_AUTH_AUDIENCE=https://app.example.com" \7  --set-env-vars "DOSO_API_PROXY_TARGET=https://doso-api-xxxxx.a.run.app" \8  --set-secrets "BETTER_AUTH_DATABASE_URL=doso-auth-database-url:latest,BETTER_AUTH_SECRET=better-auth-secret:latest"

For private invocation, configure the web service to attach a Google-signed ID token to API calls or place the services behind one load balancer. Doso JWT authorization remains the application-level gate.

Domains, migrations, and rollout#

  1. Map app.example.com to web (directly or through the load balancer).
  2. Run database migrations from Cloud Build or a Cloud Run Job using the same image and database attachment before promoting a revision.
  3. Shift traffic gradually between Cloud Run revisions.
  4. Verify JWKS, sign-in, /v1/**, streaming, and settings decryption.
  5. Use Cloud Logging, Error Reporting, and Cloud SQL metrics for operations.

Cloud Run's writable filesystem is ephemeral. Do not use it for SQLite, the settings key, or the Git vault. Use /tmp only for request-scoped scratch data.

SaaS#

Skip this page’s service list. Multi-org is ../../saas.

Official references: Cloud Run, Cloud SQL connections, and Cloud Run rollouts.