How to Deploy and Host Your Own n8n Server: Step-by-Step Guide with Docker, PostgreSQL & Caddy
A step-by-step guide to host your own n8n workflow engine with Docker Compose, PostgreSQL database, and Caddy SSL proxying.
Relying on SaaS automation tools like Zapier or Make gets expensive fast as your task volumes grow. A single runaway loop can spike your monthly bill, and sending customer data through third-party servers presents data privacy risks.
n8n (pronounced n-eight-n) is a fair-code, self-hosted workflow automation platform. It provides a visual canvas with hundreds of pre-built integrations, custom code execution, and AI agent capabilities—without charging you per-execution SaaS fees.
By hosting n8n on your own server, your data stays strictly under your control, and you eliminate per-task SaaS pricing models. While your actual execution capacity will depend on your server’s CPU, RAM, and database performance, self-hosting gives you complete freedom to scale as your automation needs grow. This guide walks you through building a solid, production-oriented n8n server using Docker Compose, a PostgreSQL database, and Caddy for automatic SSL certificate management.
Why Self-Host n8n over Zapier or Make?
Before jumping into the command line, here is how a self-hosted n8n server compares to traditional SaaS platforms:
- Fair-Code Source Availability: You can inspect the source code, build custom nodes, host it on your own server, and tailor it to your workflow needs without per-task charges.
- Node-Based Workflow Editor: Drag-and-drop triggers (webhooks, cron schedules, app listeners) and action nodes to transform data and execute API calls visually.
- JavaScript & Python Code Execution: Write inline JavaScript or Python inside n8n Code nodes to handle complex data parsing, filtering, and custom logic.
- Complete Data Sovereignty: API keys, database credentials, and sensitive customer payloads remain safely inside your isolated private cloud.
How n8n Works Under the Hood
n8n uses an event-driven runtime to process automation tasks:
- Triggers: Every workflow starts with a trigger node. This can listen for incoming HTTP requests (Webhooks), run at set intervals (Cron schedules), or poll third-party APIs (like Gmail, GitHub, or Stripe).
- Directed Graph of Nodes: The visual canvas links nodes in a directed graph. Each node receives incoming data, performs an operation (e.g., transforming payload, calling an external API, or querying a database), and outputs the results.
- JSON Array Pipeline: Nodes exchange data as arrays of JSON objects. Every node processes the incoming JSON payload and passes the modified payload downstream.
- Sequential Execution Engine: The engine executes nodes step-by-step, handles conditional IF/ELSE branching, logs execution history, and allows you to debug or replay failed runs.
Production Architecture & Network Flow
Here is how traffic, SSL termination, network isolation, and database persistence flow through the Docker stack:
graph TD
Client([External Webhooks & Clients]) -->|HTTPS:443| Caddy[Caddy Reverse Proxy]
Browser([Admin UI Browser]) -->|HTTPS:443| Caddy
Caddy -->|HTTP over Docker Network:5678| n8n[n8n Container]
n8n -->|Port 5432 Internal| Postgres[(PostgreSQL 16 Database)]
n8n <-->|Volume Mount| DataDir[(~/n8n-docker/data)]
Postgres <-->|Volume Mount| PGDir[(~/n8n-docker/postgres_data)]
Network Flow Explanation:
- External Traffic: Caddy listens on public ports
80(HTTP redirect) and443(HTTPS). Caddy automatically provisions and renews TLS/SSL certificates from Let’s Encrypt using your configuredUSER_EMAIL. - Internal Proxying: Caddy terminates TLS at the edge and proxies requests internally over Docker’s private bridge network to
n8n:5678using standard HTTP. n8n itself does not run HTTPS internally. - Loopback Binding: In
docker-compose.yml, n8n binds to127.0.0.1:5678:5678. This keeps port 5678 accessible locally on the host for testing while preventing direct public exposure over the open internet. - Database Isolation: PostgreSQL runs on port 5432 inside the private Docker network and is not exposed to host ports, protecting your data from external database scans.
Key Features in Modern n8n
n8n has expanded far beyond simple webhook triggers:
- AI Agent Nodes: Build autonomous AI agents using LLMs (OpenAI, Anthropic, or local models via Ollama) and grant them access to custom n8n tool nodes.
- Human-in-the-Loop: Pause workflows mid-execution to wait for manual approval or input via Slack, email, or custom web forms before continuing.
- Canvas Organization: Group nodes with sticky notes and visual color blocks to keep large enterprise workflows organized and clean.
Building AI Agents in n8n (Advanced AI Nodes)
Modern n8n includes native, LangChain-powered AI nodes that allow you to construct autonomous AI agents directly on your visual canvas:
- AI Agent Node (The Core Engine): Connects a language model to memory buffer sub-nodes and external tool nodes. The agent autonomously decides which tool to call based on user prompts.
- Language Model Sub-Nodes: Connect cloud LLM providers (e.g.,
OpenAI Chat Model,Anthropic Chat Model) or self-hosted local models viaOllamafor 100% private data inference. - Tool Sub-Nodes: Equip your AI agent with capabilities to execute real actions—such as querying your PostgreSQL database, searching vector stores (Qdrant, Pinecone), sending Slack messages, or calling custom HTTP APIs.
- Memory Nodes: Attach
Window Buffer MemoryorPostgres Chat Memoryso the AI agent retains context across multi-turn user conversations.
Hardware & System Prerequisites
Before starting the setup, ensure you have the following prerequisites ready:
- Cloud Server (VPS): A Linux server running Ubuntu 22.04/24.04 LTS or Debian 12 with SSH access (
rootorsudoprivileges).- Minimum: 1 vCPU, 2 GB RAM (suitable for personal automations).
- Recommended: 2 vCPU, 4 GB RAM, and SSD storage (essential for AI nodes, Queue mode, or production workloads).
- Note: Actual hardware requirements depend on your workflow complexity, dataset sizes, and execution concurrency.
- Domain Name & DNS Control: A domain or subdomain (e.g.,
automation.yourdomain.com) with access to your DNS management console. - Public IP Address: A static public IPv4 address assigned to your server.
- Open Network Ports: Ports
80(HTTP) and443(HTTPS) open for web traffic, and port22open for SSH access. - Docker & Docker Compose: Docker containerizes application environments, while Docker Compose orchestrates multi-container applications (n8n, PostgreSQL, and Caddy together) using a single
docker-compose.ymlfile.
Step-by-Step n8n Docker Setup Guide
This guide configures n8n alongside PostgreSQL (for database stability over SQLite) and Caddy (for zero-touch Let’s Encrypt HTTPS certificates).
Step 1: Configure DNS Settings
Log into your domain registrar or DNS host (like Cloudflare, Route53, or Namecheap) and create an A Record:
- Name / Host:
automation(or your preferred subdomain) - Target Value: Your VPS’s public IP address
(Note: If using Cloudflare, you can temporarily disable the proxy feature—gray cloud icon—during initial setup so Caddy can pass Let’s Encrypt HTTP-01 domain validation).
Step 2: Connect to VPS, Enable Firewall & Install Docker
SSH into your server:
ssh root@YOUR_SERVER_IP
Set up basic firewall protection with UFW to allow SSH, HTTP, and HTTPS traffic:
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw enable
Install Docker and the Docker Compose plugin:
sudo apt update && sudo apt upgrade -y
sudo apt install docker.io docker-compose-plugin -y
Step 3: Create Directory Structure & Set Container Permissions
Create directories for configuration files and database volumes:
mkdir -p ~/n8n-docker/data
mkdir -p ~/n8n-docker/postgres_data
cd ~/n8n-docker
The official n8n container runs internally as a non-root user (node with UID/GID 1000). Set permissions on the n8n data folder so the container can write user settings and binary attachments:
sudo chown -R 1000:1000 ~/n8n-docker/data
Step 4: Create the Environment File (.env)
Create .env to centralize domain names, secret keys, and database credentials:
nano .env
Paste the following variables (replace placeholder values with your domain, admin email, and strong passwords):
# Domain & Admin Settings
DOMAIN_NAME=automation.yourdomain.com
SUBDOMAIN=automation
USER_EMAIL=[email protected]
# System Secrets
# Generate a secure key with: openssl rand -hex 24
N8N_ENCRYPTION_KEY=your_generated_encryption_key_here
N8N_PORT=5678
# Database Credentials
POSTGRES_USER=n8n_db_user
POSTGRES_PASSWORD=your_secure_db_password_here
POSTGRES_DB=n8n_database
# Production Environment & Reverse Proxy Settings
GENERIC_TIMEZONE=UTC
N8N_PROTOCOL=https
NODE_ENV=production
WEBHOOK_URL=https://automation.yourdomain.com
N8N_SECURE_COOKIE=true
# SMTP Configuration (Configure to send password resets & invite emails)
N8N_EMAIL_MODE=smtp
N8N_SMTP_HOST=smtp.mailgun.org
N8N_SMTP_PORT=587
N8N_SMTP_USER=[email protected]
N8N_SMTP_PASS=your_smtp_password_here
N8N_SMTP_SENDER="n8n Automation <[email protected]>"
N8N_SMTP_SSL=false
Save with Ctrl + O, press Enter, and exit with Ctrl + X.
IMPORTANTEncryption Key Safety: Keep
N8N_ENCRYPTION_KEYbacked up in a secure password manager. Do not randomly regenerate it on an existing setup—changing this key will render previously saved credentials (API keys, OAuth tokens) permanently unreadable.
Step 5: Write docker-compose.yml
Create the compose configuration file:
nano docker-compose.yml
Paste this production configuration:
services:
postgres:
image: postgres:16-alpine
restart: always
environment:
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=${POSTGRES_DB}
volumes:
- ./postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -h localhost -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 5s
timeout: 5s
retries: 10
caddy:
image: caddy:latest
restart: always
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
- caddy_config:/config
environment:
- DOMAIN_NAME=${DOMAIN_NAME}
- USER_EMAIL=${USER_EMAIL}
n8n:
image: docker.n8n.io/n8nio/n8n:latest
restart: always
ports:
- "127.0.0.1:5678:5678"
environment:
- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=postgres
- DB_POSTGRESDB_PORT=5432
- DB_POSTGRESDB_DATABASE=${POSTGRES_DB}
- DB_POSTGRESDB_USER=${POSTGRES_USER}
- DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD}
- N8N_HOST=${DOMAIN_NAME}
- N8N_PORT=${N8N_PORT}
- N8N_PROTOCOL=${N8N_PROTOCOL}
- NODE_ENV=${NODE_ENV}
- WEBHOOK_URL=${WEBHOOK_URL}
- N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
- GENERIC_TIMEZONE=${GENERIC_TIMEZONE}
- N8N_SECURE_COOKIE=${N8N_SECURE_COOKIE}
- N8N_EMAIL_MODE=${N8N_EMAIL_MODE}
- N8N_SMTP_HOST=${N8N_SMTP_HOST}
- N8N_SMTP_PORT=${N8N_SMTP_PORT}
- N8N_SMTP_USER=${N8N_SMTP_USER}
- N8N_SMTP_PASS=${N8N_SMTP_PASS}
- N8N_SMTP_SENDER=${N8N_SMTP_SENDER}
- N8N_SMTP_SSL=${N8N_SMTP_SSL}
depends_on:
postgres:
condition: service_healthy
volumes:
- ./data:/home/node/.n8n
volumes:
caddy_data:
caddy_config:
Save and exit.
TIPImage Tag Pinning Note: While using
:latesttags is acceptable for testing and tutorials, production environments should consider pinning n8n and Caddy to specific tested version tags (e.g.,docker.n8n.io/n8nio/n8n:1.75.0). Pinning image tags prevents automatic updates from introducing breaking changes during container restarts.
Step 6: Create the Caddyfile
Caddy handles reverse proxying and automated SSL certificate issuance. Create the Caddyfile:
nano Caddyfile
Add this reverse proxy block:
{
email {$USER_EMAIL}
}
{$DOMAIN_NAME} {
reverse_proxy n8n:5678
}
Save and exit.
Explanation: Caddy uses {$USER_EMAIL} and {$DOMAIN_NAME} from your .env file. It automatically requests Let’s Encrypt SSL certificates for your domain and proxies incoming HTTPS requests to n8n:5678 over the shared Docker bridge network.
Step 7: Launch Containers
Start the services in detached background mode:
docker compose up -d
Docker will download the images, initialize PostgreSQL, provision Let’s Encrypt SSL certificates, and start the n8n application container.
Step 8: Set Up Owner Credentials
Navigate to https://automation.yourdomain.com in your browser. Create your administrator account credentials to access the canvas.
WARNINGComplete account setup immediately. The first person to visit a fresh n8n web URL becomes the instance owner. Register your admin account immediately after launching containers to prevent unauthorized registration.
Step 9: How to Create and Configure a Webhook in n8n (Verification)
To verify that your SSL proxy, container networking, and database logging are working properly:
- Create a New Workflow: Click + New Workflow inside the n8n dashboard canvas.
- Add a Webhook Trigger Node: Click + Add First Step, select Webhook, and configure its settings:
- HTTP Method: Select
POST(orGET). - Path: Enter a custom endpoint slug (e.g.,
my-test-webhook). - Authentication: Select
Nonefor testing. - Respond Mode: Select When Last Node Finishes or Immediately.
- HTTP Method: Select
- Test vs. Production URLs:
- Test URL (
/webhook-test/...): Used during workflow development. Requires clicking Listen for Test Event in the editor. - Production URL (
/webhook/...): Active 24/7 once you toggle the workflow switch from Inactive to Active.
- Test URL (
- Trigger & Test the Webhook: Toggle your workflow to Active, copy the Production URL, and send a test POST request from your terminal:
curl -X POST https://automation.yourdomain.com/webhook/my-test-webhook \
-H "Content-Type: application/json" \
-d '{"status": "testing n8n webhook", "success": true}'
If you receive an HTTP 200 OK response with {"message": "Workflow executed successfully"}, your reverse proxy, SSL certificates, container networking, and PostgreSQL logging matrix are fully operational!
Production Best Practices & Maintenance
Security Best Practices Checklist
To keep your self-hosted n8n server secure against unauthorized access:
- Strong Credentials: Use strong, unique passwords for
POSTGRES_PASSWORDand your n8n owner account. - Loopback Port Binding: In
docker-compose.yml, bind port5678strictly to loopback (127.0.0.1:5678:5678). This ensures n8n is accessible only through Caddy’s HTTPS proxy. - Enforce Non-Root Execution: Run the container under non-privileged UID/GID permissions (
chown -R 1000:1000 ~/n8n-docker/data) to prevent container breakout risks. - Enable HTTPS & Secure Cookies: Set
N8N_PROTOCOL=httpsandN8N_SECURE_COOKIE=truein.envto enforce encrypted session cookies. - Configure Firewall (UFW): Allow incoming traffic only on ports
22(SSH),80(HTTP), and443(HTTPS). - Run Security Audits: If supported by your n8n version, run n8n’s built-in security audit tool:
docker compose exec n8n n8n audit
How to Configure SMTP Email for Notifications
Configure SMTP if you want n8n to send password-reset emails, user invitations, and workflow failure notifications.
- Obtain Credentials: Get your host (
smtp.mailgun.org), port (587), username, password, and sender address from your email provider. - Update
.env: SetN8N_EMAIL_MODE=smtpand populate yourN8N_SMTP_*credentials. - Map Variables: Ensure
docker-compose.ymlmapsN8N_SMTP_*variables into then8ncontainer service. - Apply & Test: Run
docker compose up -dand test email delivery via Settings > Email in the n8n dashboard.
Automated Database & File Backup System
To protect your self-hosted instance from hardware failure or corrupted deployments, implement automated daily backups for both PostgreSQL records and user binary volumes.
Manual PostgreSQL Backup Command
To back up your database, execute pg_dump via Docker Compose. Ensure n8n_db_user matches POSTGRES_USER and n8n_database matches POSTGRES_DB in your .env file:
# 1. Export PostgreSQL database (-T disables pseudo-TTY allocation for clean redirect)
docker compose exec -T postgres pg_dump -U n8n_db_user n8n_database > ~/n8n-docker/backup_$(date +%Y%m%d).sql
# 2. Archive user binary data directory
tar -czf ~/n8n-docker/n8n_data_$(date +%Y%m%d).tar.gz -C ~/n8n-docker data
Manual PostgreSQL Restore Procedure
To restore a PostgreSQL database backup file into your running container:
cat ~/n8n-docker/backup_20260813.sql | docker compose exec -T postgres psql -U n8n_db_user -d n8n_database
Restore Notes:
- Ensure
n8n_db_userandn8n_databasematch your.envconfiguration. - Restoring a backup overwrites existing database data. Test restores periodically in a separate development/test environment before executing on production.
Automated Daily Cron Backup Script
Create an automated backup script ~/n8n-docker/backup.sh:
nano ~/n8n-docker/backup.sh
Paste this backup and retention script:
#!/bin/bash
BACKUP_DIR="$HOME/n8n-docker/backups"
DATE=$(date +%Y%m%d_%H%M%S)
mkdir -p "$BACKUP_DIR"
# 1. Dump PostgreSQL database
docker compose -f "$HOME/n8n-docker/docker-compose.yml" exec -T postgres pg_dump -U n8n_db_user n8n_database > "$BACKUP_DIR/db_$DATE.sql"
# 2. Archive binary data directory
tar -czf "$BACKUP_DIR/data_$DATE.tar.gz" -C "$HOME/n8n-docker" data
# 3. Prune local backups older than 7 days
find "$BACKUP_DIR" -type f -mtime +7 -delete
Make the script executable and schedule it to run daily at 2:00 AM via crontab:
chmod +x ~/n8n-docker/backup.sh
(crontab -l 2>/dev/null; echo "0 2 * * * /bin/bash $HOME/n8n-docker/backup.sh") | crontab -
IMPORTANTDisaster Recovery & Off-Site Retention: Storing backups on the same VPS server only protects against software corruption. For true disaster recovery (server crash, provider outage, disk failure), automatically sync backup archives to an off-site location (e.g. AWS S3, Backblaze B2, or a remote rsync target).
Safe Upgrade & Maintenance Workflow
To update n8n safely without risking downtime or data loss:
- Create Backups: Run
pg_dumpand archive yourdatafolder. - Review Changelog: Check the official n8n release notes for breaking changes.
- Pull New Images: Fetch updated Docker images:
docker compose pull
- Recreate Containers: Restart the stack to apply new images:
docker compose up -d
(Note: docker compose pull downloads updated image layers, while docker compose up -d recreates the container with the new image. They are two separate operations).
5. Verify Health: Inspect logs using docker compose logs -f n8n and test your workflows in the UI.
CAUTIONAvoid Destructive Commands: Never run
docker compose down -von a production server. The-vflag deletes named Docker volumes, destroying your PostgreSQL database and persistent n8n data.
Importing External NPM Packages in Code Nodes
By default, n8n sandboxes JavaScript Code nodes. Setting NODE_FUNCTION_ALLOW_EXTERNAL=axios,lodash in .env allows those packages to be imported in Code nodes only if they are installed in the container runtime.
Setting the environment variable does not install packages automatically. To install custom npm packages, build a custom Dockerfile:
FROM docker.n8n.io/n8nio/n8n:latest
USER root
RUN cd /usr/local/lib/node_modules/n8n && npm install axios lodash
USER node
Warning: Do not manually npm install inside a running container via docker exec. Those changes will disappear as soon as the container is recreated during updates.
Troubleshooting Common Setup Issues
Useful Diagnostic Commands
- Check Container Status:
docker compose ps
- Inspect Container Logs:
docker compose logs -f n8n
docker compose logs -f caddy
docker compose logs -f postgres
- Verify DNS Resolution:
dig automation.yourdomain.com
# or: nslookup automation.yourdomain.com
1. 502 Bad Gateway Error from Caddy
- Symptom: Visiting your domain returns a
502 Bad Gatewayerror page. - Potential Causes & Fixes:
- n8n Still Booting: n8n takes 15–30 seconds to run database migrations on startup. Check logs with
docker compose logs -f n8n. - Database Connection Failure: If n8n restarts continuously, check that
POSTGRES_USER,POSTGRES_PASSWORD, andPOSTGRES_DBmatch between.envanddocker-compose.yml. - Docker Network Mismatch: Ensure Caddy and n8n are running in the same Docker Compose stack.
- Wrong Reverse Proxy Target: Ensure
Caddyfileproxies ton8n:5678.
- n8n Still Booting: n8n takes 15–30 seconds to run database migrations on startup. Check logs with
2. Out of Memory (OOM) Container Crashes
- Symptom: n8n stops unexpectedly when processing large datasets or AI workflows on a 1 GB VPS.
- Fix: Enable a 2 GB Linux swap file to absorb RAM spikes:
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
3. Webhook URL Mismatches & Mixed Content Warnings
- Symptom: Webhooks generated inside n8n default to
http://instead ofhttps://. - Fix: Confirm
WEBHOOK_URL=https://automation.yourdomain.comis set in.envwithout a trailing slash, then restart containers:
docker compose up -d
Don’t Want to Manage Infrastructure? (Managed Option)
Self-hosting n8n requires managing server security, UFW firewalls, Docker Compose stacks, Let’s Encrypt SSL renewals, PostgreSQL backups, and resource monitoring.
If you prefer a managed option without maintaining underlying Linux servers, you can host n8n using SiliconPin n8n Cloud Hosting. Powered by rootless SiliconPin Pods, it provides dedicated multi-threaded execution, managed PostgreSQL sidecars, automatic SSL, and instant snapshot backups (sp backup).
Quick Deployment via sp CLI:
# 1. Install sp CLI & authenticate
curl -fsSL https://siliconpin.com/downloads/sp/install.sh | bash
sp login --token=$SP_TOKEN
# 2. Deploy n8n pod & attach PostgreSQL sidecar
sp deploy --name=<application-name> --port=5678
sp deployments attach db postgresql <deployment-id>
# 3. Configure environment variables
sp env set N8N_ENCRYPTION_KEY=your_generated_encryption_key_here
sp env set WEBHOOK_URL=https://n8n-app.yourname.sp.net
sp env set GENERIC_TIMEZONE=UTC
# 4. Optional: Snapshot backups & local HTTPS tunneling
sp backup <deployment-id>
sp tunnel 5678
Frequently Asked Questions (FAQ)
Q: Can I use n8n for free?
A: Yes! Under n8n’s Sustainable Use License (Fair-Code model), self-hosting n8n is 100% free for personal use, internal business automation, and custom workflow testing. You only pay for your own VPS hosting infrastructure. (A paid commercial license is only required if you resell n8n as a paid white-label managed service to external clients).
Q: What is Docker Compose and why is it used for n8n?
A: Docker Compose is an orchestration tool for defining and running multi-container Docker applications. Instead of running complex separate commands for n8n, PostgreSQL, and Caddy, Docker Compose lets you define all services, environment variables, networks, and persistent volumes in a single docker-compose.yml file and launch everything using docker compose up -d.
Q: What are AI agent nodes in n8n and how do they work?
A: AI agent nodes in n8n leverage the LangChain framework to build autonomous AI agents. An AI Agent Node serves as the reasoning engine connected to sub-nodes: Language Models (OpenAI, Anthropic, local Ollama), Memory (Window Buffer or Postgres Chat Memory), and Tools (PostgreSQL queries, Slack, HTTP API calls, Vector store RAG retrieval).
Q: What are the limitations of using SQLite with n8n in production?
A: SQLite is convenient for local testing, but PostgreSQL is generally the better choice for production workloads due to:
- Single-Writer File Locking: SQLite locks the entire database file during writes, causing
SQLITE_BUSY: database is lockederrors under concurrent webhooks. - No Multi-Worker Queue Mode Scaling: SQLite files cannot be shared across multiple container workers.
- Database Corruption Risks: Host crashes or disk space exhaustion during a write operation can corrupt
.n8n/database.sqlite. - Performance Degradation: As execution logs grow past tens of thousands of records, SQLite write speeds drop significantly compared to PostgreSQL WAL.
Q: How do I scale n8n for high execution volumes?
A: For high execution volume, you can scale n8n by switching to Queue Mode:
Main n8n Engine --> Redis (Message Broker) --> Worker Containers --> PostgreSQL
Redis acts as a queue broker, distributing workflow executions across multiple worker containers. A simple single-instance Docker Compose setup is sufficient for most small to medium automation workloads.
Q: How do I set up automated backups for n8n?
A: Create an automated bash script that executes docker compose exec -T postgres pg_dump -U n8n_db_user n8n_database > db_backup.sql and archives the ~/n8n-docker/data directory into a .tar.gz file. Schedule the script to run daily at off-peak hours using Linux crontab (e.g., 0 2 * * * /bin/bash /path/to/backup.sh), with automated pruning to remove backups older than 7 days.
Q: How do I configure SMTP email in n8n for password resets?
A: Configure SMTP if you want n8n to send password-reset emails, user invitations, and workflow failure notifications. Set N8N_EMAIL_MODE=smtp, N8N_SMTP_HOST, N8N_SMTP_PORT=587, N8N_SMTP_USER, N8N_SMTP_PASS, and N8N_SMTP_SENDER in your .env file, map them into docker-compose.yml, and restart your containers (docker compose up -d).
Q: How do I create and test a webhook in n8n?
A: Open the n8n workflow canvas, add a Webhook node, and set your desired HTTP Method (GET, POST, etc.) and path slug. During workflow building, use the Test URL (/webhook-test/...) alongside the “Listen for Test Event” button to inspect incoming JSON data. Once verified, toggle the workflow switch to Active and switch your external service (Stripe, GitHub, Typeform, etc.) to use the Production URL (/webhook/...).
Q: What are the security best practices for n8n?
A: Key security best practices include:
- Binding n8n to local loopback
127.0.0.1:5678so traffic is forced through Caddy’s encrypted HTTPS proxy. - Setting
N8N_SECURE_COOKIE=trueandN8N_PROTOCOL=httpsin.env. - Configuring UFW firewall to allow only ports 22, 80, and 443.
- Running containers under non-privileged UID/GID permissions (
1000:1000). - Backing up
N8N_ENCRYPTION_KEYin a secure password manager. - Completing owner account registration immediately upon deployment.
Q: What happens if I lose my N8N_ENCRYPTION_KEY?
A: If you lose this key, n8n cannot decrypt your stored credentials (API keys, OAuth tokens, database passwords). You will have to manually re-enter credentials for all integrations. Always store your key in a password manager.
Q: How do I migrate SQLite data to PostgreSQL?
A: Configure your PostgreSQL n8n instance using the exact same N8N_ENCRYPTION_KEY as your SQLite instance. Export your workflows and credentials using the n8n UI (or via CLI n8n export:workflow and n8n export:credentials), then import them into the new PostgreSQL-backed instance.
Q: Can I use custom npm packages inside Code nodes?
A: Yes. Set NODE_FUNCTION_ALLOW_EXTERNAL=axios,lodash in your .env file and ensure those npm packages are installed inside the n8n container (typically using a custom container Dockerfile build).
Summary
Self-hosting n8n gives you total data privacy, custom flexibility, and freedom from per-execution SaaS fees. By pairing Docker Compose with PostgreSQL and Caddy, you get a secure, production-oriented automation server ready for real-world workflows.
[email protected]
Engineering, systems programming, and curated technology insights.