n8n ist eine Workflow-Automatisierung mit einer Fair-Code-Lizenz. Das bedeutet: Der Quellcode ist offen und die Plattform darf auf eigener Infrastruktur betrieben werden, solange sie nicht als Service an Dritte weiterverkauft wird. Genau darauf zielt Self-Hosting ab. Wer n8n selbst hostet, betreibt die komplette Instanz auf einer eigenen Maschine, kontrolliert die Datenhaltung und ist nicht an die Preisstaffel der Cloud-Variante gebunden.
In der Praxis heißt das: Ein Linux-Server mit Docker, eine Domain mit TLS-Zertifikat, eine Datenbank und ein sauberes Backup-Konzept. Viel mehr ist es technisch nicht. Der Teufel steckt in den Details, und genau dort entscheidet sich, ob die Instanz nach drei Monaten noch stabil läuft oder als Wartungsfall auf dem Schreibtisch landet. Einen allgemeinen Überblick, was n8n überhaupt ist, liefert unser Einsteigerartikel zu n8n.
Vor dem ersten Docker-Befehl steht die Strategiefrage. n8n Cloud ist schnell eingerichtet, kommt mit Managed Updates und skaliert per Klick. Self-Hosting erfordert Ops-Know-how, gibt aber volle Kontrolle über Daten, Kosten und Customizing.

Die Break-even-Rechnung hängt sehr stark vom eigenen Workflow-Mix ab. Eine grobe Faustregel: Ab etwa 30 gleichzeitig aktiven Workflows und ein paar hunderttausend Executions pro Monat wird Self-Hosting wirtschaftlich.
Für den Produktivbetrieb reicht eine kleine VM bei Hetzner, OVH oder einem anderen EU-Anbieter. Für die meisten mittelständischen Setups passt eine Maschine mit 2 bis 4 vCPU, 4 bis 8 GB RAM und 40 GB SSD. Das Betriebssystem sollte eine aktuelle LTS-Version sein, typischerweise Ubuntu Server 24.04 oder Debian 12.
Neben dem Server gehören drei Dinge zur Grundausstattung: Eine Domain (inklusive A-Record auf die Server-IP), ein aktueller Docker- und Docker-Compose-Stack sowie ein Backup-Ziel außerhalb der Produktions-VM. Ob der Backup-Speicher bei S3, Backblaze oder einem zweiten Rechenzentrum liegt, ist Geschmackssache. Wichtig ist nur, dass er nicht an der gleichen Maschine hängt wie die n8n-Instanz selbst.
Vor dem Deploy sollte die Maschine gehärtet werden: SSH-Keys statt Passwort, Firewall mit nur Port 22/80/443 offen, automatische Security-Updates aktiviert, Fail2ban oder CrowdSec gegen Login-Scanner. Wer das übergeht, sitzt innerhalb weniger Tage mit einer kompromittierten Instanz dort, wo der Aufwand gerade erst begonnen hat.
Der empfohlene Weg ist Docker Compose mit drei Services: n8n-Container, Postgres-Container und ein Reverse Proxy. Ein typisches Setup trennt die Services sauber, mountet die Daten in benannte Volumes und legt alle Secrets in eine .env-Datei.

N8N_HOST und WEBHOOK_URL auf die öffentliche Domain setzen. Ohne korrekten WEBHOOK_URL laufen externe Webhooks ins Leere, weil n8n in den per Mail verschickten Webhook-URLs den Hostnamen aus dieser Variable einsetzt.N8N_ENCRYPTION_KEY: der mit Abstand wichtigste Wert. n8n verschlüsselt damit alle in der Datenbank gespeicherten Credentials (API-Keys, OAuth-Tokens, Datenbank-Passwörter, SMTP-Logins). Generiert wird er einmal mit openssl rand -hex 32, dann fix in die .env und in den Passwort-Manager (separat von der Datenbank). Der Key darf sich nie ändern, solange die Datenbank lebt.DB_TYPE=postgresdb sowie die Postgres-Zugangsdaten (DB_POSTGRESDB_HOST, DB_POSTGRESDB_DATABASE, DB_POSTGRESDB_USER, DB_POSTGRESDB_PASSWORD). SQLite ist für die ersten Tests okay, aber nicht für Produktivlasten.N8N_BASIC_AUTH_ACTIVE=false nur setzen, wenn stattdessen der integrierte User-Management-Flow mit Owner-Konto genutzt wird. Sonst steht die Instanz offen.EXECUTIONS_DATA_PRUNE=true und EXECUTIONS_DATA_MAX_AGE=336 (Stunden, also 14 Tage) verhindern, dass die Datenbank durch Execution-Logs ungebremst wächst.GENERIC_TIMEZONE=Europe/Berlin und TZ=Europe/Berlin sorgen dafür, dass Cron- und Schedule-Trigger der lokalen Zeit folgen.⚠️ Was passiert, wenn der N8N_ENCRYPTION_KEY verloren geht
Wer den Key verliert (zerstörter Server ohne Backup, fauler Server-Reset, neu generierter Key beim Wiederaufsetzen), kann keine einzige Credential mehr entschlüsseln. Workflows laufen, aber jeder Schritt, der mit einem API-Login, OAuth-Token oder Datenbank-Passwort arbeitet, scheitert mit „failed to decrypt“. Es gibt keinen Recovery-Pfad, kein Re-Key-Tool, kein Master-Override. Die einzige Lösung:jede Credential einzeln neu anlegen, also bei jeder API neu authentifizieren, jedes OAuth neu durchklicken, jedes Passwort neu eintippen. Bei einer ausgewachsenen n8n-Instanz mit 30 bis 50 Credentials sind das schnell zwei Tage Arbeit. Deshalb: Key getrennt vom Server-Backup im Passwort-Manager, idealerweise auch ausgedruckt im Tresor.
Drei Services: Caddy als Reverse Proxy mit automatischem Let's Encrypt, n8n selbst, Postgres 16 als Datenbank. Alle Secrets kommen aus der .env-Datei daneben.
# docker-compose.yml
services:
caddy:
image: caddy:2
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
- caddy_config:/config
depends_on:
- n8n
n8n:
image: n8nio/n8n:latest
restart: unless-stopped
environment:
- N8N_HOST=${N8N_HOST}
- N8N_PROTOCOL=https
- N8N_PORT=5678
- WEBHOOK_URL=https://${N8N_HOST}/
- N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
- 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}
- GENERIC_TIMEZONE=Europe/Berlin
- TZ=Europe/Berlin
- EXECUTIONS_DATA_PRUNE=true
- EXECUTIONS_DATA_MAX_AGE=336
- N8N_LOG_LEVEL=info
volumes:
- n8n_data:/home/node/.n8n
depends_on:
postgres:
condition: service_healthy
postgres:
image: postgres:16
restart: unless-stopped
environment:
- POSTGRES_DB=${POSTGRES_DB}
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 5s
timeout: 5s
retries: 10
volumes:
caddy_data:
caddy_config:
n8n_data:
postgres_data:Diese Datei landet nie im Git-Repo. Berechtigung auf chmod 600, Eigentümer Root.
# .env
N8N_HOST=n8n.example.com
# Mit `openssl rand -hex 32` einmalig generiert, NIE ändern:
N8N_ENCRYPTION_KEY=ersetze-mich-durch-32-byte-hex
POSTGRES_DB=n8n
POSTGRES_USER=n8n
POSTGRES_PASSWORD=ersetze-mich-durch-starkes-passwortEntscheidend für ein späteres Restore sind zwei Volumes: Das n8n-Volume mit den Workflow-Definitionen und das Postgres-Volume mit den Execution-Daten. Beide müssen ins Backup. Ein Snapshot der gesamten VM ist bequem, ersetzt aber kein datenbankkonsistentes Backup, weil während des Snapshots laufende Transaktionen abgeschnitten werden können.
Für Testinstallationen reicht SQLite, und ohne zusätzliche Konfiguration startet n8n genau damit. Für den Produktivbetrieb ist Postgres die klar bessere Wahl. Postgres skaliert besser mit vielen Executions, erlaubt parallele Writes und lässt sich mit pg_dump sauber sichern. SQLite dagegen serialisiert Writes und wird bei wachsender Last schnell zum Flaschenhals.
Wer auf Postgres umsteigt, sollte von Anfang an saubere Connection-Limits setzen und die Postgres-Version mit den offiziellen Docker-Images pinnen (derzeit stabil: Postgres 16). Auto-Updates auf Major-Versionen sind gefährlich, weil n8n gezielt mit bestimmten Postgres-Features getestet wird. Minor-Updates per Watchtower sind dagegen unkritisch.
Eine häufige Falle: Die Retention-Policy für Execution-Daten wird nicht gesetzt und die Datenbank wächst monatelang ungebremst. Über die Environment-Variablen EXECUTIONS_DATA_PRUNE=true und EXECUTIONS_DATA_MAX_AGE lassen sich alte Executions automatisch löschen. Ohne diese Werte sitzt man nach sechs Monaten auf einer 50-GB-Datenbank voller irrelevanter Logs.
n8n direkt am Port 5678 ins Internet zu stellen, ist keine gute Idee. Der korrekte Weg führt über einen Reverse Proxy, der TLS-Zertifikate verwaltet, Requests weiterreicht und als zusätzliche Sicherheitsschicht dient. Drei Kandidaten haben sich bewährt:
Unabhängig vom Proxy sollten zusätzlich Security-Header gesetzt werden, speziell HSTS, X-Frame-Options und eine sinnvolle Content-Security-Policy. Die konkreten Angriffsszenarien und Härtungsmaßnahmen, inklusive der kritischen CVE-Welle aus dem Winter 2025/2026, haben wir im Beitrag zur n8n-Sicherheit beim Self-Hosting im Detail behandelt.
Caddy holt sich Let's-Encrypt-Zertifikate vollautomatisch, erneuert sie selbst und leitet HTTP auf HTTPS um. Diese Konfiguration packt zusätzlich die wichtigsten Security-Header dazu.
# Caddyfile
{
email admin@example.com
}
n8n.example.com {
reverse_proxy n8n:5678 {
# WebSocket-Support für n8n-Editor und Live-Logs
flush_interval -1
}
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
X-Content-Type-Options "nosniff"
X-Frame-Options "SAMEORIGIN"
Referrer-Policy "strict-origin-when-cross-origin"
Permissions-Policy "camera=(), microphone=(), geolocation=()"
-Server
}
# Optional: Bots, die nichts auf der Instanz zu suchen haben, früh abweisen
@bots header_regexp User-Agent "(?i)(crawler|spider|bot)"
respond @bots 403
encode zstd gzip
}Wichtig: Die WEBHOOK_URL in der n8n-Compose muss exakt mit dem Caddy-Hostnamen übereinstimmen, sonst weichen die Webhook-URLs in Test- und Live-Modus voneinander ab.
Ein Backup, das nicht getestet wurde, ist kein Backup. Das gilt für n8n doppelt, weil die Workflow-Definitionen, die Credentials und die Execution-History in unterschiedlichen Stellen liegen. Empfehlenswert ist eine tägliche Routine aus pg_dump für die Postgres-Datenbank plus rsync des n8n-Volumes. Beide Artefakte gehen verschlüsselt auf den externen Backup-Speicher. Ein Restore-Test einmal im Quartal deckt Überraschungen auf, bevor sie im Ernstfall weh tun.

Das folgende Skript läuft auf dem Docker-Host (nicht im n8n-Container), zieht einen sauberen pg_dump direkt aus dem Postgres-Container, sichert das n8n-Volume mit allen Workflow-Definitionen und tagged das Ganze mit Zeitstempel.
#!/usr/bin/env bash
# /opt/n8n/backup.sh — täglich per Cron, z.B. 0 2 * * *
set -euo pipefail
STACK_DIR="/opt/n8n"
BACKUP_DIR="/var/backups/n8n"
TS="$(date +%F_%H-%M)"
KEEP_DAYS=14
cd "$STACK_DIR"
mkdir -p "$BACKUP_DIR"
# 1) Postgres-Dump aus dem laufenden Container (konsistent, keine Downtime)
docker compose exec -T postgres \
pg_dump -U "$POSTGRES_USER" -d "$POSTGRES_DB" \
--no-owner --clean --if-exists \
| gzip -9 > "$BACKUP_DIR/n8n-db-$TS.sql.gz"
# 2) n8n-Volume (Workflows, Custom Nodes, Logs)
docker run --rm \
-v n8n_data:/source:ro \
-v "$BACKUP_DIR":/target \
alpine \
tar czf "/target/n8n-volume-$TS.tar.gz" -C /source .
# 3) Old backups aufräumen
find "$BACKUP_DIR" -name "n8n-*" -mtime +$KEEP_DAYS -delete
# 4) Optional: verschlüsselt nach S3-kompatiblem Storage hochladen
# rclone copy "$BACKUP_DIR" remote-s3:n8n-backups/$(hostname) \
# --include "n8n-*-$TS.*"
echo "Backup OK: $TS"Wichtig: Die POSTGRES_USER- und POSTGRES_DB-Variablen werden über die Cron-Umgebung oder einen source /opt/n8n/.env am Skript-Anfang eingelesen. Eintragen in die Crontab am einfachsten über crontab -e als Root.
Restore ist der Punkt, an dem Backups beweisen müssen, dass sie echt sind. Routine: einmal pro Quartal in einer frischen VM komplett durchspielen, vom leeren Docker bis zum laufenden n8n. Das deckt fehlende Files, falsche Postgres-Versionen und vor allem den Encryption-Key-Loss vor dem Ernstfall auf.
#!/usr/bin/env bash
# /opt/n8n/restore.sh — Restore von Datum: ./restore.sh 2026-04-30_02-00
set -euo pipefail
if [ -z "${1:-}" ]; then
echo "Usage: $0 <YYYY-MM-DD_HH-MM>"
exit 1
fi
TS="$1"
STACK_DIR="/opt/n8n"
BACKUP_DIR="/var/backups/n8n"
DB_FILE="$BACKUP_DIR/n8n-db-$TS.sql.gz"
VOL_FILE="$BACKUP_DIR/n8n-volume-$TS.tar.gz"
[ -f "$DB_FILE" ] || { echo "Missing: $DB_FILE"; exit 1; }
[ -f "$VOL_FILE" ] || { echo "Missing: $VOL_FILE"; exit 1; }
cd "$STACK_DIR"
# 1) Stack stoppen, damit nichts in die DB schreibt
docker compose stop n8n
# 2) DB wiederherstellen (Postgres bleibt up, n8n ist gestoppt)
gunzip -c "$DB_FILE" \
| docker compose exec -T postgres \
psql -U "$POSTGRES_USER" -d "$POSTGRES_DB"
# 3) n8n-Volume austauschen (Inhalt löschen, neu entpacken)
docker run --rm \
-v n8n_data:/target \
-v "$BACKUP_DIR":/source:ro \
alpine \
sh -c "rm -rf /target/* /target/.[!.]* && tar xzf /source/n8n-volume-$TS.tar.gz -C /target"
# 4) Stack wieder starten
docker compose up -d n8n
echo "Restore OK: $TS"
echo "Prüfen: Login, Credentials, ein Workflow manuell ausführen."Nach jedem Restore sollte man unbedingt einen Workflow mit externer Credential manuell ausführen, um zu verifizieren, dass der Encryption-Key noch passt. Wenn dort „failed to decrypt“ auftaucht, hat der wiederhergestellte Stack einen anderen Encryption-Key als die Datenbank, und die Credentials sind effektiv unbrauchbar.
n8n veröffentlicht fast wöchentlich Releases, und viele davon enthalten Security-Fixes. Eine gute Strategie: Minor-Versionen werden automatisch per Watchtower aktualisiert, Major-Versionen werden im Staging-Compose-Stack manuell durchgespielt. So läuft Produktion nie auf Versionen, die noch niemand im eigenen Kontext gesehen hat. Wer die Security-Updates ignoriert, läuft Gefahr, Teil der Zerobot-Botnet-Statistik zu werden, die im März 2026 über hunderttausend verwundbare Instanzen aufgedeckt hat.
Im Produktivbetrieb reicht ein reines Uptime-Monitoring nicht. Interessant sind vier Metriken: Erreichbarkeit der öffentlichen URL, Latenz des Webhook-Endpoints, Füllstand der Postgres-Partition und Erfolgsquote der letzten 1.000 Executions. Diese Werte lassen sich mit Uptime-Kuma, Grafana oder einfach einem kleinen Statuspage-Service einsammeln.
Dazu kommt ein Blick auf die n8n-eigenen Logs. Ein immer wieder fehlgeschlagener Workflow ist entweder ein Bug im Workflow oder ein Symptom für Probleme im angebundenen System. Beides sollte innerhalb weniger Stunden sichtbar werden und nicht erst, wenn ein Kunde eine fehlende Antwort meldet. Für größere Setups lohnt sich ein zentrales Log-Aggregat mit Loki oder einem Managed Service.
Wer den gesamten Betrieb nicht selbst stemmen will, findet mit unserem Managed-n8n-Hosting eine Alternative, bei der Server-Härtung, Monitoring und Updates extern laufen, die Daten aber in einem deutschen Rechenzentrum bleiben.
Self-Hosting von n8n ist technisch kein Hexenwerk. Docker Compose, Postgres, ein Reverse Proxy, ein Backup-Plan, das war es im Kern. Der eigentliche Aufwand liegt im Betrieb: Updates fahren, Security-Fixes einspielen, Backups testen, Monitoring auswerten. Wer diese Routine in den Alltag integriert, bekommt eine Plattform, die vom Lieferantenworkflow bis zum ERP-Integrationslayer alles abdeckt, ohne monatliche Lizenzgebühren und ohne Kompromisse bei der Datenhoheit.
Zwei Fehler sind die teuersten: Kein Backup-Plan und kein Update-Rhythmus. Beide lassen sich mit klaren Routinen vermeiden. Der Rest ist Handwerk.
Ihr überlegt, n8n im eigenen Rechenzentrum oder bei einem deutschen Cloud-Anbieter laufen zu lassen? Sprecht uns an, und wir gehen mit euch die Architektur durch.