This project runs n8n locally with PostgreSQL for persistence and cloudflared to expose the instance through a Cloudflare Tunnel token.
postgres: persistent database for n8nn8n: workflow automation UI and runtimecloudflared: outbound tunnel connector for public exposure through Cloudflare
- Docker
- Docker Compose
- A Cloudflare account and a zone you control
-
Copy the environment template:
cp .env.example .env
-
Copy the Docker Compose override template:
cp docker-compose.override.yml.dist docker-compose.override.yml
-
Create the PostgreSQL data directory before the first start:
mkdir -p .docker/postgres/data
Keep this directory empty before PostgreSQL initializes, otherwise the container may fail to start.
-
Edit
.envand set at least:POSTGRES_PASSWORDN8N_ENCRYPTION_KEYN8N_BASIC_AUTH_USERN8N_BASIC_AUTH_PASSWORDCLOUDFLARE_TUNNEL_TOKEN
-
Start the local stack:
docker compose up -d
-
Open
http://localhost:5678for local access.
The main settings live in .env.
N8N_HOST,N8N_PROTOCOL,N8N_EDITOR_BASE_URL: editor URL settingsWEBHOOK_URL: public base URL used by n8n for webhooksN8N_BASIC_AUTH_*: default protection for the internet-facing instanceCLOUDFLARE_TUNNEL_TOKEN: token used by thecloudflaredcontainerCLOUDFLARE_PUBLIC_HOSTNAME: placeholder for your public DNS name
-
In Cloudflare Zero Trust, create a new tunnel.
-
Choose the Docker connector flow.
-
Create a public hostname such as
n8n.example.comthat points tohttp://n8n:5678. -
Copy the generated tunnel token into
.envasCLOUDFLARE_TUNNEL_TOKEN. -
Set:
CLOUDFLARE_PUBLIC_HOSTNAME=n8n.example.comWEBHOOK_URL=https://n8n.example.com/N8N_EDITOR_BASE_URL=https://n8n.example.com/
-
Start or restart the stack:
docker compose up -d
Cloudflare will terminate HTTPS. The local n8n container still listens on plain HTTP inside Docker.
Start:
docker compose up -dStop:
docker compose downStop and remove volumes:
docker compose down -vLogs:
docker compose logs -f n8n postgres cloudflared- Keep
.envprivate. - Use a strong random value for
N8N_ENCRYPTION_KEY. - Do not expose n8n publicly without authentication.
- If
n8ncannot start, check that PostgreSQL is healthy withdocker compose ps. - If webhooks use the wrong URL, confirm
WEBHOOK_URLandN8N_EDITOR_BASE_URL. - If the public hostname does not connect, verify the tunnel is healthy in the Cloudflare dashboard and inspect
docker compose logs cloudflared.