Docker-compose for n8n + postgres behind CloudFlared

Hopefully, it will be useful to others

I run n8n with Postgres on my laptop and OAuth2 and more requested a static domain to redirect.

As my laptop is on the road; I’m fine with unstable executions time; I had to find a way to make stable the URL to access n8n even if I can’t configure (open port) the router or my public IP change; this is the role of CloudFlared (aka a Road Warrior reverse proxy)

docker-compose.yml

version: '3'

volumes:
  n8n_db:
  n8n_data:

services:
  postgres:
    image: postgres:11
    restart: unless-stopped
    environment:
      - POSTGRES_USER
      - POSTGRES_PASSWORD
      - POSTGRES_DB
      - POSTGRES_NON_ROOT_USER
      - POSTGRES_NON_ROOT_PASSWORD
    volumes:
      - n8n_db:/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: 5s
      timeout: 5s
      retries: 10

  n8n:
    image: docker.n8n.io/n8nio/n8n
    restart: unless-stopped
    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}
      - WEBHOOK_URL=https://URL.DOMAIN.TLD
    links:
      - postgres
    volumes:
      - n8n_data:/home/node/.n8n
    depends_on:
      postgres:
        condition: service_healthy

  cloudflared:
    image: cloudflare/cloudflared
    command: tunnel --no-autoupdate run
    env_file: .env_cloudflare
    restart: unless-stopped
    depends_on:
      - n8n

while in .env_cloudflare I simply cut and past the token of the tunnel like this

  • in this example .env_cloudflare would contain: TUNNEL_TOKEN=eyJhIjoiY2E1M2MyZmFiOWZkMGI5MmQ4NTg1MGU3NTEwNWQ5ZjQiLCJ0IjoiNTcxMGQ3MmMtNTkzNi00NjRhLWE4NmYtOTViMWIyMDY0YzFkIiwicyI6Ik4yTXpaREF6TkdFdFlUUXpaaTAwWW1FeExXRm1ZV1V0T0RRMU1tUm1PV1JrWVRJeiJ9

WEBHOOK

Yes the WEBHOOK_URL and the https:// are important

CLOUDFLARE SIDE

Yes the Service URL need to reflect the NAME of the service and the PORT you want to expose

4 Likes

Hey @JOduMonT,

I really like this, Very nice work.

1 Like

Thank you so so much @JOduMonT

I’ve been struggling to get my Raspberry Pi server working with n8n on my network safely and once I decided to go with Cloudflare, I couldn’t make it work. I just removed Postgres from your .yml since I don’t need it, and it works fine.

1 Like

Hey @JOduMonT , sorry for ressurecting an old topic, but this is right up my alley.

Just had two questions:

  1. When you log into n8n, are you going through the public IP, or do you have a private route setup on CF ZeroTrust?
  2. Since, I run as root user, should I add - /local-files:/files to the volumes?

Hey;
via Cloudflared; I will login via a sub.domain.tld
if you run cloudflared in a container

my docker-compose.yml for cloudflared service

---
services:
  cloudflared:
    container_name: cloudflared
    command: tunnel run
    env_file:
    - ../env/cloudflared
    hostname: cloudflared
    image: cloudflare/cloudflared
    restart: unless-stopped

my …/env/cloudflare environment file

TUNNEL_TOKEN=[asWZkMGIQ4...]

#
# https://one.dash.cloudflare.com
# networks -> tunnels
# configure -> install/run
# command -> cloudflared.exe service install [asWZkMGIQ4...]

my docker-compose.yml for n8n service

---
services:
  n8n:
    container_name: n8n
    env_file:
    - ../env/n8n
    image: n8nio/n8n:latest
    restart: always
    volumes:
    ## ensure `chown 1000:100` + `chmod g+w` for `/home/node/.n8n`
    - ../data/n8n/app:/home/node/.n8n
    - /tmp/shared:/tmp/shared

  n8n-db:
    container_name: n8n-db
    env_file:
    - ../env/n8n
    image: postgres:16-alpine
    restart: always
    volumes:
    - ../data/n8n/db:/var/lib/postgresql/data

my …/env/n8n environment file

DB_TYPE=postgresdb
DB_POSTGRESDB_HOST=n8n-db
DB_POSTGRESDB_USER=n8n
DB_POSTGRESDB_PASSWORD=rand0mP45sw0rd

N8N_HOST=sub.domain.tld
N8N_PORT=5678
N8N_PROTOCOL=https
NODE_ENV=production
WEBHOOK_URL=https://sub.domain.tld/
GENERIC_TIMEZONE=Europe/Paris

POSTGRES_USER=n8n
POSTGRES_PASSWORD=SAMErand0mP45sw0rd
POSTGRES_DB=n8n

which I put together via a docker-compose.yml master :wink:

services:
## PROXY
  cloudflared:
    extends:
      file: compose/cloudflared.yml
      service: cloudflared
## N8N
  n8n:
    extends:
      file: compose/n8n.yml
      service: n8n
  n8n-db:
    extends:
      file: compose/n8n.yml
      service: n8n-db

my directory (I sur /srv for running docker)

/srv/
/srv/compose/
/srv/data/
/srv/env/

I run cd /srv/

docker compose up -d

  • which call my MASTER docker-compose.yml
  • which extends docker service to others docker-compose.yml files which are located in /srv/compose/
1 Like

You are the man, THANK you!