Tools
Tools: How to Deploy n8n on Google Cloud for Free (Forever)
2026-03-05
0 views
admin
What Is n8n and Why Host It Yourself? ## What You'll Need ## Why Google Cloud Free Tier Works for n8n ## Step 1 — Create the GCP VM ## Step 2 — Install Docker ## Step 3 — Set Up Neon PostgreSQL (Free Database) ## Step 4 — Deploy n8n with Docker Compose ## Step 5 — Set Up Nginx Reverse Proxy ## Step 6 — Open Firewall Ports and Add SSL ## Step 7 — Connect Your Domain ## Step 8 — Optimize Performance (Swap Space) ## Step 9 — Set Up Automatic GitHub Backups ## How to Update n8n in One Command ## How to Migrate from an Existing n8n Instance ## Frequently Asked Questions ## Summary — What You've Built Run n8n workflow automation 100% free on Google Cloud using a permanent free-tier e2-micro VM, Neon PostgreSQL, and Nginx with SSL. No credit card charges, no expiry — ever. n8n is one of the most powerful open-source workflow automation tools available today. Think Zapier or Make — but self-hosted, with no per-task pricing and no artificial limits on workflows. The problem? Most people pay €8–20/month to host it on Railway, Render, or a VPS. This guide shows you exactly how to run n8n on Google Cloud Platform's Always Free tier at zero cost, forever. Google Cloud's Always Free tier includes a permanently free e2-micro VM. Unlike AWS Free Tier which expires after 12 months, GCP's Always Free resources never expire. Here's what's included free forever: The e2-micro has 1 shared vCPU and 1GB RAM. With swap space added, this handles n8n comfortably for personal use and small teams running up to 150–200 workflows per day. Note: GCP will show an estimated cost of ~$7/month in the billing console. This is normal — the Always Free credit is applied automatically and your actual invoice will be $0.00. Run this command in your terminal (with gcloud CLI installed and authenticated): Why these specific settings matter: Press Enter twice when asked for a passphrase to generate SSH keys automatically. n8n requires a PostgreSQL database. We'll use Neon's free tier instead of running a local Postgres container, which saves precious RAM on the e2-micro VM. Go to neon.tech and create a free account. Then: In the Neon dashboard, configure compute settings: This keeps you well within Neon's 100 compute unit-hours/month free limit. Your connection string will look like: Paste this configuration (replace with your actual Neon credentials): Save with Ctrl+X → Y → Enter, then start n8n: The first run downloads the n8n image (~280MB) which takes 5–7 minutes. Important: EXECUTIONS_DATA_PRUNE=true keeps the database lean by deleting execution history older than 168 hours (7 days). This is critical for staying within Neon's 500MB free storage limit. N8N_ENCRYPTION_KEY encrypts your saved credentials — set this to a random 32-character string and keep it safe. Install Nginx and Certbot: Create the n8n Nginx config: Run these on your local machine (not the server): Then on the server, get your free SSL certificate: Certbot automatically configures Nginx for HTTPS and sets up auto-renewal every 90 days. Add a DNS A record at your domain registrar or Cloudflare: If using Cloudflare, set proxy to DNS only (grey cloud) initially. After SSL is working, switch to orange cloud with SSL/TLS mode set to Full. The e2-micro only has 1GB RAM. Adding swap makes a huge difference: This gives your server an effective 3GB of memory using free disk space. It's the single biggest performance improvement you can make on this setup. Don't lose your workflows. Set up a monthly automated backup to GitHub. First, create a GitHub repo and a fine-grained personal access token with Contents: Read and Write permission. Set up git on the server: Add this line (runs at 2am on the 1st of every month): For a manual backup anytime: Run this monthly to stay current with security patches and new features. On your old instance, export everything: Copy your old N8N_ENCRYPTION_KEY to your new instance's docker-compose.yml — this ensures credentials decrypt correctly on the new server. Then import: Will Google ever charge me?
As long as you use one e2-micro VM with a 30GB pd-standard disk in an eligible region, Google will not charge you. The Always Free tier does not expire. Is 1GB RAM enough for n8n?
Yes, for personal use and small teams. With 2GB swap added, you get an effective 3GB. n8n at idle uses 400–600MB RAM. Running 2–3 workflows simultaneously is comfortable. Is Neon's 500MB storage enough?
Yes. With execution history pruning enabled, a typical personal n8n instance stays well under 100MB. You'd need hundreds of thousands of workflow runs to approach the limit. Can I use this commercially?
n8n's self-hosted version is free for personal and small-team use under the Sustainable Use License. GCP's free tier has no restrictions on what you run on it. What if I need more power later?
Upgrade the GCP VM to e2-small or e2-medium (paid, ~$15–30/month) while keeping everything else the same. No migration needed — just change the machine type in GCP console. You're saving €8–20/month compared to managed n8n hosting — that's up to €240/year back in your pocket, running the exact same software. Found this guide helpful? Share it with other n8n users who are tired of paying for hosting they don't need. Connect with me https://x.com/DesiRichDev/
Check My Projects https://dev.businesskit.io/ Templates let you quickly answer FAQs or store snippets for re-use. Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse CODE_BLOCK:
gcloud compute instances create n8n-server \ --machine-type=e2-micro \ --zone=us-east1-b \ --image-family=ubuntu-2204-lts \ --image-project=ubuntu-os-cloud \ --boot-disk-size=30GB \ --boot-disk-type=pd-standard \ --tags=http-server,https-server Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
gcloud compute instances create n8n-server \ --machine-type=e2-micro \ --zone=us-east1-b \ --image-family=ubuntu-2204-lts \ --image-project=ubuntu-os-cloud \ --boot-disk-size=30GB \ --boot-disk-type=pd-standard \ --tags=http-server,https-server CODE_BLOCK:
gcloud compute instances create n8n-server \ --machine-type=e2-micro \ --zone=us-east1-b \ --image-family=ubuntu-2204-lts \ --image-project=ubuntu-os-cloud \ --boot-disk-size=30GB \ --boot-disk-type=pd-standard \ --tags=http-server,https-server CODE_BLOCK:
gcloud compute ssh n8n-server --zone=us-east1-b Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
gcloud compute ssh n8n-server --zone=us-east1-b CODE_BLOCK:
gcloud compute ssh n8n-server --zone=us-east1-b COMMAND_BLOCK:
sudo apt update && sudo apt upgrade -y
curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker $USER && newgrp docker
docker --version Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
sudo apt update && sudo apt upgrade -y
curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker $USER && newgrp docker
docker --version COMMAND_BLOCK:
sudo apt update && sudo apt upgrade -y
curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker $USER && newgrp docker
docker --version CODE_BLOCK:
postgresql://user:[email protected]/neondb?sslmode=require Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
postgresql://user:[email protected]/neondb?sslmode=require CODE_BLOCK:
postgresql://user:[email protected]/neondb?sslmode=require CODE_BLOCK:
mkdir n8n && cd n8n
nano docker-compose.yml Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
mkdir n8n && cd n8n
nano docker-compose.yml CODE_BLOCK:
mkdir n8n && cd n8n
nano docker-compose.yml CODE_BLOCK:
services: n8n: image: n8nio/n8n restart: always ports: - "5678:5678" environment: - DB_TYPE=postgresdb - DB_POSTGRESDB_HOST=ep-xxxx.us-east-1.aws.neon.tech - DB_POSTGRESDB_PORT=5432 - DB_POSTGRESDB_DATABASE=neondb - DB_POSTGRESDB_USER=your_user - DB_POSTGRESDB_PASSWORD=your_password - DB_POSTGRESDB_SSL_REJECT_UNAUTHORIZED=false - N8N_HOST=n8n.yourdomain.com - N8N_PORT=5678 - N8N_PROTOCOL=https - N8N_ENCRYPTION_KEY=your_32_char_random_key - EXECUTIONS_DATA_PRUNE=true - EXECUTIONS_DATA_MAX_AGE=168 volumes: - n8n_data:/home/node/.n8n volumes: n8n_data: Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
services: n8n: image: n8nio/n8n restart: always ports: - "5678:5678" environment: - DB_TYPE=postgresdb - DB_POSTGRESDB_HOST=ep-xxxx.us-east-1.aws.neon.tech - DB_POSTGRESDB_PORT=5432 - DB_POSTGRESDB_DATABASE=neondb - DB_POSTGRESDB_USER=your_user - DB_POSTGRESDB_PASSWORD=your_password - DB_POSTGRESDB_SSL_REJECT_UNAUTHORIZED=false - N8N_HOST=n8n.yourdomain.com - N8N_PORT=5678 - N8N_PROTOCOL=https - N8N_ENCRYPTION_KEY=your_32_char_random_key - EXECUTIONS_DATA_PRUNE=true - EXECUTIONS_DATA_MAX_AGE=168 volumes: - n8n_data:/home/node/.n8n volumes: n8n_data: CODE_BLOCK:
services: n8n: image: n8nio/n8n restart: always ports: - "5678:5678" environment: - DB_TYPE=postgresdb - DB_POSTGRESDB_HOST=ep-xxxx.us-east-1.aws.neon.tech - DB_POSTGRESDB_PORT=5432 - DB_POSTGRESDB_DATABASE=neondb - DB_POSTGRESDB_USER=your_user - DB_POSTGRESDB_PASSWORD=your_password - DB_POSTGRESDB_SSL_REJECT_UNAUTHORIZED=false - N8N_HOST=n8n.yourdomain.com - N8N_PORT=5678 - N8N_PROTOCOL=https - N8N_ENCRYPTION_KEY=your_32_char_random_key - EXECUTIONS_DATA_PRUNE=true - EXECUTIONS_DATA_MAX_AGE=168 volumes: - n8n_data:/home/node/.n8n volumes: n8n_data: COMMAND_BLOCK:
docker compose up -d Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
docker compose up -d COMMAND_BLOCK:
docker compose up -d COMMAND_BLOCK:
sudo apt install nginx certbot python3-certbot-nginx -y Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
sudo apt install nginx certbot python3-certbot-nginx -y COMMAND_BLOCK:
sudo apt install nginx certbot python3-certbot-nginx -y COMMAND_BLOCK:
sudo nano /etc/nginx/sites-available/n8n Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
sudo nano /etc/nginx/sites-available/n8n COMMAND_BLOCK:
sudo nano /etc/nginx/sites-available/n8n CODE_BLOCK:
server { listen 80; server_name n8n.yourdomain.com; return 301 https://$host$request_uri;
} server { listen 443 ssl; server_name n8n.yourdomain.com; ssl_certificate /etc/letsencrypt/live/n8n.yourdomain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/n8n.yourdomain.com/privkey.pem; location / { proxy_pass http://localhost:5678; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; chunked_transfer_encoding off; }
} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
server { listen 80; server_name n8n.yourdomain.com; return 301 https://$host$request_uri;
} server { listen 443 ssl; server_name n8n.yourdomain.com; ssl_certificate /etc/letsencrypt/live/n8n.yourdomain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/n8n.yourdomain.com/privkey.pem; location / { proxy_pass http://localhost:5678; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; chunked_transfer_encoding off; }
} CODE_BLOCK:
server { listen 80; server_name n8n.yourdomain.com; return 301 https://$host$request_uri;
} server { listen 443 ssl; server_name n8n.yourdomain.com; ssl_certificate /etc/letsencrypt/live/n8n.yourdomain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/n8n.yourdomain.com/privkey.pem; location / { proxy_pass http://localhost:5678; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; chunked_transfer_encoding off; }
} COMMAND_BLOCK:
sudo ln -s /etc/nginx/sites-available/n8n /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl restart nginx Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
sudo ln -s /etc/nginx/sites-available/n8n /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl restart nginx COMMAND_BLOCK:
sudo ln -s /etc/nginx/sites-available/n8n /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl restart nginx CODE_BLOCK:
gcloud compute firewall-rules create allow-http \ --allow tcp:80 --target-tags http-server gcloud compute firewall-rules create allow-https \ --allow tcp:443 --target-tags https-server Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
gcloud compute firewall-rules create allow-http \ --allow tcp:80 --target-tags http-server gcloud compute firewall-rules create allow-https \ --allow tcp:443 --target-tags https-server CODE_BLOCK:
gcloud compute firewall-rules create allow-http \ --allow tcp:80 --target-tags http-server gcloud compute firewall-rules create allow-https \ --allow tcp:443 --target-tags https-server COMMAND_BLOCK:
sudo certbot --nginx -d n8n.yourdomain.com Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
sudo certbot --nginx -d n8n.yourdomain.com COMMAND_BLOCK:
sudo certbot --nginx -d n8n.yourdomain.com COMMAND_BLOCK:
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab COMMAND_BLOCK:
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab CODE_BLOCK:
mkdir -p ~/backup && cd ~/backup
git init
git remote add origin https://YOUR_USERNAME:[email protected]/YOUR_USERNAME/n8n-backup.git
git pull origin main Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
mkdir -p ~/backup && cd ~/backup
git init
git remote add origin https://YOUR_USERNAME:[email protected]/YOUR_USERNAME/n8n-backup.git
git pull origin main CODE_BLOCK:
mkdir -p ~/backup && cd ~/backup
git init
git remote add origin https://YOUR_USERNAME:[email protected]/YOUR_USERNAME/n8n-backup.git
git pull origin main CODE_BLOCK:
crontab -e Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
0 2 1 * * docker exec n8n-n8n-1 n8n export:workflow --backup --output /home/node/.n8n/backup/workflows/ && docker exec n8n-n8n-1 n8n export:credentials --backup --output /home/node/.n8n/backup/credentials/ && docker cp n8n-n8n-1:/home/node/.n8n/backup /home/YOUR_USER/backup/ && git -C /home/YOUR_USER/backup add . && git -C /home/YOUR_USER/backup commit -m "Auto backup $(date +%F)" && git -C /home/YOUR_USER/backup push Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
0 2 1 * * docker exec n8n-n8n-1 n8n export:workflow --backup --output /home/node/.n8n/backup/workflows/ && docker exec n8n-n8n-1 n8n export:credentials --backup --output /home/node/.n8n/backup/credentials/ && docker cp n8n-n8n-1:/home/node/.n8n/backup /home/YOUR_USER/backup/ && git -C /home/YOUR_USER/backup add . && git -C /home/YOUR_USER/backup commit -m "Auto backup $(date +%F)" && git -C /home/YOUR_USER/backup push CODE_BLOCK:
0 2 1 * * docker exec n8n-n8n-1 n8n export:workflow --backup --output /home/node/.n8n/backup/workflows/ && docker exec n8n-n8n-1 n8n export:credentials --backup --output /home/node/.n8n/backup/credentials/ && docker cp n8n-n8n-1:/home/node/.n8n/backup /home/YOUR_USER/backup/ && git -C /home/YOUR_USER/backup add . && git -C /home/YOUR_USER/backup commit -m "Auto backup $(date +%F)" && git -C /home/YOUR_USER/backup push COMMAND_BLOCK:
docker exec n8n-n8n-1 n8n export:workflow --backup --output /home/node/.n8n/backup/workflows/ && git -C ~/backup add . && git -C ~/backup commit -m "Manual backup $(date +%F)" && git -C ~/backup push Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
docker exec n8n-n8n-1 n8n export:workflow --backup --output /home/node/.n8n/backup/workflows/ && git -C ~/backup add . && git -C ~/backup commit -m "Manual backup $(date +%F)" && git -C ~/backup push COMMAND_BLOCK:
docker exec n8n-n8n-1 n8n export:workflow --backup --output /home/node/.n8n/backup/workflows/ && git -C ~/backup add . && git -C ~/backup commit -m "Manual backup $(date +%F)" && git -C ~/backup push CODE_BLOCK:
cd ~/n8n && docker compose pull && docker compose up -d Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
cd ~/n8n && docker compose pull && docker compose up -d CODE_BLOCK:
cd ~/n8n && docker compose pull && docker compose up -d COMMAND_BLOCK:
docker exec YOUR_OLD_CONTAINER n8n export:workflow --backup --output /home/node/.n8n/backup/workflows/
docker exec YOUR_OLD_CONTAINER n8n export:credentials --backup --output /home/node/.n8n/backup/credentials/ Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
docker exec YOUR_OLD_CONTAINER n8n export:workflow --backup --output /home/node/.n8n/backup/workflows/
docker exec YOUR_OLD_CONTAINER n8n export:credentials --backup --output /home/node/.n8n/backup/credentials/ COMMAND_BLOCK:
docker exec YOUR_OLD_CONTAINER n8n export:workflow --backup --output /home/node/.n8n/backup/workflows/
docker exec YOUR_OLD_CONTAINER n8n export:credentials --backup --output /home/node/.n8n/backup/credentials/ COMMAND_BLOCK:
docker exec n8n-n8n-1 n8n import:workflow --separate --input=/path/to/workflows/
docker exec n8n-n8n-1 n8n import:credentials --separate --input=/path/to/credentials/ Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
docker exec n8n-n8n-1 n8n import:workflow --separate --input=/path/to/workflows/
docker exec n8n-n8n-1 n8n import:credentials --separate --input=/path/to/credentials/ COMMAND_BLOCK:
docker exec n8n-n8n-1 n8n import:workflow --separate --input=/path/to/workflows/
docker exec n8n-n8n-1 n8n import:credentials --separate --input=/path/to/credentials/ - A Google Cloud account (credit card required for verification, but you will NOT be charged)
- A domain name (e.g., n8n.yourdomain.com)
- A Neon account — free at neon.tech, no credit card needed
- A GitHub account — for automated workflow backups
- Google Cloud CLI (gcloud) installed on your local machine - 1 e2-micro VM in us-east1, us-central1, or us-west1
- 30 GB standard persistent disk (pd-standard)
- 1 GB egress per month to North America
- Free external IP on the e2-micro instance - us-east1-b — One of three regions eligible for Always Free
- pd-standard — Must specify standard disk, not pd-balanced (which is NOT free)
- 30GB — Use the full free allowance
- tags — Required for firewall rules later - Create a new project
- Select AWS us-east-1 region (closest to GCP us-east1)
- Copy your direct connection string - Set compute size to 0.25 CU (minimum)
- Set Scale to zero: 5 minutes so Neon sleeps when n8n is idle
how-totutorialguidedev.toaimlubuntuservercrondnsfirewallswitchpostgresqlnginxdocker