How to Host n8n for Free on Google Cloud Platform


n8n is a powerful workflow automation tool that has gained significant popularity in recent years. It's a free and open-source alternative to tools like Zapier or Microsoft Power Automate. It lets us connect different services and automate repetitive tasks using a visual, node-based interface.
In this post, we will learn how to deploy n8n on a Google Cloud Platform (GCP) VM using Infrastructure Manager (Terraform-as-a-Service), Secret Manager, and Cloudflare Tunnel to expose it securely to the internet, with zero public IP required.
Prerequisites
Before we begin, we will need:
Google Cloud CLI installed and authenticated.
A Cloudflare Account with a registered domain.
A Service Account with Admin Role (
roles/admin
).
APIs
We need to enable the Infrastructure Manager API, the Compute Engine API, the Cloud Storage API, and the Secret Manager API:
gcloud services enable config.googleapis.com
gcloud services enable compute.googleapis.com
gcloud services enable storage.googleapis.com
gcloud services enable secretmanager.googleapis.com
Terraform Script
Create a terraform/main.tf
file with the following content:
terraform {
required_providers {
google = {
source = "hashicorp/google"
version = ">= 4.34.0"
}
}
}
variable "project_id" {
type = string
description = "The GCP project ID to deploy resources into."
}
variable "tunnel_id" {
type = string
description = "The Cloudflare tunnel ID."
}
variable "cloudflare_token" {
type = string
description = "The Cloudflare token."
sensitive = true
}
variable "domain" {
type = string
description = "The domain to expose n8n on."
}
resource "google_secret_manager_secret" "cloudflare_token" {
project = var.project_id
secret_id = "cloudflare-token"
replication {
auto {}
}
}
resource "google_secret_manager_secret_version" "cloudflare_token_version" {
secret = google_secret_manager_secret.cloudflare_token.id
secret_data = var.cloudflare_token
}
resource "google_project_iam_member" "secret_accessor" {
project = var.project_id
role = "roles/secretmanager.secretAccessor"
member = "serviceAccount:${google_compute_instance.free_tier_vm.service_account[0].email}"
}
resource "google_compute_instance" "free_tier_vm" {
project = var.project_id
machine_type = "e2-micro"
zone = "us-central1-a"
name = "free-vm"
boot_disk {
initialize_params {
image = "debian-cloud/debian-11"
}
}
network_interface {
network = "default"
access_config {}
}
metadata = {
startup-script = templatefile("${path.module}/startup-script.sh", {
secret_id = google_secret_manager_secret.cloudflare_token.secret_id
domain = var.domain
tunnel_id = var.tunnel_id
})
}
service_account {
scopes = ["cloud-platform"]
}
}
The Terraform script defines the infrastructure required to deploy n8n on a GCP VM, securely store sensitive data, and configure access permissions. Let's break down our configuration:
google_secret_manager_secret
: Creates a secret in Secret Manager for storing our Cloudflare token. Theauto
replication ensures the secret is automatically replicated across regions for high availability.google_secret_manager_secret_version
: Adds the actual token content as a versioned secret.google_project_iam_member
: This grants our VM's service account the necessary permissions to access the secret we created.google_compute_instance
: This creates our VM with the following specifications:Machine Type:
e2-micro
.Zone:
us-central1-a
.Operating System: Debian 11
Network: Uses the default VPC with external IP.
Startup Script: Templated script that receives our configuration variables.
Service Account: Configured with
cloud-platform
scope for necessary permissions.
Startup Script
Create the terraform/startup-script.sh
file and add the following code snippets.
apt-get update -y
apt-get install -y curl lsb-release
This ensures our system is up-to-date and has the basic tools needed for the installation.
curl -L --output cloudflared.deb https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
dpkg -i cloudflared.deb
rm cloudflared.deb
Downloads and installs the latest version of cloudflared
, which creates the secure tunnel to Cloudflare.
curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
apt-get install -y nodejs
npm install -g n8n
Installs Node.js 22.x
and then n8n globally via npm.
mkdir -p /opt/n8n
useradd -r -d /opt/n8n -s /bin/false n8n
chown -R n8n:n8n /opt/n8n
Creates a directory /opt/n8n
for n8n data. It also creates a system user n8n
with no login shell for security and sets the ownership of /opt/n8n
to this new user.
cat > /etc/systemd/system/n8n.service <<EOF
[Unit]
Description=n8n
Requires=network.target
After=network.target
[Service]
Type=simple
User=n8n
Group=n8n
WorkingDirectory=/opt/n8n
ExecStart=/usr/bin/n8n start
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
Defines a systemd
service file to run n8n, ensuring it starts after the network and restarts on failure.
mkdir -p /etc/cloudflared/
cat > /etc/cloudflared/config.yml << EOF
tunnel: ${tunnel_id}
credentials-file: /root/.cloudflared/${tunnel_id}.json
ingress:
- hostname: ${domain}
service: http://127.0.0.1:5678
- service: http_status:404
EOF
Creates a configuration file specifying the tunnel ID, credentials file location, and ingress rules to route traffic from our domain to n8n´s default port (5678
), with a fallback to a 404
status for unmatched requests.
CLOUDFLARE_TOKEN=$(gcloud secrets versions access latest --secret="${secret_id}")
cloudflared service install $CLOUDFLARE_TOKEN --config /etc/cloudflared/config.yml
Retrieves the Cloudflare token from Secret Manager and installs the tunnel as a service.
systemctl start cloudflared
systemctl enable cloudflared
systemctl start n8n
systemctl enable n8n
Ensures both n8n and the tunnel start automatically on boot.
Deployment Steps
Create the terraform/inputs.tfvars
file to store all our parameter values:
project_id = "<MY_PROJECT_ID>"
tunnel_id = "<MY_TUNNEL_ID>"
domain = "<MY_DOMAIN>"
cloudflare_token = "<MY_CLOUDFLARE_TOKEN>"
Run the following command to start the deployment:
gcloud infra-manager deployments apply n8n-deployment --location=us-central1 --local-source=./terraform --service-account=projects/<MY_PROJECT_ID> /serviceAccounts/<MY_SERVICE_ACCOUNY>@<MY_PROJECT_ID>x.iam.gserviceaccount.com --inputs-file=./terraform/inputs.tfvars
The deployment will finish in less than 1 minute, but the whole startup script might take around 45 minutes to complete due to the limited resources of our VM. We can track the progress by checking the VM logs:
Once it is completed, we can go to our domain and start setting up n8n:
If you're new to workflow automation or want complete control over your automation platform, this setup is an excellent starting point with minimal cost. You can find all the code here. Thanks, and happy coding.
Subscribe to my newsletter
Read articles from Raul Naupari directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Raul Naupari
Raul Naupari
Somebody who likes to code