n8n auf einem 6-Dollar-Server selbst hosten
Folge dem auf deinem eigenen Server. Kostenlos starten, keine Karte nötig
Jedes Workflow-Automatisierungstool, das pro Ausführung abrechnet, macht aus “diese beiden APIs verbinden” eine laufende Kostenstelle, die mit genau der Sache wächst, über die du dir dank Automatisierung keine Gedanken mehr machen wolltest. n8n erledigt denselben Job wie Zapier oder Make, visuelle Workflows, die APIs aufrufen, ohne dass du Klebecode schreiben und pflegen musst, als Open-Source-Software, die du selbst betreibst. Am Ende dieser Anleitung läuft deine eigene n8n-Instanz auf einem 6-Dollar-Server pro Monat, erreichbar über HTTPS auf deiner eigenen Domain, gestützt auf Postgres statt einer einzelnen SQLite-Datei, mit Backups und einem Upgrade-Pfad, der dir nicht ins Bein schießt.
Was du brauchst
- Einen Server. DigitalOceans Basic Droplet für 6,00 $/Monat liefert 1 vCPU, 1 GB RAM und 25 GB SSD, was für n8n, Postgres und einen Reverse Proxy zusammen auf einer einzigen Box für persönliche Nutzung oder kleine Teams reicht. Jeder Ubuntu-24.04-VPS eines anderen Anbieters funktioniert genauso.
- Einen Domainnamen (oder eine Subdomain einer Domain, die du bereits besitzt), mit Zugriff auf die DNS-Einstellungen.
- Docker und das Docker-Compose-Plugin auf dem Server installiert (Schritt 2).
- Ein Terminal und SSH-Zugriff auf den Server.
Schritt 1: Server erstellen und eine Domain darauf zeigen lassen
Starte einen Ubuntu-24.04-Droplet im 6-Dollar-Basic-Plan von DigitalOcean (1 vCPU, 1 GB RAM, 25 GB SSD). Notiere die öffentliche IP-Adresse.
Füge in den DNS-Einstellungen deiner Domain einen A-Eintrag hinzu, der eine Subdomain, zum Beispiel n8n.deinedomain.com, auf diese IP zeigt:
Type: A
Name: n8n
Value: <IP deines Servers>
TTL: 300
Die DNS-Propagierung kann wenige Minuten bis einige Stunden dauern. Bevor du weitermachst, solltest du mit dig n8n.deinedomain.com +short die IP deines Servers zurückbekommen, da die nächsten Schritte davon abhängen.
Schritt 2: Docker installieren
Verbinde dich per SSH mit dem Server und installiere Docker Engine samt Compose-Plugin:
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
Melde dich ab und wieder an, damit die Gruppenänderung wirksam wird, und prüfe dann, ob beide Teile vorhanden sind:
docker --version
docker compose version
Du solltest eine Docker- und eine Compose-Version angezeigt bekommen, ohne “command not found”-Fehler.
Schritt 3: Projekt und seine Geheimnisse anlegen
Erstelle ein Verzeichnis für den Stack und eine .env-Datei für alles, was nicht in der Compose-Datei selbst stehen sollte:
mkdir -p ~/n8n && cd ~/n8n
Generiere einen echten Verschlüsselungsschlüssel. n8n nutzt ihn, um jedes in seiner Datenbank gespeicherte Credential zu verschlüsseln, ihn zu verlieren bedeutet also den Zugriff auf jedes gespeicherte Credential zu verlieren, nicht nur auf diese Installation:
openssl rand -base64 32
Erstelle .env mit diesem Schlüssel, deiner Domain, einer Zeitzone und einem Datenbankpasswort:
# .env
DOMAIN=n8n.deinedomain.com
GENERIC_TIMEZONE=Europe/Berlin
N8N_ENCRYPTION_KEY=<füge den gerade generierten Schlüssel ein>
POSTGRES_USER=n8n
POSTGRES_PASSWORD=<ein langes zufälliges Passwort>
POSTGRES_DB=n8n
Setze die Berechtigungen so, dass nur dein Benutzer sie lesen kann:
chmod 600 .env
Schritt 4: Docker-Compose-Datei schreiben
n8n liefert standardmäßig eine SQLite-Datenbank, was zum Ausprobieren in Ordnung ist, aber nicht für eine Instanz, die rund um die Uhr mit mehr als einer Handvoll Workflows läuft. Postgres ist die Datenbank, die n8n selbst empfiehlt, sobald man über die “nur testen”-Phase hinaus ist, deshalb nutzt dieses Setup sie von Anfang an.
Erstelle docker-compose.yml:
services:
n8n:
image: n8nio/n8n:1.68.0
restart: unless-stopped
environment:
- N8N_HOST=${DOMAIN}
- N8N_PROTOCOL=https
- N8N_PORT=5678
- N8N_WEBHOOK_URL=https://${DOMAIN}/
- N8N_PROXY_HOPS=1
- N8N_RUNNERS_ENABLED=true
- N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
- GENERIC_TIMEZONE=${GENERIC_TIMEZONE}
- 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}
volumes:
- n8n_data:/home/node/.n8n
depends_on:
postgres:
condition: service_healthy
networks:
- n8n-net
postgres:
image: postgres:16.4-alpine
restart: unless-stopped
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 -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 5s
timeout: 5s
retries: 10
networks:
- n8n-net
caddy:
image: caddy:2
restart: unless-stopped
ports:
- "80:80"
- "443:443"
environment:
- DOMAIN=${DOMAIN}
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
- caddy_config:/config
depends_on:
- n8n
networks:
- n8n-net
networks:
n8n-net:
volumes:
n8n_data:
postgres_data:
caddy_data:
caddy_config:
Ein paar Entscheidungen sind eine Erklärung wert:
- Das n8n-Image ist auf
1.68.0festgepinnt statt auflatest. Ein Automatisierungstool, das sich bei einem Serverneustart stillschweigend selbst aktualisiert und deine Workflows mit in das mitnimmt, was sich geändert hat, ist kein guter Tausch. Du upgradest nach deinem eigenen Zeitplan, siehe Schritt 7. N8N_PROXY_HOPS=1undN8N_WEBHOOK_URLsind wichtig, weil n8n hier hinter Caddy sitzt, statt direkt dem Internet zugewandt zu sein. Ohne sie kennt n8n seine eigene öffentliche HTTPS-Adresse nicht und registriert die falschen Webhook-URLs bei externen Diensten.N8N_RUNNERS_ENABLED=trueschaltet n8ns Task-Runner ein, der Code-Node-Skripte in einem isolierten Prozess ausführt statt innerhalb von n8ns eigenem Hauptprozess. Das bei einem 1.x-Release zu überspringen bedeutet, dass jedes Skript in einem Code-Node völlig ohne Isolation läuft, was in dem Moment wichtig wird, in dem du Workflows betreibst, die du nicht selbst geschrieben hast.- Nur Caddy veröffentlicht Ports zum Host. n8n und Postgres sind nur im internen Docker-Netzwerk erreichbar, nicht direkt aus dem Internet.
Schritt 5: Caddyfile schreiben und alles starten
Caddy besorgt das TLS-Zertifikat automatisch von Let’s Encrypt, solange DNS bereits auf den Server zeigt und die Ports 80 und 443 aus dem Internet erreichbar sind. Erstelle Caddyfile im selben Verzeichnis:
{$DOMAIN} {
reverse_proxy n8n:5678
}
Starte den Stack:
docker compose up -d
Beobachte den Start und prüfe, ob Caddy tatsächlich ein Zertifikat bekommen hat:
docker compose logs -f caddy
Du solltest eine Zeile sehen, die ein für deine Domain erhaltenes Zertifikat erwähnt, dann sollte der Besuch von https://n8n.deinedomain.com im Browser n8ns Einrichtungsbildschirm mit gültigem Schlosssymbol laden, ohne Zertifikatswarnung. Lege dort dein Besitzerkonto an; das ist n8ns eigener Ersteinrichtungs-Ablauf, nichts, was dieser Stack für dich konfiguriert.
Schritt 6: Workflows, Credentials und den Verschlüsselungsschlüssel sichern
Drei Dinge müssen gesichert werden: die Postgres-Datenbank (deine Workflows, Ausführungen und Credentials), das n8n_data-Volume (n8ns eigener lokaler Zustand, inklusive allem, was nicht in der Datenbank liegt), und die .env-Datei (dein Verschlüsselungsschlüssel, ohne den die Credentials in dieser Datenbank unlesbar sind).
Ein täglicher Postgres-Dump, außerhalb des Servers aufbewahrt:
docker compose exec -T postgres pg_dump -U n8n n8n > "n8n-backup-$(date +%F).sql"
Lege das in einen Cronjob und kopiere das Ergebnis irgendwohin, das nicht dieser Server ist, einen Object-Storage-Bucket, eine andere Maschine, überallhin, nur nicht auf diesen Droplet. Ein Backup, das nur auf dem Server liegt, den es sichern soll, überlebt genau den Ausfall nicht, der einen Server tatsächlich zerstört.
Für das Volume und die .env-Datei:
docker run --rm -v n8n_n8n_data:/data -v $(pwd):/backup alpine \
tar czf /backup/n8n-data-backup.tar.gz -C /data .
cp .env ~/n8n-env-backup-$(date +%F)
Bewahre dieses .env-Backup irgendwo getrennt und zugriffsbeschränkt auf; es enthält sowohl dein Datenbankpasswort als auch deinen Verschlüsselungsschlüssel.
Schritt 7: n8n ohne Überraschungen upgraden
Prüfe die Version, die du derzeit betreibst, lies n8ns Release-Notes für alles zwischen dieser Version und der, zu der du wechseln willst, und ändere dann den Tag in docker-compose.yml:
image: n8nio/n8n:1.69.0
Ziehe und starte nur diesen Dienst neu:
docker compose pull n8n
docker compose up -d n8n
n8ns Logs sollten einen sauberen Start ohne Fehler bei einer fehlgeschlagenen Datenbankmigration zeigen, und deine bisherigen Workflows sollten noch da sein, wenn du dich wieder einloggst. Falls eine Migration tatsächlich fehlschlägt, ist dein Postgres-Backup aus Schritt 6 der Weg zurück zur vorherigen Version.
Die Abkürzung: mit Railyard
Alles oben Beschriebene, ein Postgres-gestütztes n8n mit generiertem Verschlüsselungsschlüssel, einem persistenten Daten-Volume und bereits fertig eingerichtetem HTTPS, gibt es auch als Ein-Klick-Template:
https://app.railyard.run/deploy?template=n8n
Dieses Ein-Container-Template passt genau zu demselben Fall, den das manuelle Setup oben abdeckt: eine Person oder ein kleines Team, das interne Automatisierung betreibt. Wenn du das später sprengst, also genug Workflow-Volumen betreibst, dass Webhook-Zustellung und Ausführung um denselben Prozess konkurrieren, trennt n8ns eigene Queue-Mode-Architektur diese beiden Aufgaben, und das ist als separater Stack verfügbar: Wähle n8n (queue mode) im Template-Katalog statt es direkt über einen Link zu deployen, da ein Stack-Template erst die Bestätigung seiner Dienste braucht. Es betreibt n8ns Web- und Worker-Prozesse gegen ihr eigenes Postgres und ein passwortgeschütztes Redis für die Job-Queue.
Wenn du lieber erst allgemein mit Railyard anfangen möchtest, bevor du dich konkret für n8n entscheidest, deckt der Quickstart die Grundlagen ab, und Datenbanken und Backups erklärt, wie Backups über alle Templates hinweg funktionieren, nicht nur bei diesem. Deploy-Button erklärt das ?template=-Linkformat selbst, falls du einen Link anderswo einbinden willst. Für einen breiteren Vergleich, was dir ein 6-Dollar-Droplet gegenüber einer verwalteten Alternative tatsächlich bringt, siehe Hosting-Kosten.
Troubleshooting
Caddy bekommt nie ein Zertifikat, oder der Browser zeigt eine Zertifikatswarnung. Das liegt fast immer an DNS, nicht an Caddy. Führe dig n8n.deinedomain.com +short auf deiner eigenen Maschine aus und prüfe, ob die IP deines Servers zurückkommt, nicht eine alte und nicht nichts. Let’s Encrypt braucht für die anfängliche Validierung auch Port 80 erreichbar aus dem Internet, also prüfe, ob die Firewall oder Security Group deines Cloud-Anbieters eingehenden Verkehr auf 80 und 443 erlaubt, nicht nur 443.
docker compose up schlägt fehl mit “port is already allocated”. Etwas anderes auf der Box ist schon an 80 oder 443 gebunden, häufig eine standardmäßig installierte Nginx- oder Apache-Instanz. Finde es mit sudo ss -tlnp | grep -E ':80|:443' und stoppe diesen Dienst, oder ändere, welche Ports Caddy veröffentlicht, falls du wirklich beide gleichzeitig brauchst.
n8n-Logs zeigen Webhook-URLs, die auf die falsche Adresse zeigen, oder auf http statt https. Prüfe, ob N8N_HOST, N8N_PROTOCOL und N8N_WEBHOOK_URL in der Compose-Datei mit deiner echten Domain und https übereinstimmen, und dass N8N_PROXY_HOPS=1 gesetzt ist. Ohne das vertraut n8n den von Caddy gesendeten Forwarded-Headern nicht und rät stattdessen seine eigene Adresse.
Der Postgres-Container startet ständig neu, oder n8n kann sich nicht mit der Datenbank verbinden. Prüfe zuerst docker compose logs postgres auf den tatsächlichen Fehler. Ein nicht übereinstimmendes POSTGRES_PASSWORD zwischen dem Postgres-Dienst und dem DB_POSTGRESDB_PASSWORD, das n8n zum Verbinden nutzt, ist die häufigste Ursache, meist durch das Bearbeiten von .env, nachdem das Postgres-Volume schon mit dem alten Passwort initialisiert war; Postgres liest diese Umgebungsvariablen nur beim allerersten Start mit einem leeren Datenverzeichnis.
Der Container startet und beendet sich sofort wieder, oder das Volume zeigt Berechtigungsfehler. Das zeigt sich meist, wenn du ein Host-Verzeichnis statt eines benannten Docker-Volumes für /home/node/.n8n bindest. Das n8n-Image läuft als Non-Root-Benutzer, und ein von Root erstelltes Host-Verzeichnis ist für ihn nicht beschreibbar. Benannte Volumes, wie in der Compose-Datei oben verwendet, vermeiden das vollständig, weil Docker ihre Besitzrechte verwaltet.
Dem Server geht unter echter Last der Speicher aus. Ein 1-GB-Droplet, der n8n, Postgres und Caddy zusammen betreibt, hat wenig Spielraum. Füge als Puffer eine Swap-Datei hinzu (fallocate -l 2G /swapfile && chmod 600 /swapfile && mkswap /swapfile && swapon /swapfile), und wenn du Workflows betreibst, die große Payloads verarbeiten oder viele Ausführungen gleichzeitig laufen, wechsle zu einem 2-GB-Droplet, statt Swap als dauerhafte Lösung zu verwenden.
FAQ
Brauche ich Postgres, oder reicht SQLite? SQLite, n8ns Standard, funktioniert zum Ausprobieren, kommt aber mit mehr als einer Handvoll gleichzeitiger Workflows nicht gut zurecht und ist nicht das, was n8n empfiehlt, sobald eine Instanz tatsächlich gebraucht wird. Postgres von Anfang an, wie in dieser Anleitung, vermeidet eine spätere Migration.
Kann ich das ohne Domain betreiben, nur mit der IP des Servers? Caddys automatisches HTTPS braucht eine echte Domain; Let’s Encrypt stellt keine Zertifikate für bloße IP-Adressen aus. Du kannst über einfaches HTTP auf einer IP zum schnellen Testen laufen, indem du den Browser direkt auf Port 5678 richtest, aber speichere keine echten Credentials in einer Instanz, die nicht hinter HTTPS liegt.
Was kostet das tatsächlich im Betrieb? Der Server kostet 6 $/Monat. n8n selbst ist kostenlose, Open-Source-Software ohne eigene Ausführungslimits; du zahlst für die Box, auf der es läuft, nicht für das, was darauf läuft.
Was passiert mit meinen Workflows, wenn ich den Verschlüsselungsschlüssel verliere? Jedes von n8n gespeicherte Credential wird unlesbar. Die Workflow-Struktur bleibt erhalten, aber alles, was einen gespeicherten API-Key oder OAuth-Token brauchte, verlangt, dass diese Credentials neu eingegeben werden. Das ist der ganze Grund, warum Schritt 6 .env getrennt von der Datenbank sichert.
Ist das Ein-Container-Setup hier dasselbe, was Railyards n8n-Template betreibt? Fast, mit einem echten Unterschied: Railyards Template enthält standardmäßig kein Postgres, da die meisten Einzelbenutzer-Installationen es nicht von Anfang an brauchen. Die Architektur, ein n8n-Container mit generiertem Verschlüsselungsschlüssel und persistentem Daten-Volume, ist dieselbe Idee; diese Anleitung fügt Postgres hinzu, weil es der ehrlichere Standard für alles ist, das du dauerhaft betreiben willst.
Beide Wege führen am Ende zum gleichen Ergebnis: dein eigener Automatisierungsserver, deine eigenen Daten, und eine Rechnung, die sich nicht ändert, egal wie viel Arbeit deine Workflows erledigen.
Warum Leute sich dafür Railyard entscheiden
- Dein eigenes Cloud-Konto. Deploye auf DigitalOcean, Hetzner, Vultr, AWS, OVHcloud oder jedem Linux-Server per SSH, direkt von deinem Anbieter abgerechnet, ohne Aufschlag.
- Ein fester Preis pro Team. Free ist für immer kostenlos: ein Server plus ein Datenbankserver, drei Apps, keine Karte. Pro kostet 19 $ im Monat für bis zu fünf Server und unbegrenzte Apps. Team kostet 49 $ im Monat mit unbegrenzten Servern. Keine Kosten pro App, pro Deployment, pro Sitz oder pro Gigabyte.
- Templates mit einem Klick. Deploye Open-Source-Apps, wie Datenbanken, Analytics und Dev-Tools, mit einem Klick auf deinem eigenen Server.
- Verwaltete Datenbanken. Postgres, MySQL und Redis mit geplanten, wiederherstellungsgeprüften Backups und Point-in-Time-Recovery.
- Push-to-Deploy. Deploye von GitHub, GitLab oder der CLI, mit automatischem HTTPS und Releases ohne Ausfallzeit.