Self-Hosting n8n on Raspberry Pi with Cloudflare Tunnel


Everything is moving so fast. Like, really fast.

The last few weeks have been an absolute mess. I’ve been buried under a mountain of side projects, each one screaming for attention like a toddler who just discovered they have lungs. Claude Code dropped a lot things and suddenly everyone’s terminal looks like it’s possessed by a very helpful demon. Ralph scripts are everywhere. Clawdbot (now called Moltbot), well, it is something. New CLI tools pop up every other day. My GitHub stars list looks like a hoarder’s attic.

i-am-in-danger

Thing is, sometimes you really need to go through this chaos. You need to tinker with a dozen half-baked projects before something clicks. Not every side project needs to be “the one.” Sometimes the journey through the noise helps you find the signal.

But here’s what I’ve learned the hard way. It’s not always best to be an early adopter, especially when life keeps throwing lemons at your face in the shape of AI agents, new CLI tools, and yet another framework that promises to change everything. You don’t need to buy an M4 Mac Studio with 512GB of RAM just to send a Telegram message to your smart washing machine. That’s not tinkering, that’s FOMO with a credit card.

OK, I calmed down…

Among all this chaos, one tool actually stuck. Something that turned my scattered automations into actual useful workflows: n8n.

What is n8n?

n8n (according to YT, pronounced “n-n-n”) is like a self-hosted Zapier, but you own the whole thing. It’s a workflow automation platform where you connect different services, APIs, and triggers through a visual node-based editor. Want to get a Slack notification when someone stars your GitHub repo? Done. Want to scrape a website and dump results into a spreadsheet every morning? Easy. Want to trigger a home automation routine based on weather data? You get the idea.

one-of-my-n8n-flows I’ll give more details about these flows in the coming days.

The best part? It can run beautifully on a Raspberry Pi. No cloud subscriptions are needed (at least for personal fair use). No usage limits. Just your tiny computer doing actual work.

If you’ve been following my Raspberry Pi homelab journey, this is another piece of that puzzle. And if you already have Portainer running, deploying this becomes even easier.

Prerequisites

Before we dive in, make sure you have:

  • A Raspberry Pi (Pi 4 or Pi 5 recommended, at least 4GB RAM)
  • Docker and Docker Compose installed
  • A Cloudflare account with a domain pointed to Cloudflare DNS
  • Basic terminal knowledge (SSH into your Pi, edit files, etc.)

If you don’t have Docker yet, it’s a one-liner:

curl -sSL https://get.docker.com | sh

Let’s do this.

The Setup Files

I’m using Cloudflare Tunnel to expose n8n to the internet without messing with port forwarding. This is especially handy if your ISP uses CG-NAT or blocks inbound ports (like mine does). Cloudflare handles SSL automatically, so you get HTTPS out of the box.

Here are the two files you need. Create a directory for your n8n setup first:

mkdir ~/n8n && cd ~/n8n

docker-compose.yml

This is the main configuration file. It sets up both the Cloudflare tunnel and n8n itself:

# ===========================================
# n8n with Cloudflare Tunnel
# ===========================================
# Raspberry Pi
# Cloudflare Tunnel handles SSL automatically
# ===========================================

services:
  # Cloudflare Tunnel - handles routing and SSL
  cloudflared:
    image: cloudflare/cloudflared:latest
    container_name: cloudflared-n8n
    restart: always
    command: tunnel run
    environment:
      - TUNNEL_TOKEN=${CLOUDFLARE_TUNNEL_TOKEN}

  # n8n Workflow Automation
  n8n:
    image: docker.n8n.io/n8nio/n8n
    container_name: n8n
    restart: always
    ports:
      - "127.0.0.1:5678:5678"
    environment:
      # Security
      - N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
      - N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true
      # Domain configuration
      - N8N_HOST="YOUR_DOMAIN"
      - N8N_PORT=5678
      - N8N_PROTOCOL=https
      - WEBHOOK_URL="YOUR WEBHOOK URL"
      # Features
      - N8N_RUNNERS_ENABLED=true
      - NODE_ENV=production
      # Timezone
      - GENERIC_TIMEZONE=Europe/London
      - TZ=Europe/London
    volumes:
      - n8n_data:/home/node/.n8n
      - ./local-files:/files
    depends_on:
      - cloudflared
    healthcheck:
      test: ["CMD-SHELL", "wget -qO- http://localhost:5678/healthz || exit 1"]
      interval: 30s
      timeout: 10s
      retries: 3

volumes:
  n8n_data:

Environment Variables (.env)

Create a .env file in the same directory. Never commit this to version control!

# ===========================================
# n8n Environment Configuration
# ===========================================
# Copy this file to .env and fill in the values
# NEVER commit .env to version control!
# ===========================================

# Cloudflare Tunnel Token (REQUIRED)
# Get this from: Cloudflare Zero Trust → Networks → Tunnels → Your Tunnel
CLOUDFLARE_TUNNEL_TOKEN=your-tunnel-token-here

# n8n Encryption Key (REQUIRED for production)
# Generate with: openssl rand -hex 32
# IMPORTANT: Save this somewhere safe! If lost, all saved credentials become unrecoverable.
N8N_ENCRYPTION_KEY=generate-a-random-32-byte-hex-string

Phew.

Step-by-Step Instructions

1. Generate Your Encryption Key

This key encrypts all your credentials stored in n8n. Lose it and you lose access to all saved API keys and passwords. Run this and save the output somewhere safe:

openssl rand -hex 32

Copy the output and paste it as your N8N_ENCRYPTION_KEY in the .env file.

2. Create a Cloudflare Tunnel

Head over to Cloudflare Zero Trust Dashboard:

  1. Go to Networks → Tunnels
  2. Click Create a tunnel
  3. Give it a name (something like n8n-tunnel)
  4. Choose Cloudflared as the connector
  5. Copy the tunnel token—this goes into your .env file as CLOUDFLARE_TUNNEL_TOKEN

3. Configure the Tunnel Route

Still in the Cloudflare dashboard:

  1. In your tunnel settings, go to Public Hostname
  2. Add a new public hostname:
    • Subdomain: n8n (or whatever you want)
    • Domain: Select your domain
    • Service: http://n8n:5678

This tells Cloudflare to route traffic from n8n.yourdomain.com to your n8n container.

4. Update Your docker-compose.yml

Replace YOUR_DOMAIN with your actual domain (e.g., n8n.yourdomain.com) and YOUR WEBHOOK URL with the full URL (e.g., https://n8n.yourdomain.com).

5. Fire It Up

docker compose up -d

Give it a minute to pull the images and start. You can check the logs with:

docker compose logs -f

6. Access n8n

Visit your domain (e.g., https://n8n.yourdomain.com) and you should see the n8n setup screen. Create your account and start building workflows!

If you’re using Portainer, you can also deploy this stack through the UI by copying the docker-compose.yml content into a new stack. Just make sure to add the environment variables in Portainer’s environment section.

Potential Improvements

  1. Set up automated backups – Use a cron job to backup the n8n_data volume regularly
# Add to crontab with: crontab -e
# Runs every Sunday at 3 AM
0 3 * * 0 docker run --rm -v n8n_n8n_data:/data -v ~/n8n-backups:/backup alpine tar czf /backup/n8n-backup-$(date +\%Y\%m\%d).tar.gz -C /data .
  1. Add Watchtower – Automatically update your containers when new images are released
  2. Set up monitoring with Uptime Kuma – Track if your n8n instance goes down

Why Self-Host?

I’ll be honest. You could just use n8n’s cloud offering or stick with Zapier. But where’s the fun in that? Self-hosting means:

  • No monthly fees eating into your budget
  • No workflow limits holding you back
  • Complete data privacy – your automations, your data, your server
  • Learning experience – you actually understand what’s happening under the hood

Is it the easiest path? I mean, it is not that hard c’mon. Is it the most satisfying? Absolutely.

This was a fun project to spend some of my time and brain juice. Among all the chaos of new tools and frameworks, sometimes the best thing you can do is pick one thing, make it work, and actually use it. n8n is that thing for me right now. I really don’t need to send Telegram messages to my washing machine. Or, do I?

I’ve already designed and activated some nice automations that have been saving me time. I’ll share them here soon. Stay tuned!


Let me know if this works for you!

Cheers,

Berkem