Back to Blog
☁️ Automation

Self-Host n8n on Google Cloud — The One-Go Working Flow

A single clean flow, copy-paste done. Docker + Nginx + Certbot on Google Cloud free tier, using a Docker-managed volume so 502s and permission crashes never happen in the first place.

Oct 5, 202510 min readBy Eugene Samuel

You don't need another theory-heavy guide — you need a single clean flow that just works if followed once, start to finish. Below is exactly that: no branching, no confusion, every command verbatim.

StackUbuntu 22.04Docker ComposeNginxCertbot / Let's EncryptGoogle Cloud free tier

End result: https://n8n.eugenesamuel.uno loading the n8n owner-setup screen over real HTTPS — in about 15 minutes.

01
Step 1

Create the VM (Google Cloud)

Go to Compute Engine → Create Instance and use:

  • Name: n8n
  • OS: Ubuntu 22.04 LTS
  • Machine type: e2-micro (free tier)

Tick:

  • ✅ Allow HTTP traffic
  • ✅ Allow HTTPS traffic

Click Create. Wait 1–2 minutes for the VM to boot.

02
Step 2

Connect & prepare

Click SSH from the VM list to open a browser terminal, then run:

bash — update & install tools
sudo apt update && sudo apt upgrade -y
sudo apt install -y ca-certificates curl gnupg nano
03
Step 3

Install Docker

Add Docker's GPG key:

bash — Docker GPG key
sudo install -m 0755 -d /etc/apt/keyrings

curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
| sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

sudo chmod a+r /etc/apt/keyrings/docker.gpg

Add the Docker apt repo:

bash — Docker repo
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" \
| sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Install Docker + Compose plugin:

bash — install Docker
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Enable and start the service:

bash — start Docker
sudo systemctl enable docker
sudo systemctl start docker
bash — fix permissions
sudo usermod -aG docker $USER
newgrp docker

Test (should NOT show a permission error):

bash — test
docker ps
04
Step 4

Set up n8n (the most important part)

bash — create project dir
mkdir ~/n8n
cd ~/n8n
nano docker-compose.yml

Paste exactly this into Nano. Notice the n8n_data named volume at the bottom — this is Docker-managed storage, which is why you never need to chown anything and 502 errors never appear:

docker-compose.yml
services:
  n8n:
    image: n8nio/n8n
    restart: always
    ports:
      - "5678:5678"
    environment:
      - N8N_HOST=n8n.eugenesamuel.uno
      - N8N_PORT=5678
      - WEBHOOK_URL=https://n8n.eugenesamuel.uno/
      - GENERIC_TIMEZONE=Asia/Kolkata
    volumes:
      - n8n_data:/home/node/.n8n

volumes:
  n8n_data:

Save: Ctrl + XYEnter

05
Step 5

Start n8n

bash — launch
docker compose up -d

Wait 20 seconds, then check:

bash — verify container
docker ps

The STATUS column must show Up 20 seconds (and growing). Now smoke-test from the VM itself:

bash — local curl test
curl http://localhost:5678

You should get back HTML (the n8n login/setup page source). If you do, the container is healthy — we just need to put Nginx + HTTPS in front.

06
Step 6

Domain setup

In your domain DNS, add:

TypeNameValue
An8nYOUR_VM_IP

Wait 2–5 minutes for DNS to propagate.

07
Step 7

Install Nginx

bash — install + remove default
sudo apt install -y nginx
sudo rm /etc/nginx/sites-enabled/default
08
Step 8

Configure Nginx

bash — open config
sudo nano /etc/nginx/sites-available/n8n

Paste:

/etc/nginx/sites-available/n8n
server {
    listen 80;
    server_name n8n.eugenesamuel.uno;

    location / {
        proxy_pass http://127.0.0.1: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;
    }
}

Save (Ctrl + XYEnter). Enable and reload:

bash — enable site
sudo ln -s /etc/nginx/sites-available/n8n /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx
09
Step 9

HTTPS (final)

bash — Certbot
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d n8n.eugenesamuel.uno

When prompted, choose Redirect to HTTPS. Certbot writes the TLS block + 80→443 redirect into your Nginx config automatically.

🎉 Done

Open:

browser
https://n8n.eugenesamuel.uno

The n8n owner-setup screen loads over real HTTPS. Create your account and you're in.

Rules — do NOT do these again

  • ❌ Don'tuse a ~/.n8n bind-mount volume
  • ❌ Don'tadd N8N_PROTOCOL=https (Nginx terminates TLS, not n8n)
  • ❌ Don'trun docker without newgrp docker first
  • ❌ Don'tskip the Docker restart after changing compose
  • ❌ Don'tmix HTTP and HTTPS inside the container

Already have a broken install? Clean reset

If you followed an older guide that used ~/.n8n as a bind-mount and are now stuck in a 502 / crash-loop, this is the safe reset path. From the ~/n8n folder:

bash — stop & wipe the broken state
cd ~/n8n
docker compose down
sudo rm -rf ~/.n8n

Then edit docker-compose.yml to match Step 4 above (named volume, no N8N_PROTOCOL). Start fresh:

bash — start fresh
docker compose up -d

Re-test locally, then bounce Nginx so it picks up the healthy upstream:

bash — local test + Nginx restart
curl http://localhost:5678
sudo systemctl restart nginx

Open https://n8n.eugenesamuel.uno — 502 is gone.

✅ Final result

  • Docker n8n running
  • Domain connected
  • HTTPS working
  • No 502
  • No permission errors

If anything breaks (rare now)

Paste the output of these two commands:

bash — diagnostics
docker ps
docker logs n8n-n8n-1 --tail=30

…and I'll fix it. Or, if you want to skip the surgery entirely, I'll set this up for you end-to-end — VM, domain, SSL, monitoring — in one sitting.