Self-hosting
Google Cloud setup
The Google Cloud reference deployment: Cloud Run, Cloud SQL with IAM database auth, Cloud Storage, Secret Manager, an SMTP relay and a Cloud Scheduler OIDC tick, from the Terraform template.
This is the reference deployment on Google Cloud. The template is in deploy/gcp/terraform/, and deploy/gcp/README.md has the full commands. The GCP reference profile runs the same provider combination locally against emulators.
| Area | Google Cloud service | Settings |
|---|---|---|
| Hosting | Cloud Run service and a Cloud Run migrate job | |
| Database | Cloud SQL for PostgreSQL 16 with IAM database auth, over the Cloud Run Cloud SQL socket | DB_PROVIDER=postgres, DATABASE_AUTH=gcp, DATABASE_URL=postgresql://<sa>%40<project>.iam@/usertasks?host=/cloudsql/<connection> |
| Auth | Built-in, plus Google over OIDC | AUTH_SSO_PROVIDERS with "preset":"google" and hostedDomain |
| Storage | Cloud Storage (public access blocked) | STORAGE_PROVIDER=gcs, GCS_PROJECT_ID, STORAGE_BUCKET_MAP |
| Realtime | Built-in SSE | REALTIME_PROVIDER=sse |
| Scheduler | Cloud Scheduler every minute, with an OIDC token | SCHEDULER_PROVIDER=external, SCHEDULER_OIDC_SERVICE_ACCOUNTS, SCHEDULER_OIDC_AUDIENCE |
| Workspace SMTP relay, or any SMTP relay | EMAIL_PROVIDER=smtp, SMTP_*, SMTP_PASSWORD=secret://smtp-password | |
| Secrets | Secret Manager (roles/secretmanager.secretAccessor) | SECRETS_PROVIDER=gcp_secret_manager, GCP_SECRET_MANAGER_PROJECT, ENCRYPTION_KEY=secret://encryption-key; optionally GCP_SECRET_MANAGER_ENDPOINT for a regional endpoint |
| Log export (per workspace) | Cloud Logging or Pub/Sub destinations, with a service-account key | Settings → Log Export; LOG_EXPORT_ALLOW_INSTANCE_IDENTITY=true to let destinations use the service's workload identity (single-tenant only) |
| KMS (optional) | A Cloud KMS key wrapping the data keys (roles/cloudkms.cryptoKeyEncrypterDecrypter) | KMS_PROVIDER=gcp_kms, GCP_KMS_KEY_NAME; then usertasks-admin kms rotate and kms rewrap |
| Cache | Memorystore for Redis / Valkey with in-transit encryption (needed with more than one instance) | CACHE_PROVIDER=redis, CACHE_REDIS_URL=rediss://<ip>:6378, CACHE_REDIS_TLS_CA_FILE, CACHE_REDIS_PASSWORD (AUTH string) or CACHE_REDIS_AUTH=gcp_iam; or CACHE_PROVIDER=postgres |
Steps
- Create the infrastructure:
terraform applywithdeploy_apps=false. That enables the APIs and creates Artifact Registry, Cloud SQL, the buckets and the secrets. - Push the image to Artifact Registry. Build it with
--build-arg INCLUDE_OPTIONAL_DB_DRIVERS=trueif workflows use the Snowflake, Oracle or MongoDB connectors (Optional drivers). - Grant the IAM database user its privileges. Run the
db_grant_sqloutput once aspostgres, for example in Cloud SQL Studio. A new IAM database user has no privileges, so the migrations can't create the API roles without this step. - Create the services:
terraform applywithdeploy_apps=true. Then run the migrate job:gcloud run jobs execute <prefix>-migrate. - Create the first workspace. Run the migrate job once with overridden arguments (
node admin.cjs bootstrap --email … --org …), with the password inBOOTSTRAP_PASSWORD. - Check the install: run
node admin.cjs doctorthe same way.
Not wired up yet
- The Cloud SQL Node.js Connector. The app uses Cloud Run's built-in socket instead.
Moving an existing Supabase install
See Switching providers. For the database step, the target role needs cloudsqlsuperuser.