n8n self-hosten: Hetzner/Contabo Setup mit Docker, HTTPS, Backup & Updates

    Dieses Tutorial zeigt ein produktionsnahes Setup: Ubuntu VPS (Hetzner oder Contabo), Docker Compose, Postgres, Reverse Proxy (Traefik) mit TLS/Let's Encrypt, sowie eine pragmatische Backup- und Update-Strategie. Dazu ordne ich n8n als Systemklasse ein: Workflow-Automatisierung / leichtgewichtiges iPaaS.

    Einordnung: n8n als Workflow-Automatisierung / iPaaS

    Was n8n typischerweise leistet

    • Systeme verbinden (API, Webhooks, Datenbanken, SaaS-Tools)
    • Daten transformieren und anreichern
    • Workflows orchestrieren (Trigger Schritte Fehlerpfade)
    • Reprocessing/Monitoring über ergänzende Patterns (wichtig für Run)

    Wenn du viele Systeme zusammenbringst (ERP, PIM, CRM, Shop), ist iPaaS oft der \u201eKlebstoff\u201c. Siehe auch: iPaaS Beratung

    SaaS vs Self-Hosting (kurz)

    Warum self-hosten?

    • Datenhoheit (Credentials/Workflows intern kontrollieren)
    • Kostenkontrolle bei vielen Runs
    • Flexibilität (Reverse Proxy, Netzwerk, Custom Nodes)

    Wann besser SaaS?

    • Kein Betriebsteam/keine Zeit für Updates/Backups/Monitoring
    • Hohe Compliance-Anforderungen ohne Infrastruktur-Reife
    • Sehr kurze Time-to-Value ohne Ops-Aufwand

    Voraussetzungen (Checkliste)

    Das Setup ist identisch für Hetzner/Contabo. Unterschiede liegen eher in UI/Provisioning – nicht in Docker.

    • VPS (2 vCPU / 4 GB RAM) + 40–80 GB SSD (Startpunkt; Workload kann mehr brauchen)
    • Ubuntu 22.04/24.04 LTS
    • Domain/Subdomain (z.B. n8n.deinefirma.de) DNS A-Record auf VPS IP
    • SSH Key Login (empfohlen) + Firewall (UFW) nur 22/80/443
    • Docker + Docker Compose
    • Persistente Volumes (n8n Daten + Postgres) + Backup Plan

    Domain-Tipp: Lege eine Subdomain an (z.B. n8n.deinefirma.de) und setze einen DNS A-Record auf die VPS IP. Let's Encrypt kann dann automatisiert Zertifikate ausstellen.

    1) Server vorbereiten (Ubuntu, Firewall, Docker)

    Ubuntu aktualisieren + Basis-Tools

    sudo apt update && sudo apt -y upgrade
    sudo apt -y install ca-certificates curl gnupg ufw git

    Firewall (UFW) – nur SSH + HTTP/HTTPS

    # SSH (22) – optional: nur von deiner IP erlauben
    sudo ufw allow 22/tcp
    
    # Web
    sudo ufw allow 80/tcp
    sudo ufw allow 443/tcp
    
    sudo ufw enable
    sudo ufw status

    Docker installieren (Ubuntu)

    # Docker Repo
    sudo install -m 0755 -d /etc/apt/keyrings
    curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
    sudo chmod a+r /etc/apt/keyrings/docker.gpg
    
    echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
    $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
    
    sudo apt update
    sudo apt -y install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
    
    # User in docker group (danach neu einloggen)
    sudo usermod -aG docker $USER

    Security-Basics (Minimum)

    • Root-Login per SSH deaktivieren oder nur via Key (kein Passwort)
    • UFW: nur Ports 22 (optional IP-restricted), 80, 443
    • Fail2ban (optional) + SSH auf non-standard Port ist kein echter Schutz, aber kann Noise reduzieren
    • Secrets nie im Repo; .env nur auf Server, Rechte restriktiv setzen
    • n8n UI nicht offen ins Internet ohne Auth (Basic Auth oder SSO via Reverse Proxy)
    • Regelmäßige Updates (Docker Images) + Reboots/Kernel Updates einplanen

    2) Docker Compose: n8n + Postgres + Traefik (TLS)

    Dieses Setup nutzt Traefik als Reverse Proxy (HTTPS via Let's Encrypt) und Postgres als Datenbank. n8n-Daten bleiben persistent in Volumes.

    Empfehlung: Lege ein Verzeichnis an, z.B. /opt/n8n. Dort liegen docker-compose.yml und .env.

    Verzeichnis + .env anlegen

    sudo mkdir -p /opt/n8n
    sudo chown -R $USER:$USER /opt/n8n
    cd /opt/n8n
    
    # .env erstellen
    cat > .env <<'EOF'
    # Domain
    N8N_HOST=n8n.deinefirma.de
    N8N_PORT=5678
    
    # Timezone
    TZ=Europe/Berlin
    
    # n8n security
    N8N_ENCRYPTION_KEY=BITTE_EINEN_LANGEN_RANDOM_KEY_SETZEN
    N8N_BASIC_AUTH_ACTIVE=true
    N8N_BASIC_AUTH_USER=admin
    N8N_BASIC_AUTH_PASSWORD=BITTE_STARKES_PASSWORT_SETZEN
    
    # Postgres
    POSTGRES_DB=n8n
    POSTGRES_USER=n8n
    POSTGRES_PASSWORD=BITTE_STARKES_DB_PASSWORT_SETZEN
    
    # Traefik / Let's Encrypt
    LE_EMAIL=admin@deinefirma.de
    EOF
    
    chmod 600 .env

    docker-compose.yml (Traefik + Postgres + n8n)

    services:
      traefik:
        image: traefik:v3.1
        container_name: traefik
        restart: unless-stopped
        command:
          - "--api.dashboard=false"
          - "--providers.docker=true"
          - "--providers.docker.exposedbydefault=false"
          - "--entrypoints.web.address=:80"
          - "--entrypoints.websecure.address=:443"
          - "--certificatesresolvers.le.acme.httpchallenge=true"
          - "--certificatesresolvers.le.acme.httpchallenge.entrypoint=web"
          - "--certificatesresolvers.le.acme.email=${LE_EMAIL}"
          - "--certificatesresolvers.le.acme.storage=/letsencrypt/acme.json"
        ports:
          - "80:80"
          - "443:443"
        volumes:
          - "/var/run/docker.sock:/var/run/docker.sock:ro"
          - "letsencrypt:/letsencrypt"
        networks:
          - web
    
      postgres:
        image: postgres:16
        container_name: n8n-postgres
        restart: unless-stopped
        environment:
          - POSTGRES_DB=${POSTGRES_DB}
          - POSTGRES_USER=${POSTGRES_USER}
          - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
          - TZ=${TZ}
        volumes:
          - postgres_data:/var/lib/postgresql/data
        networks:
          - internal
    
      n8n:
        image: n8nio/n8n:latest
        container_name: n8n
        restart: unless-stopped
        environment:
          - N8N_HOST=${N8N_HOST}
          - N8N_PORT=${N8N_PORT}
          - N8N_PROTOCOL=https
          - WEBHOOK_URL=https://${N8N_HOST}/
          - GENERIC_TIMEZONE=${TZ}
          - TZ=${TZ}
          - N8N_BASIC_AUTH_ACTIVE=${N8N_BASIC_AUTH_ACTIVE}
          - N8N_BASIC_AUTH_USER=${N8N_BASIC_AUTH_USER}
          - N8N_BASIC_AUTH_PASSWORD=${N8N_BASIC_AUTH_PASSWORD}
          - 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}
          - N8N_LOG_LEVEL=info
        depends_on:
          - postgres
          - traefik
        networks:
          - web
          - internal
        labels:
          - "traefik.enable=true"
          - "traefik.http.routers.n8n.rule=Host("${N8N_HOST}")"
          - "traefik.http.routers.n8n.entrypoints=websecure"
          - "traefik.http.routers.n8n.tls=true"
          - "traefik.http.routers.n8n.tls.certresolver=le"
          - "traefik.http.services.n8n.loadbalancer.server.port=5678"
          - "traefik.http.routers.n8n-http.rule=Host("${N8N_HOST}")"
          - "traefik.http.routers.n8n-http.entrypoints=web"
          - "traefik.http.routers.n8n-http.middlewares=redirect-to-https"
          - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
    
    volumes:
      postgres_data:
      letsencrypt:
    
    networks:
      web:
      internal:

    Starten + Logs prüfen

    cd /opt/n8n
    docker compose up -d
    docker compose ps
    docker logs -f traefik
    # n8n logs (in separatem Terminal)
    docker logs -f n8n

    Wenn DNS korrekt gesetzt ist, sollte Traefik automatisch ein Let's-Encrypt Zertifikat holen. Danach erreichst du n8n unter https://n8n.deinefirma.de.

    3) Backup-Strategie (Postgres + Volumes) – pragmatisch

    Backups sind nur dann wertvoll, wenn du Wiederherstellung getestet hast.

    Backup-Skript (DB-Dump) – /opt/n8n/backup.sh

    #!/usr/bin/env bash
    set -euo pipefail
    
    TS=$(date +"%Y-%m-%d_%H-%M-%S")
    BACKUP_DIR="/opt/n8n/backups"
    mkdir -p "$BACKUP_DIR"
    
    set -a
    source /opt/n8n/.env
    set +a
    
    docker exec -t n8n-postgres pg_dump -U "$POSTGRES_USER" -d "$POSTGRES_DB" > "$BACKUP_DIR/postgres_${TS}.sql"
    gzip -f "$BACKUP_DIR/postgres_${TS}.sql"
    ls -1t "$BACKUP_DIR"/postgres_*.sql.gz | tail -n +15 | xargs -r rm --
    
    echo "Backup done: $BACKUP_DIR/postgres_${TS}.sql.gz"

    Cronjob (täglich 02:15)

    crontab -e
    # hinzufügen:
    15 2 * * * /opt/n8n/backup.sh >/dev/null 2>&1

    Empfohlene Ergänzungen

    • Backups offsite speichern (S3, Storage Box, anderer Server) – sonst schützt es nicht gegen Serververlust.
    • Restore-Test: mindestens 1× pro Quartal in einer Testumgebung.
    • Monitoring: Backup-Laufzeit/Erfolg als Health Check.

    Restore (Beispiel)

    # Dump entpacken
    gunzip -c /opt/n8n/backups/postgres_YYYY-MM-DD_HH-MM-SS.sql.gz > /opt/n8n/restore.sql
    
    # in Container kopieren
    docker cp /opt/n8n/restore.sql n8n-postgres:/restore.sql
    
    # restore (Achtung: überschreibt Inhalte)
    docker exec -i n8n-postgres psql -U n8n -d n8n -f /restore.sql

    4) Updates & Betrieb (Run)

    Für produktive Automatisierung ist Betrieb kein Nachgedanke.

    Update (Docker Images aktualisieren)

    cd /opt/n8n
    docker compose pull
    docker compose up -d
    docker compose ps

    Monitoring (Minimum)

    • Uptime Check (HTTPS Endpoint) + Alert
    • Disk/CPU/RAM Monitoring (VPS)
    • Traefik/n8n Logs bei Fehlerfällen
    • Fehlerpfade in Workflows: Dead-letter Pattern / Retry-Logik

    Für Integrations-Patterns siehe: ERP–PIM Integration Use Case

    Praxis-Tipp: Reprocessing-Pattern

    • Fehlerdaten in separatem Store (DB/Queue/Sheet) ablegen
    • Workflows idempotent designen (Upsert statt Create)
    • Retries begrenzen + Alerts ab Schwelle
    • Runbook: wer macht was bei Incident?

    Wenn du Beratungsperspektive willst: Workflow Automatisierung Beratung

    Troubleshooting (häufige Probleme)

    Let's Encrypt holt kein Zertifikat

    • DNS A-Record zeigt wirklich auf die VPS IP?
    • Ports 80/443 offen (UFW/Sicherheitsgruppe)?
    • Domain bereits auf anderem Server mit Redirect?
    • Traefik Logs prüfen: docker logs -f traefik

    n8n startet, aber Webhooks funktionieren nicht

    • WEBHOOK_URL korrekt auf HTTPS-URL gesetzt?
    • Reverse Proxy Header/Proto korrekt (hier via Traefik ok)?
    • Wenn hinter weiterer Proxy-Schicht: X-Forwarded-* prüfen.

    Performance/Timeouts bei großen Runs

    • VPS Ressourcen (RAM) erhöhen
    • Workflows chunking/pagination (nicht 50k Datensätze in einem Schritt)
    • Retries/Backoff, Rate Limits berücksichtigen
    • DB-Performance prüfen, Logs beobachten

    Häufige Fragen

    Erstberatung: n8n/iPaaS Setup, Betrieb & Integrationsdesign (vendor-neutral)

    Wenn du n8n produktiv einsetzen willst (ERP/PIM/CRM/Shop), ist nicht nur das Setup entscheidend, sondern auch Betriebsfähigkeit: Fehlerpfade, Reprocessing, Monitoring, Datenhoheit, Idempotenz und TCO.