Minimalistic setup to deploy n8n workflow automation on Google Cloud Run with external PostgreSQL.
- Terraform >= 1.0
- gcloud CLI configured
- A PostgreSQL database (free tier works):
Create a free PostgreSQL database at NeonDB or Supabase.
Copy your connection string. It should look like:
postgresql://user:password@host.neon.tech:5432/n8n?sslmode=require
cd terraform
# Copy and edit the example config
cp terraform.tfvars.example terraform.tfvars
# Edit terraform.tfvars with your values
# Deploy
terraform init
terraform applyThis allows GitHub Actions to authenticate to GCP without storing service account keys.
# Set your project
export PROJECT_ID="your-project-id"
export GITHUB_REPO="your-username/n8n-gcloud"
# Create Workload Identity Pool
gcloud iam workload-identity-pools create "github-pool" \
--location="global" \
--display-name="GitHub Actions Pool"
# Create Provider
gcloud iam workload-identity-pools providers create-oidc "github-provider" \
--location="global" \
--workload-identity-pool="github-pool" \
--display-name="GitHub Provider" \
--attribute-mapping="google.subject=assertion.sub,attribute.actor=assertion.actor,attribute.repository=assertion.repository" \
--issuer-uri="https://token.actions.githubusercontent.com"
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:github-actions@${PROJECT_ID}.iam.gserviceaccount.com" \
--role="roles/serviceusage.serviceUsageAdmin"
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:github-actions@${PROJECT_ID}.iam.gserviceaccount.com" \
--role="roles/iam.serviceAccountUser"
# Allow GitHub to impersonate the service account
gcloud iam service-accounts add-iam-policy-binding \
"github-actions@${PROJECT_ID}.iam.gserviceaccount.com" \
--role="roles/iam.workloadIdentityUser" \
--member="principalSet://iam.googleapis.com/projects/$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')/locations/global/workloadIdentityPools/github-pool/attribute.repository/${GITHUB_REPO}"Go to Settings β Secrets and variables β Actions and add:
| Secret | Value |
|---|---|
GCP_PROJECT_ID |
Your GCP project ID |
GCP_WORKLOAD_IDENTITY_PROVIDER |
projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/github-pool/providers/github-provider |
GCP_SERVICE_ACCOUNT |
github-actions@PROJECT_ID.iam.gserviceaccount.com |
DB_HOST |
Database host (e.g., ep-xy.eu-central-1.aws.neon.tech) |
DB_NAME |
Database name (e.g., neondb) |
DB_USER |
Database username |
DB_PASSWORD |
Database password |
N8N_ENCRYPTION_KEY |
Generate with openssl rand -hex 32 |
N8N_HOST |
Public URL for n8n (e.g., n8n.titenkov.com) |
Go to Actions β Deploy n8n β Run workflow and select "apply".
βββββββββββββββββββ βββββββββββββββββββ
β Cloud Run ββββββΆβ PostgreSQL β
β (n8n) β β (NeonDB/ β
β β β Supabase) β
ββββββββββ¬βββββββββ βββββββββββββββββββ
β
βΌ
βββββββββββββββββββ
β Secret Manager β
β - DB URL β
β - Encryption Keyβ
βββββββββββββββββββ
| Component | Cost |
|---|---|
| Cloud Run | ~$0-5/month (pay per use, scale to zero) |
| PostgreSQL | $0 (free tier) |
| Secret Manager | $0.06/month |
| Total | ~$0-5/month |
Ensure your GCP service account has the required roles:
roles/run.adminroles/secretmanager.adminroles/iam.serviceAccountAdminroles/serviceusage.serviceUsageAdmin
- Check your
DATABASE_URLformat includes?sslmode=require - Verify the database is accessible from the internet
- Check Cloud Run logs:
gcloud run services logs read n8n
Ensure N8N_ENCRYPTION_KEY is set correctly. If you change this key, you'll need to reconfigure all credentials in n8n.
If webhooks are generating URLs with localhost instead of your actual domain, ensure the n8n_host variable is set in your terraform.tfvars file (e.g., n8n_host = "n8n.example.com"). This sets the N8N_HOST environment variable which tells n8n its public URL.
MIT