n8n im Queue-Modus mit Redis, PostgreSQL-Persistenz und sauberem Prozess-Supervising — das unspektakuläre, zuverlässige Setup, das Neustarts und Lastspitzen übersteht. Die Automatisierungsschicht hint
Wenn ein Knoten nicht reicht: SeaweedFS liefert verteilten, replizierten S3-Speicher mit Master/Filer/Volume-Architektur — ideal als Backup-Ziel im größeren Maßstab auf Standard-Hardware.
Die zwei Services, die fast jede Anwendung braucht — getunt statt default: PostgreSQL produktionskonfiguriert (Shared Buffers, WAL-Kompression), Redis mit AOF- und RDB-Persistenz sowie ein geplanter Backup-Job mit Retention.
Ein Deployment-Guide mit lauffähigen Beispielen — kein herunterladbares Produkt. Alles unten ist die tatsächlich eingesetzte Konfiguration, gekürzt auf das, worauf es ankommt.
services:
postgres:
image: postgres:${POSTGRES_VERSION:-16-alpine}
container_name: db-postgres
restart: unless-stopped
volumes:
- postgres_data:/var/lib/postgresql/data
- ./config/postgres/postgresql.conf:/etc/postgresql/postgresql.conf:ro
- ./config/postgres/init:/docker-entrypoint-initdb.d:ro
- backup_data:/backups
environment:
- POSTGRES_USER=${POSTGRES_USER:-app}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}
- POSTGRES_DB=${POSTGRES_DB:-app}
- PGDATA=/var/lib/postgresql/data/pgdata
ports:
- ${POSTGRES_PORT:-5432}:5432
command:
- postgres
- -c
- config_file=/etc/postgresql/postgresql.conf
healthcheck:
test:
- CMD-SHELL
- pg_isready -U ${POSTGRES_USER:-app}
interval: 15s
timeout: 5s
retries: 5
networks:
- db_network
redis:
image: redis:${REDIS_VERSION:-7-alpine}
container_name: db-redis
restart: unless-stopped
command:
- redis-server
- --appendonly
- "yes"
- --appendfsync
- everysec
- --requirepass
- ${REDIS_PASSWORD:?REDIS_PASSWORD is required}
- --maxmemory
- ${REDIS_MAX_MEMORY:-512mb}
- --maxmemory-policy
- allkeys-lru
- --save
- 900 1
- --save
- 300 10
- --save
- 60 10000
volumes:
- redis_data:/data
ports:
- ${REDIS_PORT:-6379}:6379
healthcheck:
test:
- CMD
- redis-cli
- --raw
- incr
- ping
interval: 15s
timeout: 5s
retries: 5
networks:
- db_network
Auszug — postgres, redis aus der Compose-Datei. Die übrigen Services (proxies, init jobs, exporters) folgen demselben Muster und binden ihre Konfiguration aus einem config/-Verzeichnis ein.
Kopieren Sie .env.example zu .env und setzen Sie mindestens:
POSTGRES_VERSION=16-alpine
POSTGRES_USER=app
POSTGRES_PASSWORD=change_me
POSTGRES_DB=app
POSTGRES_PORT=5432
PGDATA=/var/lib/postgresql/data/pgdata
.env setzen — niemals die Beispielwerte übernehmenDrei Einstellungen machen die meiste Arbeit, und alle drei sind Aussagen über
Ihre Maschine, keine magischen Zahlen. shared_buffers ist PostgreSQLs
eigener Cache — der klassische Startpunkt ist ein Viertel des System-RAMs:
genug, um das heiße Working Set zu halten, ohne das Betriebssystem zu
verhungern. effective_cache_size reserviert nichts; es sagt dem Planer, wie
viel Cache der OS-Page-Cache likely liefert, was die Entscheidung zwischen
Index-Scan und Sequential-Scan verändert. Auf einhalb bis dreiviertel RAM zu
setzen ist ehrliche Berichterstattung, kein Tuning. WAL-Kompression tauscht
ein wenig CPU gegen deutlich weniger Schreibvolumen auf der Platte — der
richtige Tausch auf praktisch jedem modernen Host. Die Konfigurationsdatei
liegt read-only gemountet bei: Tuning ändern heißt also Git-Commit plus
Container-Neustart, und der Neustart ist Absicht — dauerhafte Konfiguration
darf nie davon abhängen, sich an einen docker exec zu erinnern.
Der Backup-Job ist die halbe Funktion; die andere Hälfte ist, den Restore so
lange zu proben, bis er langweilig ist. Die Probe: einen Wegwerf-Postgres-Container
starten, den neuesten Dump einspielen, die Anwendung dagegen laufen lassen und
das Ganze stoppen. Das Timing ist wichtiger als der Erfolg — die
Restore-Dauer ist Ihr echtes RTO, und im Incident zu entdecken, dass es vier
Stunden sind, ist zu spät. Die Probe gehört in den Kalender, pro
Retention-Zyklus einmal. Redis-Restores sind dieselbe Disziplin im Kleinen:
Instanz stoppen, dump.rdb eintauschen, starten, Keys bestätigen. Ein nie
wiedereingespieltes Backup ist kein Backup — es ist eine Hoffnung mit
Zeitplan.
Welche PostgreSQL-Einstellungen lohnen sich für Produktion am meisten?
Die Defaults sind für Laptops gestimmt: shared_buffers,
effective_cache_size und WAL-Kompression sind die ersten drei, die man
bewusst gegen den realen RAM setzt. Der Stack bringt eine getunte
postgresql.conf mit, read-only gemountet — Tuning ist damit versionierte
Config, kein vergessener docker exec.
Warum AOF und RDB in Redis gleichzeitig aktivieren? Beide schließen die Lücken des anderen: RDB ist ein kompakter Momentaufnahme-Snapshot, der schnell restored, aber alles seit dem letzten Snapshot verliert; AOF loggt jeden Schreibvorgang mit minimalem Verlust, wächst aber stärker und spielt langsamer zurück. Zusammen gibt es schnelle Recovery und ein enges Verlustfenster.
Wie funktionieren Backups und Aufbewahrung hier? Ein geplanter Job sichert die Datenbank in ein Backup-Volume mit Retention-Policy, getrennt von den Live-Datenverzeichnissen. Entscheidend ist nicht der Dump, sondern der Restore: Den Wiederherstellungsweg vorher proben — ein nie wiedereingespieltes Backup ist eine Hypothese.
Sollen Postgres- und Redis-Ports zum Host exponiert werden? Standardmäßig auf dem internen Docker-Netzwerk lassen und nur exponieren, was ein externer Konsument wirklich braucht — idealerweise über den Reverse-Proxy mit TLS. Datenbanken auf 0.0.0.0 sind der häufigste selbst zugefügte Sicherheitsvorfall in Homelab-Setups.
Ein Guide, kein Produkt. Diese Seite ist Deployment-Dokumentation mit lauffähigen Beispielen — kein Zip, kein Download, kein Supportvertrag. Sie adaptieren die Muster auf Ihre eigene Umgebung, und das Ergebnis gehört Ihnen.
Wenn Sie das produktionsreif in Ihrer Infrastruktur wollen: Fundament-Arbeit dieser Art ist mein Standard-Umfang für Infrastruktur-Consulting — Details auf der Consulting-Seite.