
Architecture, deployment, credentials and secrets, backups, monitoring, updates, and security — plus an implementation checklist you can work through.
Self-hosting n8n is a reasonable choice for a small business when data residency, credential control, or integration with private systems matters more than not having a server to look after. It is a poor choice when nobody on the team wants to own patching and backups. This guide covers what a defensible self-hosted stack looks like and what you are signing up for operationally.
Check the licensing terms for your intended use before you build. n8n is fair-code licensed under the Sustainable Use License, which permits internal business use but restricts reselling n8n itself as a service.
Should you self-host at all?
- Self-host when workflows must reach systems on a private network, when data cannot leave a jurisdiction or a VPC, or when you want full control over retention of execution data.
- Use managed hosting when your workflows only touch SaaS APIs, when nobody owns infrastructure internally, or when you are still validating whether automation is worth it.
- Hybrid is common: managed for experimentation, self-hosted once a workflow touches regulated data.
Reference architecture
A small-business stack that will not embarrass you in month six has five parts. Each exists for a specific failure you are avoiding.
- Reverse proxy with TLS (Caddy or Traefik) — terminates HTTPS, holds the certificate, and is the only thing exposed to the internet.
- n8n main process — the editor UI and API.
- Postgres — the workflow, credential, and execution store. Never run production on the default SQLite.
- Redis + at least one worker (queue mode) — so a long-running workflow cannot block the UI or other executions.
- Backups and monitoring — a scheduled encrypted database dump off-box, plus uptime and failure alerting.
Sizing
For typical SMB volumes — thousands, not millions, of executions per month — a single 2 vCPU / 4 GB instance for n8n plus a managed Postgres is usually enough. Move to multiple workers when executions queue during peaks or when a single workflow routinely runs for minutes.
Deployment: Docker Compose baseline
The compose file below is a starting point, not a copy-paste production system. Read the comments; the values you must change are the ones that determine whether your instance is safe.
services:
caddy:
image: caddy:2
restart: unless-stopped
ports: ["80:80", "443:443"]
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
postgres:
image: postgres:16
restart: unless-stopped
environment:
POSTGRES_DB: n8n
POSTGRES_USER: n8n
POSTGRES_PASSWORD_FILE: /run/secrets/pg_password
secrets: [pg_password]
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U n8n"]
interval: 10s
redis:
image: redis:7
restart: unless-stopped
n8n:
image: docker.n8n.io/n8nio/n8n:latest # pin an explicit version in production
restart: unless-stopped
depends_on: [postgres, redis]
environment:
N8N_HOST: automation.example.com
N8N_PROTOCOL: https
WEBHOOK_URL: https://automation.example.com/
N8N_PORT: 5678
DB_TYPE: postgresdb
DB_POSTGRESDB_HOST: postgres
DB_POSTGRESDB_DATABASE: n8n
DB_POSTGRESDB_USER: n8n
EXECUTIONS_MODE: queue
QUEUE_BULL_REDIS_HOST: redis
GENERIC_TIMEZONE: America/New_York
EXECUTIONS_DATA_PRUNE: "true"
EXECUTIONS_DATA_MAX_AGE: "336" # hours of execution history
N8N_DIAGNOSTICS_ENABLED: "false"
env_file: [.env.secrets] # N8N_ENCRYPTION_KEY, DB password
volumes:
- n8n_data:/home/node/.n8n
n8n-worker:
image: docker.n8n.io/n8nio/n8n:latest
restart: unless-stopped
command: worker
depends_on: [n8n]
env_file: [.env.secrets]
environment:
EXECUTIONS_MODE: queue
QUEUE_BULL_REDIS_HOST: redis
DB_TYPE: postgresdb
DB_POSTGRESDB_HOST: postgres
DB_POSTGRESDB_DATABASE: n8n
DB_POSTGRESDB_USER: n8n
volumes: { pgdata: {}, n8n_data: {}, caddy_data: {} }
secrets:
pg_password: { file: ./secrets/pg_password.txt }automation.example.com {
encode gzip
reverse_proxy n8n:5678
}Credentials and secrets
Two different things are often confused here. n8n credentials are the third-party logins your workflows use; they are stored encrypted in Postgres. The encryption key that protects them is infrastructure config and must be handled separately.
- Generate N8N_ENCRYPTION_KEY once, store it in your password manager, and never let it change silently — losing it makes every stored credential unreadable.
- Keep it out of the compose file and out of Git. Use an env file with restricted permissions, Docker secrets, or your cloud provider's secret store.
- Never paste API keys into Set nodes, code nodes, or workflow JSON. Workflow JSON gets exported, shared, and committed.
- Create least-privilege service accounts in each third-party system rather than reusing an owner login.
- Document rotation: who rotates each key, how often, and what breaks during rotation.
# generate a strong encryption key once, then store it in your password manager
openssl rand -base64 32
# keep secrets out of git and readable only by the deploy user
printf 'N8N_ENCRYPTION_KEY=%s\n' "$KEY" > .env.secrets
chmod 600 .env.secrets
echo '.env.secrets' >> .gitignoreBackups
Free 30-min audit
Want us to build this for your business?
We build n8n automations and AI agents for SMBs. Book a free 30-minute audit — we'll map your highest-ROI workflow live, no pitch.
Book a free callYour backup target is the Postgres database (workflows, credentials, executions) plus the encryption key. A database dump without the key restores workflows whose credentials cannot be decrypted, which is a bad discovery to make mid-incident.
#!/usr/bin/env bash
set -euo pipefail
STAMP=$(date -u +%Y%m%dT%H%M%SZ)
docker compose exec -T postgres pg_dump -U n8n n8n | gzip > "/tmp/n8n-$STAMP.sql.gz"
# encrypt before it leaves the box
gpg --batch --yes --encrypt --recipient ops@example.com "/tmp/n8n-$STAMP.sql.gz"
aws s3 cp "/tmp/n8n-$STAMP.sql.gz.gpg" "s3://example-backups/n8n/"
rm -f "/tmp/n8n-$STAMP.sql.gz" "/tmp/n8n-$STAMP.sql.gz.gpg"Then do the part everyone skips: restore into a scratch instance once a quarter and confirm a workflow with credentials actually runs. An untested backup is a hypothesis.
Monitoring
- Uptime — an external check against the n8n health endpoint, so you find out before your customers do.
- Workflow failures — an n8n Error Trigger workflow that posts failures to Slack, email, or your ticketing tool with the workflow name and execution URL.
- Queue depth — alert if Redis queue length stays elevated; that means workers are undersized or one workflow is stuck.
- Host basics — disk (execution history fills disks fast), memory, and CPU.
- Certificate expiry — automatic with Caddy, but still worth alerting on.
// Error Trigger workflow -> Code node -> Slack node
const e = $json;
return [{
json: {
text: [
":rotating_light: n8n workflow failed",
"*Workflow:* " + e.workflow.name,
"*Node:* " + (e.execution?.lastNodeExecuted ?? "unknown"),
"*Error:* " + (e.execution?.error?.message ?? "unknown"),
"*Execution:* " + (e.execution?.url ?? "n/a"),
].join("\n"),
},
}];Updates
Pin an explicit image version rather than latest, so a restart never becomes an unplanned upgrade. Read the release notes, back up first, update in a staging instance, then promote. Monthly is a reasonable cadence for a small business, with out-of-band updates when a security fix lands.
Security hardening
- Expose only 80/443 through the proxy; never publish 5678 directly.
- Enforce SSO or strong passwords with MFA for editor access, and remove accounts on the day people leave.
- Restrict the code node's reachable modules and treat it as production code, not a scratchpad.
- Validate and authenticate every inbound webhook — a public webhook URL is an unauthenticated write endpoint until you add a shared secret or signature check.
- Prune execution data on a schedule; stored payloads are a copy of your customer data.
- Keep the host patched, disable password SSH, and put the instance behind your firewall or a private network where possible.
A self-hosted instance is not more secure by default. It is more controllable — which only becomes security once someone exercises the control.
Implementation checklist
- Named internal owner for the instance, with a named backup person.
- DNS record and TLS via the reverse proxy; port 5678 not publicly reachable.
- Postgres in use (not SQLite), with credentials in a secret store.
- N8N_ENCRYPTION_KEY generated, stored in the password manager, and excluded from Git.
- Queue mode enabled with at least one worker.
- Nightly encrypted backups off-box, plus a quarterly restore test on the calendar.
- Execution pruning configured to a retention period you can justify.
- Error Trigger workflow routing failures to a channel a human reads.
- Uptime, disk, and queue-depth alerts configured.
- Image version pinned, with a monthly update window.
- Workflow JSON exported to Git; staging path defined for changes.
- Webhook authentication (shared secret or signature) on every inbound endpoint.
- Offboarding runbook: which accounts and keys get revoked, and by whom.
If you want the architecture without owning the pager, that is exactly what our AI automation agency engagements cover, and the automation services page breaks down what is included at each tier.
Need this built for you? We scope, build, and hand over automation systems as a done-for-you engagement — see what an AI automation agency actually delivers, the published pricing ranges, or book a 30-minute call.
Frequently asked questions
What's your AI Readiness Score?
10 questions. A personalized score, profile, and a 90-day automation roadmap built for your business. No email required.
30-minute working session
Find the highest-ROI automation in your business
Bring one workflow that is slow, repetitive, or leaking opportunities. We will map the bottleneck, the systems involved, and whether automation is actually worth implementing.
No obligation. If automation is not the right answer, we will say so.



0 Comments
Be the first to comment. Start the conversation below.