Who this is for
- Backends deployed on Zeabur from GitHub: Node.js, Python or Go APIs, or LINE and Discord bots
- Low traffic, where you’d like to pay no compute when nobody is using it (Cloud Run scales to zero)
- A nearby region:
asia-east1is in Taiwan; useasia-northeast1(Tokyo) orasia-northeast3(Seoul) if those are closer to your users
Not a good fit: services that need a persistent disk (for example, saving uploads to a local folder). Cloud Run’s filesystem is temporary; files written to it disappear after a redeploy or a scale to zero. Store such files in Cloud Storage or R2, or use a VPS instead (see the n8n post).
Step 0: Prepare a new project (per the official docs)
- Install the gcloud CLI and run
gcloud initto log in and pick a project. The project must be linked to a billing account - Enable the APIs:
gcloud services enable run.googleapis.com cloudbuild.googleapis.com
- For source deploys, Cloud Build uses the Compute Engine default service account by default, and the official docs say to grant it the Cloud Run Builder role:
gcloud projects add-iam-policy-binding YOUR_PROJECT_ID \
--member=serviceAccount:[email protected] \
--role=roles/run.builder
The docs note that the grant takes a couple of minutes to propagate.
Always check which project you’re using. Add
--project=YOUR_PROJECT_IDto everygcloudcommand, or rungcloud config get-value projectfirst. Our own machines have several projects, and the default is often not the one we mean to deploy to.
Step 1: Make sure the app listens on PORT
Both Zeabur and Cloud Run tell the app which port to listen on through the PORT environment variable. If you already used $PORT on Zeabur as its docs recommend, nothing changes. If the port is hard-coded to 3000, change it to:
app.listen(process.env.PORT || 3000);
Step 2: Deploy
Run this in the project root (no Dockerfile needed; Google’s buildpacks detect the language):
gcloud run deploy my-api --source . --region asia-east1 \
--allow-unauthenticated \
--set-env-vars "NODE_ENV=production" \
--project=YOUR_PROJECT_ID
When it finishes it prints Service URL: https://my-api-xxxx.asia-east1.run.app. In our test, a Node service with no Dockerfile responded on the very first deploy.
If the project root has a Dockerfile, Cloud Run uses it instead.
Step 3: Put secrets in Secret Manager, not in environment variables
Anyone who can view the service configuration can see --set-env-vars values. Put database passwords and API keys in Secret Manager:
# Create the secret (printf adds no trailing newline)
printf '%s' 'postgresql://...' | gcloud secrets create database-url --data-file=- --project=YOUR_PROJECT_ID
# Mount it on the service; the app still reads process.env.DATABASE_URL
gcloud run services update my-api --region asia-east1 \
--set-secrets "DATABASE_URL=database-url:latest" --project=YOUR_PROJECT_ID
The error you will probably hit
If the service account cannot read the secret, the deploy fails:
ERROR: (gcloud.run.deploy) ... Permission denied on secret: projects/.../secrets/database-url/versions/latest
for Revision service account [email protected]. The service account used must be granted
the 'Secret Manager Secret Accessor' role (roles/secretmanager.secretAccessor) at the secret, project or higher level.
The fix is to grant access on that one secret only (the narrowest scope) and redeploy:
gcloud secrets add-iam-policy-binding database-url \
--member="serviceAccount:THE_SERVICE_ACCOUNT_FROM_THE_ERROR" \
--role="roles/secretmanager.secretAccessor" --project=YOUR_PROJECT_ID
In our test, the redeploy succeeded immediately after the grant.
Step 4: The database
Cloud Run doesn’t include a database. PostgreSQL can move to a managed service such as Neon or Supabase, or to Google’s Cloud SQL. See the database post.
Step 5: Update your LINE bot’s webhook URL
- Open the LINE Developers console and select your channel
- On the Messaging API tab, change the Webhook URL to the new Cloud Run URL (plus your app’s path, such as
/webhook) - Click Verify to confirm it works
We also recommend replacing the Channel Secret and Access Token while you’re at it; see the security post.
Step 6: Custom domains
There are several ways to put a custom domain on Cloud Run (Cloud Run domain mapping, a load balancer, Firebase Hosting), with different region support and costs; choose using Google’s official docs. We did not test this step. For DNS switch-over tips, see the domains and DNS post.