How to Host n8n for Free on Google Cloud Platform

Raul NaupariRaul Naupari
5 min read

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:

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. The auto 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.

0
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