Securely Self-Hosting n8n with Docker & Cloudflare Tunnel (The... Arguably Less-Painful Way)

Securely Self-Hosting n8n with Docker & Cloudflare Tunnel (The… Arguably Less-Painful Way)

Alright, let’s be honest. You want to run n8n. You don’t want to pay for a hosted service. You also don’t want to become a network security expert just to open a single port. I get it.

This guide outlines a method for securely self-hosting n8n using Docker and Cloudflare Tunnel (cloudflared). The goal? Remote access without the firewall headaches. We’ll be setting this up on a Linux server (Debian Bookworm was used initially, but most distributions should work). The best part? It plays nicely with Cloudflare’s free tier if you’re already using it.

Who’s this for? Anyone reasonably familiar with the Linux command line. If you can copy and paste commands, you’re probably good. If you got a domain, an old PC/server laying around, and you’re really dead set on killing half a day to save $8 a month, this guide is for you.

The payoff? A publicly accessible n8n instance without compromising your network. Consider this your “good enough” solution.

What You’ll Need (Prerequisites)

Before we begin the descent into self-hosting madness, gather these essentials:

  1. A Linux (or Windows) Server: A physical machine or VM. (Debian/Ubuntu are common, systemd assumed). Docker and cloudflared are also available for Windows if that’s your thing, though this guide focuses on Linux.
  2. Root or sudo Access: You’ll need admin rights on the server.
  3. Docker & Docker Compose: The containerization tools. Also available for Windows, see the links below.
  4. A Domain Name: Registered and managed through your Cloudflare account (e.g., yourdomain.com).
  5. Cloudflare Account: A free account is perfectly fine.
  6. Basic Command Line Skills: If you’re reading this, you probably have them.

Step 1 - Getting Docker Ready

We need Docker (and Docker Compose if desired) installed.

Installing Docker Engine

Follow Docker’s official guide for your OS:

Pro Tip: After installing, add your user to the docker group to avoid constant sudo:
sudo usermod -aG docker $USER
Then log out/in, or run newgrp docker.

Installing Docker Compose

It helps manage container setups.

Step 2 - Installing cloudflared

Cloudflare’s tunnel daemon.

  1. Download cloudflared: Downloads page - https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/
  2. Install:
    • Debian/Ubuntu (.deb file):

      sudo dpkg -i <path-to-your-cloudflared-package.deb>
      sudo apt --fix-broken install #If deps are missing
      

Step 3 - Connecting Cloudflare (cloudflared Login & Tunnel Creation)

Link to Cloudflare and create the tunnel.

Logging In

cloudflared tunnel login

It opens a browser to authenticate with your Cloudflare account.

Important: Run this as your regular user, not root. It saves the auth cert in your home directory.

Creating Your Tunnel

Creates the tunnel (give it a name, we’ll use n8n-tunnel):

cloudflared tunnel create n8n-tunnel

Important: Save the output! You need the Tunnel UUID and credentials file path.

Step 4 - Pointing Your Domain (The Magic DNS Bit!)

This connects your public hostname (e.g., n8n.yourdomain.com) to the tunnel. The cloudflared command handles the DNS CNAME creation.

Run this, replace placeholders:

cloudflared tunnel route dns <YOUR_TUNNEL_NAME_OR_UUID> <your-subdomain.yourdomain.com>

Example:

cloudflared tunnel route dns n8n-tunnel n8n.yourdomain.com

It adds a CNAME in Cloudflare DNS automatically.

Step 5 - Configuring cloudflared

Tells cloudflared what to do.
Standard location: /etc/cloudflared/config.yml

# /etc/cloudflared/config.yml

tunnel: 0354b1ee-acc8-4638-b4d7-7951160a4723 # REPLACE - Your Tunnel UUID

credentials-file: /home/local/.cloudflared/0354b1ee-acc8-4638-b4d7-7951160a4723.json #REPLACE- credential path

ingress:
  - hostname: n8n.yourdomain.com # REPLACE- your desired subdomain
    service: http://localhost:5678 # Points to n8n on the *host*
  - service: http_status:404

Note: credentials-file path. Check where the auth file is actually stored. Default is usually /home if instructions above were followed, but can also be in /root if cloudflared tunnel login was run with sudo, ensure it can be accessed.

Step 6 - Running n8n (Choose Your Adventure!)

Use either docker run or docker compose.

Remember: WEBHOOK_URL env var must match the public URL from Step 4.
Also, the n8n subdomain here is just an example, use anything you want!

Option A - Using docker run

docker run -it -d --restart unless-stopped --name n8n \
  -p 5678:5678 \
  -e GENERIC_TIMEZONE="America/New_York" \
  -e TZ="America/New_York" \
  -e WEBHOOK_URL="https://n8n.yourdomain.com" #REPLACE -Webhook MUST match subdomain
  -v n8n_data:/home/node/.n8n \
  -v ./local-files:/files \ #maps a folder for local files
  docker.n8n.io/n8nio/n8n
  • Key Flags:
    • --restart: Keeps n8n running.
    • -p 5678: Exposes n8n to the host.
    • -v ./local-files:/files: Directory where you ran the command.
  • Details: n8n Docker Documentation

Option B - Using docker compose

Create docker-compose.yml:

# docker-compose.yml
services:
  n8n:
    image: docker.n8n.io/n8nio/n8n
    container_name: n8n
    restart: unless-stopped
    ports:
      - "5678:5678" # Exposes port 5678 to the host
    environment:
      - GENERIC_TIMEZONE=America/New_York
      - TZ=America/New_York
      #REPLACE!!!! -Webhook MUST match subdomain
      - WEBHOOK_URL=https://n8n.yourdomain.com
    volumes:
      - n8n_data:/home/node/.n8n
      - ./local-files:/files #maps a folder for local files

volumes:
  n8n_data:

Run:

docker compose up -d

Verify: docker ps, and curl localhost:5678.

Step 7 - Launching the Tunnel (Finally!)

Run cloudflared as a system service for reliability.

  1. Install the Service: Registers with systemd.

    sudo cloudflared service install
    
  2. Enable and Start:

    sudo systemctl enable --now cloudflared
    
  3. Check Status:

    systemctl status cloudflared
    

    See if it’s running.

  4. View Logs:

    journalctl -u cloudflared -f
    

Conclusion & Benefits

Alright, that’s it. Assuming no gremlins snuck in and you didn’t skip any steps, you should have n8n running securely and accessible via your chosen public URL. Give yourself a pat on the back – you’ve navigated the sometimes-murky waters of self-hosting!

Quick Recap of Benefits

  • No Open Ports: The major win. This is a significantly more secure setup than traditional port forwarding.
  • Encrypted & Proxied: Traffic is encrypted via HTTPS to Cloudflare and proxied through their network.
  • Cloudflare’s Network: You’re leveraging a robust, globally distributed infrastructure.
  • Free-ish (For Light Use): Cloudflare’s free tier covers most home/testing scenarios.

Important Limitations & Warnings (Read This!)

  • Scalability Caveat: This setup is primarily intended for development, testing, or light personal use. It is not a robust, scalable solution for high-traffic production environments. Proceed at your own risk.
  • Cloudflare Cost Implications: While the tunnel itself can be free, Cloudflare might start charging you if you push excessive amounts of traffic through their network. Monitor your Cloudflare usage carefully. High webhook volumes, large file transfers, or frequent UI access can all contribute to increased traffic.
  • This Is Not a Fortress: Cloudflare Tunnel provides a good baseline level of security, but it is not a replacement for proper security practices inside your network or within n8n itself. Always keep your n8n instance updated.

Final Checks, Security Hardening & Enjoy

  • Testing, Testing: Visit https://<your-subdomain.yourdomain.com>. If it doesn’t load, double-check everything (again). Seriously.
  • Troubleshooting Power-Ups: If things explode, start by:
    • Reviewing /etc/cloudflared/config.yml (Tunnel UUID and hostname).
    • Verifying the cloudflared tunnel route dns ... command syntax.
    • Confirming the n8n Docker config has the correct WEBHOOK_URL.
    • Checking cloudflared service status (systemctl status cloudflared) and logs (journalctl -u cloudflared -f).
  • n8n’s Admin Panel on non-dev boxes: Look into configuring user management on your n8n server. This will avoid any security issues relating to this.
  • Serious Security Considerations (Beyond the Scope of This Guide):
    • For production environments, consider using Cloudflare Access (WARP) to add an additional layer of authentication before reaching your n8n instance. This allows only authorized users to access the n8n UI, even though the tunnel is publicly accessible.
    • You’ll also need to create Cloudflare routing rules to allow inbound traffic from valid webhooks URLs (e.g., https://n8n.yourdomain.com/webhook/*) and require authentication for all other traffic (especially access to the n8n login panel).

Hopefully, this was helpful. Happy Automating :sunglasses:


6 Likes

I’ve put together a complete and secure stack using Docker Compose for running n8n with all the bells and whistles :rocket:

:wrench: What’s Included in the Stack:

  • n8n: Powerful workflow automation platform
  • PostgreSQL: For data persistence
  • Qdrant: Vector DB for AI/semantic search use cases
  • NGINX: Reverse proxy for local HTTPS access with Let’s Encrypt
  • Cloudflared: For secure public access without opening ports

:sparkles: The beauty of this setup:

  • You can run it entirely in your home lab with SSL via NGINX
  • Or use Cloudflare Tunnel for remote access without port forwarding
  • Or even combine both for maximum flexibility
  • Everything starts with a single docker compose up -d

:closed_lock_with_key: This guide is perfect for:

  • Home lab enthusiasts
  • Developers testing automation
  • Anyone who wants a secure, production-ready n8n deployment

:open_book: Grab the Docker Compose file here:
:point_right: GitHub

4 Likes

You sir, are a gentleman and a scholar. Excellent repo, I have no notes. If you’re here looking for a turn-key package for a performant and secure home lab build, this guy just hooked you up.

His script also fixes a lot of nuisance bits neither I nor n8n in their docs really talk about, like setting up permissions correctly, setting up the systemd service, and more. Thank you for sharing! :saluting_face:

Wouldn’t it be slightly improved, by swapping PostgreSQL & Qdrant out for Supabase instead?

Ostensibly, for those familiar with it, but I think the objective of this was for it to be fully self-hostable. I know Supabase has a SH option, don’t know if it supports all the AI/Vector stuff and how much more or less involved its setup is vs. PostgreSQL/Qdrant. Not a Supabase guy myself.

Thanks so much.

I’m so grateful you took the time to share this.

you can also just add it into the docker composer like this

cloudflared:
image: cloudflare/cloudflared:latest
command: tunnel --no-autoupdate run --token TOKENHERE
restart: always
depends_on:
- n8n

saves so much time :slight_smile:

1 Like

Big shout out to @TFSho & @King_Samuel_David . Here’s a video demonstrating the work you gentlemen contributed to.

:point_right: Video Tutorial

2 Likes

btw, if you want I can explain securing I briefly mentioned it here

using zerotrust, maybe another good content piece for you

2 Likes

oh this is gold! Thanks for sharing!

to add to this question that @MarkR-A said.. I kind of did tried and experimented with selfhosted Supabase, but it’s not working very well for me (in browser context - its not like live site) - so kind of postgres/pgadmin+pgvector - do very well - this docker setup looks very solid!