Run Weldall and the discovery proxy as Cloud Run services with Cloud SQL for PostgreSQL and Secret Manager.
This guide deploys Weldall as a Cloud Run service with one instance, stores its data in Cloud SQL for PostgreSQL and its secrets in Secret Manager, and deploys the discovery proxy as a second, independent Cloud Run service. It ends with a backup, an upgrade and a rollback, so you know the procedure before you need it.
Docker images explains the images, tags and start-up behavior this guide relies on.
Before you start
Section titled “Before you start”- A Google Cloud project with billing enabled, and the Owner role in it.
- Cloud Shell. It has
gcloud,nodeandjqpreinstalled; every command below runs there. - The versions of the two images you want to run, for example
0.5.1for Weldall and0.1.1for the discovery proxy. The available versions are the tags on Docker Hub:seibertgroup/weldallandseibertgroup/weldall-discovery-proxy. Use a fullX.Y.Ztag, see Docker images. - Access to your identity provider to create an OIDC client, see How to: Run the installer.
Set these variables once per Cloud Shell session:
PROJECT=your-project-idPROJECT_NUMBER=$(gcloud projects describe "$PROJECT" --format="value(projectNumber)")REGION=europe-west3WELDALL_VERSION=0.5.1PROXY_VERSION=0.1.1DB_TIER=db-f1-micro # database machine type for a test; for production e.g. db-custom-1-3840gcloud config set project "$PROJECT"1. Enable the services
Section titled “1. Enable the services”gcloud services enable run.googleapis.com sqladmin.googleapis.com \ secretmanager.googleapis.com iam.googleapis.com2. Create the database
Section titled “2. Create the database”gcloud sql instances create weldall-db \ --region "$REGION" \ --database-version POSTGRES_16 \ --edition ENTERPRISE \ --tier "$DB_TIER"
gcloud sql databases create weldall --instance weldall-db- Creating the instance takes about 15 minutes.
- The command sets only what Weldall needs: the region of the Cloud Run service, PostgreSQL 16 and a machine type. Storage, availability and automatic backups keep the Cloud SQL defaults; check them against your requirements in the instance settings.
db-f1-microis a shared-core machine type for tests and not covered by the Cloud SQL SLA. For production, setDB_TIERto a dedicated-core type such asdb-custom-1-3840.--edition ENTERPRISEis required for these machine types; PostgreSQL 16 otherwise defaults to Enterprise Plus.
3. Create the database user
Section titled “3. Create the database user”Weldall applies its migrations on every start, so its database user must be allowed to change the schema. A user created with gcloud sql users create is a member of cloudsqlsuperuser and can create and alter tables in the public schema of weldall.
The password goes directly into the connection URL in Secret Manager and is not stored anywhere else:
CONN="${PROJECT}:${REGION}:weldall-db"pw=$(node -e 'process.stdout.write(require("node:crypto").randomBytes(24).toString("base64url"))')gcloud sql users create weldall --instance weldall-db --password "$pw"printf 'postgresql://weldall:%s@localhost/weldall?host=/cloudsql/%s' "$pw" "$CONN" \ | gcloud secrets create weldall-postgres-url \ --replication-policy user-managed --locations "$REGION" --data-file=-unset pwCloud Run connects to Cloud SQL through a Unix socket under /cloudsql/. The host in the URL stays localhost; the socket path is the host parameter. The instance needs no authorized networks.
4. Create the service accounts
Section titled “4. Create the service accounts”Each service runs under its own account with only the permissions it needs. The proxy needs none.
gcloud iam service-accounts create weldall-run --display-name "Weldall on Cloud Run"gcloud iam service-accounts create weldall-proxy-run --display-name "Weldall discovery proxy on Cloud Run"
gcloud projects add-iam-policy-binding "$PROJECT" \ --member "serviceAccount:weldall-run@${PROJECT}.iam.gserviceaccount.com" \ --role roles/cloudsql.client --condition=None5. Store the secrets
Section titled “5. Store the secrets”The command generates the secrets, writes each one directly to Secret Manager without printing it, and lets only weldall-run read them:
tmp=$(mktemp); chmod 600 "$tmp"node -e 'const { generateKeyPairSync, randomBytes, randomUUID } = require("node:crypto");const { privateKey, publicKey } = generateKeyPairSync("ec", { namedCurve: "P-256" });process.stdout.write(JSON.stringify({ "weldall-better-auth-secret": randomBytes(32).toString("base64url"), "weldall-setup-token": randomBytes(32).toString("base64url"), "weldall-credential-encryption-key": randomBytes(32).toString("base64"), "weldall-connector-kek": randomBytes(32).toString("base64"), "weldall-signing-private-jwk": JSON.stringify(privateKey.export({ format: "jwk" })), "weldall-signing-public-jwk": JSON.stringify(publicKey.export({ format: "jwk" })), "weldall-signing-kid": randomUUID(),}));' > "$tmp"
for name in weldall-better-auth-secret weldall-setup-token weldall-credential-encryption-key \ weldall-connector-kek weldall-signing-private-jwk weldall-signing-public-jwk \ weldall-signing-kid; do jq -j --arg k "$name" '.[$k]' "$tmp" | gcloud secrets create "$name" \ --replication-policy user-managed --locations "$REGION" --data-file=-donerm -f "$tmp"
for name in weldall-postgres-url weldall-better-auth-secret weldall-setup-token \ weldall-credential-encryption-key weldall-connector-kek \ weldall-signing-private-jwk weldall-signing-public-jwk weldall-signing-kid; do gcloud secrets add-iam-policy-binding "$name" \ --member "serviceAccount:weldall-run@${PROJECT}.iam.gserviceaccount.com" \ --role roles/secretmanager.secretAccessordoneGenerate these secrets once and never replace them while this installation exists. Docker images explains why.
6. Deploy Weldall
Section titled “6. Deploy Weldall”The URL of a Cloud Run service is known before the first deployment: https://SERVICE-PROJECT_NUMBER.REGION.run.app. Weldall needs it as WELDALL_ISSUER from the first start, because the callback URL you register at your identity provider is built from it.
WELDALL_URL="https://weldall-${PROJECT_NUMBER}.${REGION}.run.app"
gcloud run deploy weldall --region "$REGION" \ --image "docker.io/seibertgroup/weldall:${WELDALL_VERSION}" \ --service-account "weldall-run@${PROJECT}.iam.gserviceaccount.com" \ --port 3000 \ --max-instances 1 \ --add-cloudsql-instances "$CONN" \ --set-env-vars "WELDALL_ISSUER=${WELDALL_URL}" \ --set-secrets "POSTGRES_URL=weldall-postgres-url:latest,BETTER_AUTH_SECRET=weldall-better-auth-secret:latest,WELDALL_SETUP_TOKEN=weldall-setup-token:latest,WELDALL_CREDENTIAL_ENCRYPTION_KEY=weldall-credential-encryption-key:latest,WELDALL_CONNECTOR_KEK=weldall-connector-kek:latest,WELDALL_SIGNING_PRIVATE_JWK=weldall-signing-private-jwk:latest,WELDALL_SIGNING_PUBLIC_JWK=weldall-signing-public-jwk:latest,WELDALL_SIGNING_KID=weldall-signing-kid:latest" \ --liveness-probe "httpGet.path=/.well-known/openid-configuration,httpGet.port=3000,periodSeconds=30,timeoutSeconds=5,failureThreshold=3" \ --allow-unauthenticated- The command sets only what Weldall needs. CPU, memory and minimum instances keep the Cloud Run defaults; adjust them to your requirements, see the
gcloud run deployreference. --port 3000is the port the Weldall image listens on.--max-instances 1keeps Weldall to one instance; Docker images explains why. The limit applies per revision: during a deployment, the old and the new revision run side by side for a short time.--liveness-probemakes Cloud Run restart an instance that hangs. Without it, Cloud Run only notices a process that exits.--allow-unauthenticatedmakes Weldall reachable for browsers, the CLI and resource servers. Cloud Run provides the HTTPS certificate for therun.appURL. The installer stays closed to anyone without the setup token.- Cloud Run pulls public Docker Hub images without credentials and pins the image digest per revision. A moving tag such as
0.5orlatesttherefore does not change a running service; only the nextgcloud run deployresolves it again. - By default, Cloud Run stops the instance when idle. The first request afterwards waits for a cold start of a few seconds.
--min-instances 1avoids that and is billed continuously.
7. Verify Weldall and run the installer
Section titled “7. Verify Weldall and run the installer”curl -s "$WELDALL_URL/.well-known/openid-configuration" | jq -r .issuer # prints $WELDALL_URLcurl -s "$WELDALL_URL/api/me/skills"; echo # invalid_token
gcloud logging read \ 'resource.type="cloud_run_revision" AND resource.labels.service_name="weldall"' \ --order=asc --limit 200 --format="value(textPayload,jsonPayload.message)" \ | grep -E "migrations found|Applying migration|successfully applied|No pending|Deployment initialization|server initialized"The second call answers with invalid_token. That is the expected result: the API requires a login.
On the first start, the log shows every migration being applied, All migrations have been successfully applied., then Deployment initialization completed, then Weldall server initialized.
Open $WELDALL_URL and follow How to: Run the installer. Copy the setup token to the clipboard without printing it, for example in a local terminal on macOS:
gcloud secrets versions access latest --secret weldall-setup-token --project "$PROJECT" | pbcopy8. Deploy the discovery proxy
Section titled “8. Deploy the discovery proxy”Skip this step if all your resource servers can reach $WELDALL_URL directly.
gcloud run deploy weldall-discovery-proxy --region "$REGION" \ --image "docker.io/seibertgroup/weldall-discovery-proxy:${PROXY_VERSION}" \ --service-account "weldall-proxy-run@${PROJECT}.iam.gserviceaccount.com" \ --set-env-vars "WELDALL_UPSTREAM=${WELDALL_URL}" \ --allow-unauthenticatedEverything else keeps the Cloud Run defaults, including port 8080, which is the port the proxy listens on.
Verify that the proxy forwards both documents unchanged and blocks everything else:
PROXY_URL="https://weldall-discovery-proxy-${PROJECT_NUMBER}.${REGION}.run.app"cmp <(curl -s "$WELDALL_URL/.well-known/oauth-authorization-server") \ <(curl -s "$PROXY_URL/.well-known/oauth-authorization-server") && echo identicalcmp <(curl -s "$WELDALL_URL/api/oauth/jwks") <(curl -s "$PROXY_URL/api/oauth/jwks") && echo identicalcurl -s -o /dev/null -w "%{http_code}\n" "$PROXY_URL/.well-known/openid-configuration" # 404curl -s -o /dev/null -w "%{http_code}\n" -X POST "$PROXY_URL/api/oauth/jwks" # 405Resource servers use $PROXY_URL as discoveryProxyOrigin and keep $WELDALL_URL as the issuer, see Discovery proxy.
9. Upgrade Weldall
Section titled “9. Upgrade Weldall”Take a backup directly before the upgrade and note its ID:
NEW_VERSION=0.5.2 # the version you upgrade togcloud sql backups create --instance weldall-db --description "before Weldall ${NEW_VERSION}"gcloud sql backups list --instance weldall-db --limit 3Deploy the new version. Only the image changes; Cloud Run keeps every other setting of the previous revision:
gcloud run deploy weldall --region "$REGION" \ --image "docker.io/seibertgroup/weldall:${NEW_VERSION}"The log of the new revision shows only the new migrations, then the initialization and the server start. Run the checks from step 7 again.
10. Roll Weldall back
Section titled “10. Roll Weldall back”Starting the previous image alone is not enough. The older version starts without a warning and reports No pending migrations to apply., while the database keeps the schema of the newer version. Docker images explains the consequences.
Restore the backup from step 9, then start the previous image:
gcloud sql backups restore BACKUP_ID --restore-instance weldall-db --backup-instance weldall-dbgcloud run deploy weldall --region "$REGION" \ --image "docker.io/seibertgroup/weldall:${WELDALL_VERSION}"- The restore replaces the whole instance with the state of the backup. Logins, administration changes and audit records written after the backup are lost.
- The database is unavailable during the restore, which takes several minutes. Plan a maintenance window.
11. Upgrade and roll back the proxy
Section titled “11. Upgrade and roll back the proxy”The proxy stores nothing and is independent of Weldall. Upgrade it with a new image, and roll it back by sending the traffic to the previous revision:
NEW_PROXY_VERSION=0.1.2 # the version you upgrade togcloud run deploy weldall-discovery-proxy --region "$REGION" \ --image "docker.io/seibertgroup/weldall-discovery-proxy:${NEW_PROXY_VERSION}"
gcloud run revisions list --service weldall-discovery-proxy --region "$REGION"gcloud run services update-traffic weldall-discovery-proxy --region "$REGION" \ --to-revisions PREVIOUS_REVISION=100After --to-revisions, the traffic stays pinned to that revision, and later deployments receive none. Undo the pin before the next upgrade:
gcloud run services update-traffic weldall-discovery-proxy --region "$REGION" --to-latestDo not roll back Weldall this way: it would reactivate an old revision without restoring the database.
