Install n8n locally using Cloudflare

Install n8n locally using Cloudflare

Russ McKendrick Russ McKendrick | | 11 min read | Suggest Changes

I finally got around to getting a small AMD Ryzen 7 Mini PC with 32GB of RAM to use as part of my home lab to replace some aging Raspberry Pis.

While it came with Windows 11 (which i am sure was fine and not dodgy in any way) I instead opted to run the server version of Ubuntu 24.04 LTS and immediately trashed the Windows install. Given everyone is making videos about running n8n on VPS servers I decided to do the same and run it locally on my new machine.

Installing Docker

As I was running a fresh Ubuntu 24.04 install I needed to install Docker before I could run n8n locally, To do this I first needed to install the prerequisites and then setup the official Docker repository:

Installing the prerequisites and setting up the Docker repository
sudo apt update
sudo apt install apt-transport-https ca-certificates curl software-properties-common -y
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update

Once the repository is setup I could install Docker itself and configure it to run as the current user:

Installing Docker
sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin -y
sudo usermod -aG docker $USER
newgrp docker

Finally, I checked the Docker version to ensure it was installed correctly:

Checking the Docker version
docker --version
Docker version 28.5.0, build 887030f

With that done I could start to install n8n locally.

Preparing the environment

As I will be running a few different services locally on the same machine I decided to use Docker Compose and keep all of the services needed for n8n in one file. We will be running the following containers:

Setting up Cloudflare Tunnel

I host all of my domains via Cloudflare (as well as this blog) so using their Tunnel service for routing the traffic to my local n8n instance was a no-brainer.

To do this signup for their Zero Trust service, using the free tier is fine, once you have signed up you need to create a new tunnel, you can this by going Network > Tunnels > Create a Tunnel.

Create a Tunnel

On the Select your tunnel type screen select Cloudflare. Next you will be asked to name the tunnel, in the screens below I have called mine n8nBlogPost.

Name the Tunnel

Next you will be taken to the Install and run connectors screen, here select Docker, copy and page the command you get given as this contains the --token parameter you will need to use later the command will look something like this:

Copying the Cloudflare Tunnel token
docker run cloudflare/cloudflared:latest tunnel \
--no-autoupdate run \
--token eyJhIjoiMzQwODksoTHingRealyLong5YzNotaR4alTok3N
Install and run connectors

We won’t be bringing the tunnel up here, we will do that later when we setup the Docker Compose file so just move onto the next screen.

Here, we will be setting up the domain and ports for the tunnel, in the screens below I have called mine n8n.domain.com and have used the service we will be tunnelling to:

Set the domain and Service

As you can see from the screenshot above I have set the Hostname as n8n.wibble.foo (Yes wibble.foo is a real domain I own) and as we will be proxying to our local n8n instance on port 5678 I set the type to HTTP and URL as n8n:5678.

Once setup we can click on Complete setup and you will be taken back to the Cloudflare Tunnel screen where you will see your new tunnel listed, as we haven’t brought up the connector you will see it as INACTIVE, don’t worry about this yet.

Setting the folders and .env file

First we need to generate a secure random key for which will be used for encryption, you can do this by running the following command:

Generating a secure random key for encryption
openssl rand -hex 32

Make a note of the random key and we can move on to creating the folders and setting the permissions:

Setting the folders
sudo mkdir -p /opt/n8n/local-files
sudo chown -R $USER:$USER /opt/n8n
sudo chown -R 1000:1000 /opt/n8n/local-files
cd /opt/n8n/
vi /opt/n8n/.env

Inside the .env file we need to set the following variables (make sure you use your own values):

Environment variables
# Domain Configuration
PUBLIC_DOMAIN=n8n.domain.com
# PostgreSQL Configuration
POSTGRES_USER=root
POSTGRES_PASSWORD=some-secure-password-here
POSTGRES_DB=n8n
POSTGRES_NON_ROOT_USER=n8n
POSTGRES_NON_ROOT_PASSWORD=some-secure-password-here
# Timezone
GENERIC_TIMEZONE=Europe/London
# n8n Configuration
# IMPORTANT: Generate a secure random key for encryption
# Use: openssl rand -hex 32
N8N_ENCRYPTION_KEY=random-key-here
# Cloudflare Tunnel Token (get from Cloudflare dashboard)
CLOUDFLARE_TUNNEL_TOKEN=your-cloudflare-tunnel-token

Enter the values you generated for the encryption key, set some passwords for the PostgreSQL database and add the Cloudflare Tunnel Token we grabbed earlier (make sure the domain matches the one you set up in Cloudflare) and save the file.

Download the Database setup script

Next we need to create a script to setup the database:

Creating the database setup script
curl -L https://raw.githubusercontent.com/russmckendrick/local-n8n-with-cloudflare/refs/heads/main/init-data.sh > /opt/n8n/init-data.sh

This will download the script from my local-n8n-with-cloudflare GitHub repository.

Setup Docker Compose file

Next we need to create a Docker Compose file:

Creating the Docker Compose file
curl -L https://raw.githubusercontent.com/russmckendrick/local-n8n-with-cloudflare/refs/heads/main/docker-compose.yml > /opt/n8n/docker-compose.yml

This will download the following file:

Docker Compose file
volumes:
db_storage:
driver: local
n8n_data:
driver: local
networks:
backend:
driver: bridge
cloudflare:
driver: bridge
services:
postgres:
image: postgres:16
restart: unless-stopped
networks:
- backend
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_NON_ROOT_USER: ${POSTGRES_NON_ROOT_USER}
POSTGRES_NON_ROOT_PASSWORD: ${POSTGRES_NON_ROOT_PASSWORD}
volumes:
- db_storage:/var/lib/postgresql/data
- ./init-data.sh:/docker-entrypoint-initdb.d/init-data.sh
healthcheck:
test: ['CMD-SHELL', 'pg_isready -h localhost -U ${POSTGRES_USER} -d ${POSTGRES_DB}']
interval: 10s
timeout: 5s
retries: 5
start_period: 10s
n8n:
image: docker.n8n.io/n8nio/n8n
container_name: n8n
restart: unless-stopped
networks:
- backend
- cloudflare
environment:
DB_TYPE: postgresdb
DB_POSTGRESDB_HOST: postgres
DB_POSTGRESDB_PORT: 5432
DB_POSTGRESDB_DATABASE: ${POSTGRES_DB}
DB_POSTGRESDB_USER: ${POSTGRES_NON_ROOT_USER}
DB_POSTGRESDB_PASSWORD: ${POSTGRES_NON_ROOT_PASSWORD}
EXECUTIONS_MODE: regular
N8N_HOST: ${PUBLIC_DOMAIN}
N8N_PROTOCOL: https
WEBHOOK_URL: https://${PUBLIC_DOMAIN}
GENERIC_TIMEZONE: ${GENERIC_TIMEZONE}
TZ: ${GENERIC_TIMEZONE}
N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY}
N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS: true
volumes:
- n8n_data:/home/node/.n8n
- ./local-files:/files
depends_on:
postgres:
condition: service_healthy
healthcheck:
test: ['CMD-SHELL', 'wget --spider -q http://localhost:5678/healthz || exit 1']
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
cloudflared:
image: cloudflare/cloudflared:latest
container_name: cloudflared
restart: unless-stopped
networks:
- cloudflare
command: tunnel --no-autoupdate run --token ${CLOUDFLARE_TUNNEL_TOKEN}
depends_on:
- n8n

Bringing up the n8n containers

We now have everything in place to bring up the containers, to do this run the following command:

Bringing up the containers
docker compose -f /opt/n8n/docker-compose.yml pull

This will pull the images for the containers, next we can bring them up:

Bringing up the containers
docker compose -f /opt/n8n/docker-compose.yml up -d

This should give you the following output:

Bringing up the containers
[+] Running 5/5
Volume n8n_n8n_data Created 0.1s
Volume n8n_db_storage Created 0.0s
Container n8n-postgres-1 Healthy 5.8s
Container n8n Started 5.9s
Container cloudflared Started 6.0s

Once the containers are up and running we can check the logs to ensure everything is working correctly:

Checking the logs
docker compose -f /opt/n8n/docker-compose.yml logs -f

You should see something like the following:

Logs
n8n |
n8n | [license SDK] Skipping renewal on init: license cert is not initialized
n8n | [Data table] The Data table module is experimental and subject to change.
n8n | Any tables added before the official release may become inaccessible at any point. Use at your own risk.
n8n | Version: 1.113.3
n8n |
n8n | Editor is now accessible via:
n8n | https://n8n.wibble.foo

If you open your browser and navigate your domain, for example https://n8n.wibble.foo you should see the n8n editor, if you click on the Sign in button you should be taken to the login screen, enter the credentials you set up in the .env file and you should be logged in.

That’s it, you now have a fully working n8n instance running locally and accessible via Cloudflare Tunnel. Install the free license, grab a coffee and get started with n8n - but thats another post.

Housekeeping

If you need to update the n8n instance you can do so by running the following command:

Updating the n8n instance
docker compose -f /opt/n8n/docker-compose.yml down
docker compose -f /opt/n8n/docker-compose.yml pull
docker compose -f /opt/n8n/docker-compose.yml up -d

This will stop the current instance, pull the latest images and bring the containers back up.

If you need to remove the instance you can do so by running the following command:

Removing the n8n instance
docker compose -f /opt/n8n/docker-compose.yml down

This will remove the containers and networks, to remove the volumes you can run the following command:

Removing the volumes
docker volume rm n8n_db_storage n8n_n8n_data

Making it a little more secure

Given that we are running the n8n instance on a local resource, and the tunnel is exposing it to the internet, we can make it a little more secure by fronting the site with a Cloudflare Zero Trust login. This will prevent anyone from accessing the n8n instance without being validated via Cloudflare.

To do this go to the Cloudflare dashboard and navigate to Zero Trust > Access > Applications > Add an Application; the first screen will ask you to select the application type, select Self hosted and click on Next.

Create Application

Next give your application a name, in the screens below I have called mine n8nBlogPost, then in the public hostname section enter the URL of your n8n instance, in the screens below I have entered n8n.wibble.foo:

Configure Application

Now we need to add a policy to the application, click on + Create new policy where you will be taken to the Add policy screen, here enter a name for the policy, I have called mine n8nBlogPostPolicy. Then scroll down to the Add rules section, by default there will an Include rule waiting to be added, in the Selector select Emails ending in and enter the domain name of your email provider, in my example I have entered wibble.email. Now click on + Add require, in the Selector this time select Country and enter the country(s) you want to allow access from, in my example I have entered United Kingdom and click on Next.

Add a policy

This will create a policy that will allow access to the n8n instance from the United Kingdom for users with an email ending in wibble.email. Click on Save and return to the tab where you are configuring the application, here click on Select existing policy and select the policy you just created.

Select a policy

Under Login methods select Accept all available identity providers and click on Next. The next two screens are both optional and can be left at their defaults. Finally, click on Save and you will be taken to the Application screen where you will see your new application listed.

Applications

Once configured and goto your n8n domain you should be prompted to login with Cloudflare, once you have done this you will be taken to the n8n editor:

If you were to try and access the n8n instance from outside the United Kingdom you would be denied access:

Denied !!!

Same for not using the correct email ending in wibble.email. The advantage of this is that unless you meet the criteria you will not be able to access the n8n instance; which means no traffic to your local machine from random people or bots on the internet.

Summary

In this post, we explored how to install n8n on a local resource using Docker and route it via Cloudflare. We saw how easy it is to setup a local n8n instance and how to use Cloudflare Tunnel to route the traffic to it.

Here are the links to n8n and the repository we downloaded the files from:

Share

Related Posts

Comments