Self-Hosting n8n on Ubuntu
2025-09-05
20 min
End-to-end instructions for deploying n8n on an old computer/local server.
Pantheon Network
Share

Self-Hosting n8n on Ubuntu

with Docker & a Cloudflare tunnel

This guide provides end-to-end instructions to deploy an n8n instance.

n8n is actively being developed so definitely check their github issues to troubleshoot, don't just rely on stackoverflow or LLMs to debug.

Part 1: Prerequisites & Permanent Permissions Fix

This section prepares the server and solves prepares Docker with the proper permissions.

n8n runs lightweight, it really depends what you have it do. If you're running local LLMs, expect it to require a heavy-duty computer. However, if you're calling APIs and just chaining a workflow together, any old laptop with 8gb of RAM should suffice. The key requirement is that this computer won't move, it will stay put, plugged in and connected to the internet.

All instructions below are for Ubuntu. If it's an old, unused computer, there's no reason not to install Ubuntu on it as a second operating system -- you can use it for n8n and a variety of other purposes (e.g. Home Assistant).

But all these instructions can be adapted for Windows and Mac as well. I would just recommend copy pasting everything below into your LLM of choice, tell it to adapt them to your operating system and additionally web search all instructions to validate that they are correct for your operating system.

If curious: Why use Ubuntu? Mostly every "server" type solution will have Linux support -- they may or may not have Windows or Mac support. Ubuntu is the most popular Linux distro (i.e. operating system). If you have a computer lying around in storage, this is a great way to "learn by doing" and get some value out of an otherwise unused machine.

So, without further ado, setup instructions for Ubuntu:

Update Your System: Ensure all system packages are current.

1sudo apt update && sudo apt upgrade -y 

Install Docker & Compose Plugin: If you don't yet have docker, install the Docker engine and the compose plugin.

1sudo apt install docker.io docker-compose-plugin -y 

Add Your User to the docker Group: This is the most important step to prevent future permission errors with docker. It allows your user to run Docker commands without needing sudo.

1sudo usermod -aG docker ${USER} 

Apply the Group Change: For the permission change to take effect, you must completely log out of your server and log back in (so log out and come back 🙌).

Verify the Change: After logging back in, run the groups command. You should see docker in the list.

1groups 

Part 2: Setup Cloudflare

These steps configure a tunnel to securely expose n8n and protect it with a password. In other words, we're creating a URL to visit rather than a "http://localhost:15679/" and adding a email sign in (so not just anyone on the internet who finds your URL can use your n8n instance. As a heads up, email sign in is overkill, n8n requires a sign in, but adding this step anyways).

So, if you have a Cloudflare tunnel already set up on your device, skip to the "New Cloudflare Tunnel Setup" section, else use the ones directly below:

New Cloudflare tunnel setup:

Prerequisite: Add Your Domain to Cloudflare: You must own a domain name to use Cloudflare Tunnels. If you don't have one, just buy a cheap one from Cloudflare or use your existing domain from Namecheap, GoDaddy, PorkBun, etc and add it to your Cloudflare account and change its nameservers to point to Cloudflare.

Install cloudflared: Follow the official Cloudflare instructions to install the command-line tool on your server.

Login to Cloudflare:

1cloudflared login 

This will open a browser window for you to authorize the tunnel with your Cloudflare account.

Create a Tunnel: Give your tunnel a name.

1cloudflared tunnel create n8n-tunnel 

This will generate a tunnel ID. You do not need to create any local configuration files.

Run the Tunnel as a Service: Copy the tunnel token from the Zero Trust dashboard and use it to create and enable a systemd service. This is the recommended approach for a headless server. Again, follow Cloudflare's instructions.

Add Password Protection (for New and Existing Tunnels):

  1. Go to the Applications Menu:
  2. In the Cloudflare dashboard, go to Zero Trust -> Access -> Applications.
  3. Click Add an application and choose Self-hosted.
  4. Configure Application Details: Application name: n8n Server (or your choice) Session Duration: 24 hours is a good default. Subdomain: {choose a subdomain here like "n8n"} Domain: {your domain goes here}
  5. Create an Access Policy: On the next screen, give the policy a name like Admin Access.
  6. Set the Action to Allow.
  7. Under "Configure rules", for the Selector, choose Emails.
  8. In the Value field, enter your email address.
  9. Click Save application.

Add to an existing Cloudflare tunnel:

Add n8n to Your Existing Tunnel:

  1. In the Cloudflare dashboard, go to Zero Trust -> Access -> Tunnels.
  2. Find your existing, active tunnel and click Configure.
  3. Select the Public Hostnames tab and click + Add a public hostname.
  4. Fill it out with:

Subdomain: {choose a subdomain here like "n8n"}

Domain: {your domain goes here}

Service Type: HTTP

URL: localhost:15679

  1. Click Save hostname.
  2. Add Password Protection: Follow the "Add a Policy for Users to Log In" steps at the end of this section.

* Caveat: If Cloudflare is being annoying, definitely google search to troubleshoot. It can be a headache.

Part 3: n8n Configuration (docker-compose.yml)

This section outlines two options for your database. For a simple, single-user setup, you can use the default SQLite database. If you plan for multiple users, it is highly recommended to use the PostgreSQL setup.

Option A: Single-User Setup with SQLite

Create the Project Directory:

1mkdir -p ~/n8n-server
2cd ~/n8n-server 

Create the docker-compose.yml File:

1nano docker-compose.yml 

Paste the following content: Fyi at the time of writing, the latest version has a bug right at the admin login screen so if you're reading this in the future, replace image: n8nio/n8n:1.108.2 with image: n8nio/n8n@latest

1services:
2  n8n:
3    image: n8nio/n8n:1.108.2
4    restart: always
5    ports:
6      - "15679:5678"
7    environment:
8      - GENERIC_TIMEZONE=America/New_York
9      - N8N_HOST={your url from cloudflare like n8n.yourdomain.com}
10      - WEBHOOK_URL={your url from cloudflare but with the https:// like https://n8n.yourdomain.com}
11      - N8N_SECURE_COOKIE=false
12      - DB_SQLITE_POOL_SIZE=5
13      - N8N_RUNNERS_ENABLED=true
14      - N8N_BLOCK_ENV_ACCESS_IN_NODE=true
15    volumes:
16      - ./n8n_data:/home/node/.n8n

Option B: Multi-User Setup with PostgreSQL

This is the recommended configuration for any production or multi-user environment. It adds a dedicated PostgreSQL database container for better performance and stability.

Create the Project Directory:

1mkdir -p ~/n8n-server
2cd ~/n8n-server 

Create the docker-compose.yml File:

1nano docker-compose.yml 

To use this, add the content of your docker-compose.yml with the following pre-filled configuration:

Fyi at the time of writing, the latest version has a bug right at the admin login screen so if you're reading this in the future, replace image: n8nio/n8n:1.108.2 with image: n8nio/n8n@latest

1services:
2  n8n:
3    image: n8nio/n8n:1.108.2
4    restart: always
5    ports:
6      - "15679:5678"
7    environment:
8      - GENERIC_TIMEZONE=America/New_York
9      - N8N_HOST={your url from cloudflare like n8n.yourdomain.com}
10      - WEBHOOK_URL={your url from cloudflare but with the https:// like https://n8n.yourdomain.com}
11      - N8N_SECURE_COOKIE=false
12      - N8N_RUNNERS_ENABLED=true
13      - N8N_BLOCK_ENV_ACCESS_IN_NODE=true
14      # --- PostgreSQL Connection Settings ---
15      - DB_TYPE=postgresdb
16      - DB_POSTGRESDB_HOST=postgres
17      - DB_POSTGRESDB_PORT=5432
18      - DB_POSTGRESDB_DATABASE=n8n
19      - DB_POSTGRESDB_USER={add a username here}
20      - DB_POSTGRESDB_PASSWORD={add a password here}
21    volumes:
22      - ./n8n_data:/home/node/.n8n
23    depends_on:
24      - postgres
25  postgres:
26    image: postgres:15
27    restart: always
28    environment:
29      - POSTGRES_USER={add a username here}
30      - POSTGRES_PASSWORD={add a password here}
31      - POSTGRES_DB=n8n
32    volumes:
33      - ./postgres_data:/var/lib/postgresql/data

Part 4: The Foolproof Launch Sequence

This sequence ensures n8n starts with a clean slate and the correct permissions. This is for a fresh n8 install and will delete any existing data.

Make sure you're in the Project Directory, else navigate there:

1cd ~/n8n-server 

Stop Any Old Containers:

1docker compose down 

Delete Any Old Data:

1sudo rm -rf ./n8n_data 
2# If you are using PostgreSQL, also remove its old data 
3sudo rm -rf ./postgres_data 

Create Directories and Set Permissions

This prevents the container crash loop by ensuring the data directory has the correct ownership before the container starts.

1mkdir ./n8n_data 
2sudo chown -R 1000:1000 ./n8n_data 
3# If using PostgreSQL, create its directory too
4mkdir ./postgres_data 

Launch the n8n Container(s):

1docker compose up -d 

Ok boom it's launched!

Part 5: Automation (Future-Proofing)

This ensures both n8n and the Cloudflare Tunnel restart automatically after a reboot.

Automate the n8n Container:

Create the service file:

1sudo nano /etc/systemd/system/n8n-docker.service

Paste the following content (make sure to add your username for Ubuntu login):

1[Unit]
2Description=n8n Docker Compose Service
3Requires=docker.service
4After=docker.service
5[Service]
6Type=oneshot
7RemainAfterExit=yes
8User={username goes here!}
9WorkingDirectory={path to wherever your folder is!}/n8n-server
10ExecStart=/usr/bin/docker compose up -d
11ExecStop=/usr/bin/docker compose down
12[Install]
13WantedBy=multi-user.target

Enable the service to start on boot:

1sudo systemctl enable n8n-docker.service 

Ensure Cloudflare Tunnel is Automated:

Verify your cloudflared service is enabled to start on boot.

1sudo systemctl is-enabled cloudflared 

If it's not enabled, run:

1sudo systemctl enable cloudflared

Now go visit your domain and create an admin account!

Part 6: Debugging Journey & Key Fixes

Error: Docker permission denied

Fix: Added the user to the docker group then logged in and out:

1sudo usermod -aG docker ${USER}

Error: 502 Bad Gateway from Cloudflare

Cause: The n8n container was in a "crash loop" because the n8n_data volume had the wrong ownership.

Fix: Manually creating the n8n_data directory and setting its ownership before starting the container.

1sudo chown -R 1000:1000 ./n8n_data 

Error: 1033 from Cloudflare

Fix: Added the correct Public Hostname to the active tunnel in the Cloudflare dashboard.

Error: record with that host already exists in Cloudflare

Fix: Manually deleted the conflicting CNAME record in Cloudflare DNS settings.

Error: 401 Unauthorized and "Could not connect to server" on the n8n setup page

Cause: A bug in n8n versions 1.109.1 and 1.109.2.

Fix: Downgraded to a stable version by changing the image tag to n8nio/n8n:1.108.2.

Read More Articles
I’m interesting in becoming a...
Partner/Client
Researcher
Impact Program Member
Newsletter Subscriber
We look forward to hearing from you
Connect
Thank you! We will be in touch soon.