Skip to content

Guide on how to fully self-host n8n in a GCP project with up to no monthly costs (depending on the workflows you might pay networking costs, see: [GCP Network Pricing](https://cloud.google.com/vpc/network-pricing)) as well as auto-update the Docker image whenever the open-source GitHub repo of n8n has another release.

Notifications You must be signed in to change notification settings

JimPresting/n8n-gcp-selfhost

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

27 Commits
 
 

Repository files navigation

Self-Hosting N8N on the Google Cloud with Auto-Updates

Guide on how to fully self-host n8n in a GCP project with up to no monthly costs (depending on the workflows you might pay networking costs, see: GCP Network Pricing) as well as auto-update the Docker image whenever the open-source GitHub repo of n8n has another release. The only two things you need to replicate this process 100% are a credit/debit card and a domain.

Step 1: Setting up the GCP

  1. Go to cloud.google.com and click on Console

  2. Click on Try for free Screenshotgcptrial

  3. You need to add a billig method to verify your identity.

  4. After you added your payment method and verified your identity you should click on Activate full account: youreinfreetrial --> This allows you to use the account after the 90-day trial period expires. --> Bear in mind that after the trial period ends or if the credits are used up, you will be charged on the provided payment method. However, you can limit this risk by setting up budget alerts. Check Google Cloud Budgets.

  5. Adding a New Project: If you are starting with a new Google Cloud account, it may take some time before you can create a new project. Alternatively, you can click on the settings of your existing "My First Project" and rename it for better association with your project. image

  6. Whichever way you are using it, when selecting your project in the top left, it should say, "You've activated your full account."

Step 2: Setting up the Cloud VM Instance

Now we set up the instance where N8N will run.

  1. Make sure your project is selected
  2. Click on VM Instances image
  3. It might ask you to enable the Compute Engine API first (if you have just set up the account). Click "Enable" to proceed. image
  4. Click on Create Instance
  5. In the configuration, you are generally free to set it up as you like. However, to host this instance for free, you need to check Google's requirements for the free-tier cloud setup: Google Cloud Free Tier.

As of now, the free-tier configuration is limited to:

  • 1 non-preemptible e2-micro VM instance per month in one of the following US regions:
    • Oregon: us-west1
    • Iowa: us-central1
    • South Carolina: us-east1
  • 30 GB-months of standard persistent disk
  • 1 GB of outbound data transfer from North America to all region destinations (excluding China and Australia) per month
  1. So, click on E2 and select the Preset. image Select e2-micro
  2. Click on OS and Storage, then select Change. image
  3. Change Size (GB) to 30 and the Boot disk type to Standard Persistent Disk as per the guidelines.
  4. It will show you a monthly estimate, as running multiple instances 24/7 would incur these costs for what you selected. However, since you have only one project, you will stay within the free-tier limits, and the only potential costs will be for bandwidth, depending on your workflows.
  5. Give the instance a name (it doesn’t really matter—just make sure it's written without spaces) and click Create. Wait a minite until the Status says that it has compelted the setup. If it takes longer, refresh the page. image
  6. Before setting up everything in the shell make sure to make the external IP static so that when an error occurs and you need to restart the instance it will still be pointing on your subdomain.
  • click on VPC Network, IP addresses. image
  • It will show two IP addresses: one internal and one external. For the external IP, click on the three dots and select "Promote to static IP address.". Name again doesn't matter. Screenshot 2025-02-15 114830

Lastly Select "Allow" on these 3 traffic sources. You can edit that later in the VM instance as well but we need it in order to reach our domain via our subdomain. image

Step 3: Setting up N8N

Now, go back to the VM instance we created and click on "Connect SSH." image Authorize with your Google Account (note that the connection may drop frequently). If that happens, just reconnect and reauthorize.
Depending on where you left off, you might need to reinstall or remove a partially installed instance. This happened to me quite often. In such cases, just ask ChatGPT how to uninstall the instance, and then you can restart the setup. Now enter the following commands after one another:

  1. Update the Package Index:
    sudo apt update
    
  2. Install Docker:
    sudo apt install docker.io

Click on Y

  1. Start Docker:
    sudo systemctl start docker
    
  2. Enable Docker to Start at Boot:
    sudo systemctl enable docker
    
    
    

Step 3.1: Setting up a Subdomain to point to your Google Cloud Instance

Now we want to add a subdomain of your domain which makes it easy to access your N8N instance from everywhere (dont worry you will need an account). With your domain provider go to Edit DNS settings (every domain provider has this) then you want to add a New Record.

copy the external IP address which we made static before: Screenshot 2025-02-15 120154

For the new record, select Type A and name it whatever you like, but keep it short and precise. Points to: Paste the external IP address. TTL: Default is 14400; you can leave it as is. image

Step 3.2: Starting n8n in Docker

Run the following command to start n8n in Docker. Replace your-domain.com with your actual domain name. Make sure you don’t copy and paste it with the "bash" part and the three backticks (```), or it won’t work.

We are using a subdomain, it should look like this: (The subdomain is what we defined as the name—in my example, myn8n.)

```bash
sudo docker run -d --restart unless-stopped -it \
  --name n8n \
  -p 5678:5678 \
  -e N8N_HOST="your-subdomain.your-domain.com" \
  -e WEBHOOK_TUNNEL_URL="https://your-subdomain.your-domain.com/" \
  -e WEBHOOK_URL="https://your-subdomain.your-domain.com/" \
  -e N8N_ENABLE_RAW_EXECUTION="true" \
  -e NODE_FUNCTION_ALLOW_BUILTIN="crypto" \
  -e NODE_FUNCTION_ALLOW_EXTERNAL="" \
  -e N8N_PUSH_BACKEND=websocket \
  #-e N8N_DEFAULT_BINARY_DATA_MODE="filesystem" \   # Needed when e.g. trying to upload Youtube Videos
  -v /home/your-google-account/.n8n:/home/node/.n8n \
  n8nio/n8n
```

It now downloads the latest n8n image. Since this is the first installation, it obviously can’t find n8n:latest in your directory, so that’s not a problem. image

Step 3.3: Installing Nginx

We need Nginx as a reverse proxy to route traffic to n8n, handle SSL encryption, and allow access via a custom domain. Without it, n8n would only be reachable through its internal port (5678), which is not ideal for public access. An alternative is using a Google Cloud Load Balancer, but it’s more complex and can incur additional costs. Nginx is lightweight, free, and gives full control over traffic and security. It simplifies setup while ensuring a secure and accessible deployment.

  1. Install Nginx:
    sudo apt install nginx
    

Click Y

  1. Configuring Nginx

Configure Nginx as a reverse proxy for the n8n web interface. This can be a bit tricky, so proceed carefully.

sudo mkdir -p /etc/nginx/sites-available /etc/nginx/sites-enabled

Now edit the config file.

sudo nano /etc/nginx/sites-available/n8n.conf

Paste the following content (replace with your actual domain and subdomain):

server {
    server_name your-subdomain.your-domain.com;
    location / {
        proxy_pass http://localhost:5678;
        proxy_http_version 1.1;
        chunked_transfer_encoding off;
        proxy_buffering off;
        proxy_cache off;
        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 https;
        proxy_read_timeout 86400;
    }
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/your-subdomain.your-domain.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/your-subdomain.your-domain.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
    if ($host = your-subdomain.your-domain.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot
    listen 80;
    server_name your-subdomain.your-domain.com;
    return 404; # managed by Certbot
}

Save with Ctrl + O, Enter, then exit with Ctrl + X.

sudo ln -s /etc/nginx/sites-available/n8n.conf /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx

If the sudo nginx -t test fails at this stage, it's because the Nginx configuration includes lines related to Certbot's SSL setup which hasn't run yet. You need to temporarily comment out these lines as shown below, run the test again, restart Nginx, and then proceed with Certbot.

server {
    server_name your-subdomain.your-domain.com; # Replace with your subdomain and domain

    location / {
        proxy_pass http://localhost:5678;
        proxy_http_version 1.1;
        chunked_transfer_encoding off;
        proxy_buffering off;
        proxy_cache off;
        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 https;
        proxy_read_timeout 86400;
    }

    # These sections are managed by Certbot and need to be commented out for the initial Nginx test
    #listen 443 ssl; # managed by Certbot
    #ssl_certificate /etc/letsencrypt/live/your-subdomain.your-domain.com/fullchain.pem; # managed by Certbot
    #ssl_certificate_key /etc/letsencrypt/live/your-subdomain.your-domain.com/privkey.pem; # managed by Certbot
    #include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    #ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}

server {
    # This redirect is managed by Certbot and needs to be commented out for the initial Nginx test
    #if ($host = your-subdomain.your-domain.com) { # Replace with your subdomain and domain
    #    return 301 https://$host$request_uri;
    #} # managed by Certbot

    listen 80;
    server_name your-subdomain.your-domain.com; # Replace with your subdomain and domain
    #return 404; # managed by Certbot - Also comment this out
}

Step 3.4: Setting up SSL with Certbot

Certbot will obtain and install an SSL certificate from Let's Encrypt.

  1. Install Certbot and the Nginx Plugin:
    sudo apt install certbot python3-certbot-nginx

Click Y

  1. Obtain an SSL Certificate:

Here, we need to configure the firewall settings to allow HTTP and HTTPS traffic. If you haven't done this before, you can easily add firewall rules globally for the project or edit the VM instance settings.

Adjust the subdomain and domain.

sudo certbot --nginx -d myn8n.your-domain.com

Enter an Email and select Y Second one you can enter Y or N doesn't matter. It should work. If an error occurs it's propably due to the Firewall settings not being set up correctly.

image

When entering your domain (with the subdomain) in the browser, it should look like this: image

Bear in mind that this has nothing to do with any n8n accounts you might already have. You are setting it up from scratch, and it will only work on this VM instance.

Step 3: Setting up Auto Updates for N8N

Since the official n8n repository regularly adds new features, it's important to stay updated without manually downloading, uploading workflows, or reconfiguring credentials. To automate this, we create a cronjob that checks for new stable releases (not pre-releases) in the n8n GitHub repository every Sunday night. If an update is available, it automatically updates the Docker image. Before updating, it saves your configurations in a new folder named update_n8n.

Bear in mind that the first part of your SSH prompt is your Google Account name, and the second part is the name of your VM instance.
For example, if your VM instance is called myvmn8n and your Google Account is johndoe@gmail.com, your SSH prompt will show:

johndoe@myvmn8n

image

After the updates execute it might show you errors: "Cannot GET /home " dont worry just dont let you browser auto-complete the URL. Enter subdomain.yourdomain.com then it will redirect you to the correct path.

Auto-Update Script for n8n

1. Create or Edit the Update Script

nano /home/mygoogleaccount/update_n8n.sh

Add the following content:

#!/bin/bash
# Backup current n8n directory
BACKUP_DATE=$(date +'%Y-%m-%d_%H-%M-%S')
cp -r /home/mygoogleaccount/.n8n /home/mygoogleaccount/.n8n-backup-$BACKUP_DATE

# Stop and remove old container
sudo docker stop n8n
sudo docker rm n8n

# Pull latest n8n version
sudo docker pull n8nio/n8n:latest

# Start new container with correct volume
sudo docker run -d --restart unless-stopped -it \
  --name n8n \
  -p 5678:5678 \
  -e N8N_HOST="myn8n.your-domain.com" \
  -e WEBHOOK_TUNNEL_URL="https://myn8n.your-domain.com/" \
  -e WEBHOOK_URL="https://myn8n.your-domain.com/" \
  -e N8N_ENABLE_RAW_EXECUTION="true" \
  -e NODE_FUNCTION_ALLOW_BUILTIN="crypto" \ # adding Javascript Package Crypto just to show how the packages would be added
  -e NODE_FUNCTION_ALLOW_EXTERNAL="" \ # needed for external 
  -e N8N_PUSH_BACKEND=websocket \
  -v /home/mygoogleaccount/.n8n:/home/node/.n8n \
  n8nio/n8n

# Clean up old Docker images
sudo docker image prune -af

Save with Ctrl + O, Enter, then exit with Ctrl + X.


2️⃣ Make the Script Executable

chmod +x /home/mygoogleaccount/update_n8n.sh

3. Set Up a Weekly Cronjob (Sunday at 3 AM)

Open the crontab:

sudo crontab -e

(to be 100% sure open both the "sudo crontab -e" and the "crontab -e" and enter the same commands twice) Select nano image

Add this line (you can remove the comments before):

0 3 * * 0 /bin/bash /home/mygoogleaccount/update_n8n.sh >> /var/log/update_n8n.log 2>&1
30 3 * * 0 sudo find /home/mygoogleaccount/.n8n-backup* -maxdepth 0 -type d | sort | head -n -2 | sudo xargs rm -rf
@reboot sudo chown -R 1000:1000 ~/.n8n && sudo chmod -R 777 ~/.n8n

Save and exit.

0 3 * * 0 means:

  • 0 → Minute (Runs at minute 0, i.e., the start of the hour)
  • 3 → Hour (Runs at 3 AM)
  • * → Day of the month (Runs every day of the month)
  • * → Month (Runs every month)
  • 0 → Day of the week (0 = Sunday, 1 = Monday, ..., 6 = Saturday)

This schedule runs the script every Sunday at 3:00 AM.

Regarding the Update file deletion (-maxdepth 0 -type d | sort | head -n -2 | xargs rm -rf):

  • find /home/mygoogleaccount/.n8n-backup* -maxdepth 0 -type d
    • find is the command to search for files
    • /home/mygoogleaccount/.n8n-backup* is the search pattern - it finds all directories that start with ".n8n-backup"
    • -maxdepth 0 means that only the directly specified directories are searched, not in subdirectories
    • -type d finds only directories, not regular files
  • | sort
    • The pipe (|) forwards the output of find to sort
    • sort arranges the list alphabetically, which for your backup names with dates is also chronological
    • e.g., ".n8n-backup-2025-02-15..." comes before ".n8n-backup-2025-03-09..."
  • | head -n -2
    • The pipe forwards the sorted list to head
    • head -n -2 takes all entries EXCEPT the last two
    • These last two are the newest backups (because of the previous sorting)
  • | xargs rm -rf
    • The pipe forwards the directory names to be deleted to xargs
    • xargs rm -rf executes the command rm -rf for each directory name
    • rm -rf deletes directories and all their contents recursively

4. Test & Verify

  • Run the script manually:

    /home/mygoogleaccount/update_n8n.sh

    Since we just installed N8N it should not find a newer version so it should look like this: image

  • Check backup directory:

    ls /home/mygoogleaccount/ | grep .n8n-backup
  • Verify Docker volume binding:

    docker inspect n8n | grep Mounts -A 10

    Expected output:

    "Source": "/home/mygoogleaccount/.n8n",
    "Destination": "/home/node/.n8n",

Summary

A backup of .n8n is created before each update.
The container restarts with the old data preserved.
The cronjob automates updates every Sunday at 3 AM.

Now, please make sure that when setting up your private n8n account, you watch out for the correct path the next time you use it. It should be .../home so that it doesn’t ask you to sign up again, as there is no login page from the signup screen. It may seem trivial, but if you don’t notice it, you might think your data is lost.

If the Cronjob does not work and it does not auto update enter:

sudo touch /var/log/update_n8n.log
sudo chmod 666 /var/log/update_n8n.log

this hands the log file the permissions it may need.

and change the Cronjob to:

0 3 * * 0 /bin/bash /home/stand_4_business/update_n8n.sh >> /var/log/update_n8n.log 2>&1

the "/bin/bash" tells him that he should execute it like that. Normally just entering the path to the file should work.

At worst case you can simply open the shell and enter it manually so it updates whenever you need it:

sudo bash /home/mygoogleaccount/update_n8n.sh

Hope this helps you set up and automate your n8n instance! 🚀 For more on how to effectively set up workflows that truly help you or your business be more efficient, check out our YouTube channel: StardawnAI. Thank you! 😊


Appendix: Additional Note

Fixing n8n 502 Bad Gateway after GCP VM Restart (if you changed your CPU/configs)

1️⃣ Fix Permissions

After restarting the VM, n8n couldn't access its config due to permission issues which leads to a 502 BAD GATEWAY. Fix it with:

sudo chown -R 1000:1000 ~/.n8n
sudo chmod -R 777 ~/.n8n

2️⃣ Restart n8n Container

sudo docker stop n8n
sudo docker rm n8n
sudo docker run -d --restart unless-stopped -it \
--name n8n \
-p 5678:5678 \
-e N8N_HOST="myn8n.my-domain.com" \
-e WEBHOOK_TUNNEL_URL="https://myn8n.my-domain.com/" \
-e WEBHOOK_URL="https://myn8n.my-domain.com/" \
-v ~/.n8n:/home/node/.n8n \
n8nio/n8n

3 Verify n8n is Running

sudo docker ps
  • docker ps should show Up X minutes
  • curl should return HTTP/1.1 200 OK or 403 Forbidden

4 Final Check

Open in browser:

https://myn8n.my-domain.com

Screenshot 2025-02-18 104846

crontab -e

Add the following line at the end to fix n8n folder permissions on startup:

@reboot sudo chown -R 1000:1000 ~/.n8n && sudo chmod -R 777 ~/.n8n

This ensures n8n always has full access to its config directory after a reboot.

Screenshot 2025-02-18 111733

About

Guide on how to fully self-host n8n in a GCP project with up to no monthly costs (depending on the workflows you might pay networking costs, see: [GCP Network Pricing](https://cloud.google.com/vpc/network-pricing)) as well as auto-update the Docker image whenever the open-source GitHub repo of n8n has another release.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published