Strato V-Server · 3 eigenständige Bausteine · Saubere Struktur
Übersicht & Architektur
Internet
│
├── n8n01.linkemarco.de:443 ──▶ Traefik ──▶ n8n Container
│
└── mqtt.linkemarco.de:8883 ──▶ Traefik ──▶ Mosquitto Container
~/traefik/ # Baustein 1 – Reverse Proxy, läuft immer, unabhängig
~/n8n/ # Baustein 2 – nur n8n
~/mosquitto/ # Baustein 3 – nur Mosquitto
Gemeinsames Docker-Netzwerk: traefik-networkDesignprinzip: Alle drei Bausteine folgen demselben Muster:
- Ordnername = Dienstname (kein
-composeSuffix, keine Technologie im Namen) - Daten liegen sichtbar als Bind-Mount im jeweiligen Ordner (
data/,config/,log/) – keine versteckten Docker-Volumes mit auto-generierten Namen - Jeder Baustein ist unabhängig startbar/stoppbar
Verzeichnisstruktur:
~/traefik/
│ compose.yaml
│ .env
letsencrypt/ # Zertifikate, sichtbar statt verstecktem Volume
~/n8n/
│ compose.yaml
│ .env
data/ # n8n Workflows, Credentials, Settings
local-files/
~/mosquitto/
compose.yaml
.env
config/
├── mosquitto.conf
├── passwd
└── acl
data/
log/Benutzer & Rechte (Übersicht)
| Benutzer | Rolle | Topic-Rechte |
|---|---|---|
creed | Admin | Alle Topics + $SYS/# (Broker-Statistiken) |
marco | Power-User | Alle normalen Topics lesen/schreiben |
n8n | Service | Alle normalen Topics lesen/schreiben |
ulanzi | Device | Nur awtrix/# lesen/schreiben |
Teil 0: Bestandsaufnahme & Vorbereitung
Schritt 1: Aktuelles n8n-Datenvolume identifizieren
docker volume ls | grep n8nErwartete Ausgabe, z.B.:
local n8n-compose_n8n_data
local n8n-compose_traefik_dataSchritt 2: Altes Setup stoppen
cd ~/n8n-compose
docker compose down
downlöscht die Volumes nicht – deine Daten sind weiterhin sicher gespeichert, nur der Container ist gestoppt.
Baustein 1: Traefik (eigenständig, sauberer Neuaufbau)
Da das Zertifikat neu ausgestellt werden soll, kein Übernehmen alter Volumes nötig – kompletter sauberer Neustart.
Schritt 1: Netzwerk erstellen
docker network create traefik-networkSchritt 2: Verzeichnis anlegen
mkdir -p ~/traefik/letsencrypt
cd ~/traefikSchritt 3: .env erstellen
nano .envInhalt:
SSL_EMAIL=deine@email.deSchritt 4: compose.yaml erstellen
nano compose.yamlInhalt:
services:
traefik:
image: "traefik"
container_name: traefik
restart: always
command:
- "--api.insecure=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.web.http.redirections.entryPoint.to=websecure"
- "--entrypoints.web.http.redirections.entrypoint.scheme=https"
- "--entrypoints.websecure.address=:443"
- "--entrypoints.mqtt.address=:8883"
- "--certificatesresolvers.mytlschallenge.acme.tlschallenge=true"
- "--certificatesresolvers.mytlschallenge.acme.email=${SSL_EMAIL}"
- "--certificatesresolvers.mytlschallenge.acme.storage=/letsencrypt/acme.json"
ports:
- "80:80"
- "443:443"
- "8883:8883"
volumes:
- ./letsencrypt:/letsencrypt
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
- traefik-network
networks:
traefik-network:
external: trueZertifikate liegen jetzt sichtbar unter
~/traefik/letsencrypt/acme.json– kein verstecktes Docker-Volume mehr, konsistent mit dem Rest der Struktur.
Schritt 5: Traefik starten
docker compose up -d
docker compose logs -fBaustein 2: n8n (eigenständig, saubere Struktur, Datenmigration)
Schritt 1: Neues Verzeichnis anlegen
mkdir -p ~/n8n/data ~/n8n/local-filesSchritt 2: Alte Daten migrieren
Die alten n8n-Daten aus dem Docker-Volume in den neuen Bind-Mount-Ordner kopieren:
docker run --rm \
-v n8n-compose_n8n_data:/source \
-v ~/n8n/data:/target \
alpine sh -c "cp -av /source/. /target/"Prüfen ob die Daten angekommen sind:
ls -la ~/n8n/dataDu solltest Dateien wie config, database.sqlite o.ä. sehen.
Schritt 3: Alte local-files migrieren (falls vorhanden)
cp -av ~/n8n-compose/local-files/. ~/n8n/local-files/Schritt 4: .env erstellen
cd ~/n8n
nano .envInhalt:
DOMAIN_NAME=linkemarco.de
SUBDOMAIN=n8n01
GENERIC_TIMEZONE=Europe/BerlinSchritt 5: compose.yaml erstellen
nano compose.yamlInhalt:
services:
n8n:
image: docker.n8n.io/n8nio/n8n
container_name: n8n
restart: always
ports:
- "127.0.0.1:5678:5678"
labels:
- traefik.enable=true
- traefik.http.routers.n8n.rule=Host(`${SUBDOMAIN}.${DOMAIN_NAME}`)
- traefik.http.routers.n8n.tls=true
- traefik.http.routers.n8n.entrypoints=web,websecure
- traefik.http.routers.n8n.tls.certresolver=mytlschallenge
- traefik.http.middlewares.n8n.headers.SSLRedirect=true
- traefik.http.middlewares.n8n.headers.STSSeconds=315360000
- traefik.http.middlewares.n8n.headers.browserXSSFilter=true
- traefik.http.middlewares.n8n.headers.contentTypeNosniff=true
- traefik.http.middlewares.n8n.headers.forceSTSHeader=true
- traefik.http.middlewares.n8n.headers.SSLHost=${DOMAIN_NAME}
- traefik.http.middlewares.n8n.headers.STSIncludeSubdomains=true
- traefik.http.middlewares.n8n.headers.STSPreload=true
- traefik.http.routers.n8n.middlewares=n8n@docker
environment:
- N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true
- N8N_HOST=${SUBDOMAIN}.${DOMAIN_NAME}
- N8N_PORT=5678
- N8N_PROTOCOL=https
- N8N_RUNNERS_ENABLED=true
- NODE_ENV=production
- WEBHOOK_URL=https://${SUBDOMAIN}.${DOMAIN_NAME}/
- GENERIC_TIMEZONE=${GENERIC_TIMEZONE}
- TZ=${GENERIC_TIMEZONE}
volumes:
- ./data:/home/node/.n8n
- ./local-files:/files
networks:
- traefik-network
networks:
traefik-network:
external: trueKein
volumes:-Top-Level-Eintrag mehr nötig – reine Bind-Mounts, alles sichtbar unter~/n8n/data/.
Schritt 6: Berechtigungen prüfen
n8n läuft im Container als User node (UID 1000). Falls es beim Start Berechtigungsprobleme gibt:
sudo chown -R 1000:1000 ~/n8n/dataSchritt 7: n8n starten
docker compose up -d
docker compose logs -fn8n sollte unter https://n8n01.linkemarco.de erreichbar sein, mit allen alten Workflows.
Schritt 8: Nach erfolgreicher Prüfung aufräumen
Erst wenn du bestätigt hast dass alle Workflows/Credentials da sind:
docker volume rm n8n-compose_n8n_data
docker volume rm n8n-compose_traefik_data
rm -rf ~/n8n-composeBaustein 3: Mosquitto (eigenständig)
Schritt 1: Verzeichnisse anlegen
mkdir -p ~/mosquitto/{config,data,log}
cd ~/mosquittoSchritt 2: Alle Benutzer anlegen
# creed (Admin) – erster Benutzer, -c erstellt die Datei neu
docker run --rm -v $(pwd)/config:/mosquitto/config \
eclipse-mosquitto \
mosquitto_passwd -c /mosquitto/config/passwd creed
# marco (Power-User)
docker run --rm -v $(pwd)/config:/mosquitto/config \
eclipse-mosquitto \
mosquitto_passwd /mosquitto/config/passwd marco
# n8n (Service)
docker run --rm -v $(pwd)/config:/mosquitto/config \
eclipse-mosquitto \
mosquitto_passwd /mosquitto/config/passwd n8n
# ulanzi (Device)
docker run --rm -v $(pwd)/config:/mosquitto/config \
eclipse-mosquitto \
mosquitto_passwd /mosquitto/config/passwd ulanziNur beim ersten Benutzer (
creed) das Flag-cverwenden. Alle weiteren ohne-c, sonst wird die Datei überschrieben.
Schritt 3: ACL-Datei erstellen
nano config/aclInhalt:
# creed – Admin
user creed
topic readwrite #
topic read $SYS/#
# marco – Power-User
user marco
topic readwrite #
# n8n – Service
user n8n
topic readwrite #
# ulanzi – Device (nur awtrix Topics)
user ulanzi
topic readwrite awtrix/#Schritt 4: mosquitto.conf erstellen
nano config/mosquitto.confInhalt:
listener 1883
allow_anonymous false
password_file /mosquitto/config/passwd
acl_file /mosquitto/config/acl
persistence true
persistence_location /mosquitto/data/
log_dest file /mosquitto/log/mosquitto.log
log_type error
log_type warning
log_type notice
log_type informationSchritt 5: .env erstellen
nano .envInhalt:
MQTT_DOMAIN=mqtt.linkemarco.deSchritt 6: compose.yaml erstellen
nano compose.yamlInhalt:
services:
mosquitto:
image: eclipse-mosquitto:latest
container_name: mosquitto
restart: unless-stopped
volumes:
- ./config/mosquitto.conf:/mosquitto/config/mosquitto.conf
- ./config/passwd:/mosquitto/config/passwd
- ./config/acl:/mosquitto/config/acl
- ./data:/mosquitto/data
- ./log:/mosquitto/log
labels:
- traefik.enable=true
- traefik.tcp.routers.mqtt.rule=HostSNI(`${MQTT_DOMAIN}`)
- traefik.tcp.routers.mqtt.entrypoints=mqtt
- traefik.tcp.routers.mqtt.tls=true
- traefik.tcp.routers.mqtt.tls.certresolver=mytlschallenge
- traefik.tcp.services.mqtt.loadbalancer.server.port=1883
networks:
- traefik-network
networks:
traefik-network:
external: trueSchritt 7: Mosquitto starten
docker compose up -d
docker compose logs -fFirewall & DNS (einmalig)
Strato Firewall:
| Protokoll | Port | Richtung | Quelle |
|---|---|---|---|
| TCP | 8883 | Eingehend | 0.0.0.0/0 |
DNS A-Record:
mqtt.linkemarco.de → A → <VPS-IP> → TTL: 300Verbindung testen
# Topic subscriben (als marco)
mosquitto_sub -h mqtt.linkemarco.de -p 8883 \
--capath /etc/ssl/certs \
-u marco -P <passwort> \
-t "#" -v
# Publishen (als n8n)
mosquitto_pub -h mqtt.linkemarco.de -p 8883 \
--capath /etc/ssl/certs \
-u n8n -P <passwort> \
-t "awtrix/custom" \
-m '{"text": "Setup OK!", "color": "#00FF00"}'Ulanzi TC001 verbinden
Im AWTRIX Webinterface (http://<ulanzi-ip>) → MQTT:
- Host:
mqtt.linkemarco.de - Port:
8883 - TLS: aktivieren
- Username:
ulanzi - Password:
<ulanzi-passwort> - Prefix:
awtrix
n8n MQTT-Credentials
In n8n → Settings → Credentials → New → MQTT:
- Host:
mosquitto(interner Docker-Hostname) - Port:
1883 - Username:
n8n - Password:
<n8n-passwort>
Alltag: Jeder Baustein unabhängig verwaltbar
# Nur Traefik neu starten (n8n & Mosquitto bleiben unberührt)
cd ~/traefik && docker compose restart
# Nur n8n updaten
cd ~/n8n && docker compose pull && docker compose up -d
# Nur Mosquitto neu laden
cd ~/mosquitto && docker compose restart
# Status aller drei Bausteine prüfen
docker ps --format "table {{.Names}}\t{{.Status}}"
# Backup eines Bausteins (Beispiel n8n) – da alles Bind-Mount ist, reicht tar
tar -czvf n8n-backup-$(date +%Y%m%d).tar.gz ~/n8n/dataNützliche MQTT-Befehle
# Alle Topics beobachten (intern)
docker exec -it mosquitto mosquitto_sub \
-u creed -P <passwort> -t "#" -v
# Neuen Benutzer hinzufügen
docker run --rm -v $(pwd)/config:/mosquitto/config \
eclipse-mosquitto \
mosquitto_passwd /mosquitto/config/passwd neuer-user
# Passwort ändern
docker run --rm -v $(pwd)/config:/mosquitto/config \
eclipse-mosquitto \
mosquitto_passwd /mosquitto/config/passwd marco
# Benutzer löschen
docker run --rm -v $(pwd)/config:/mosquitto/config \
eclipse-mosquitto \
mosquitto_passwd -D /mosquitto/config/passwd alter-user
# Config neu laden ohne Neustart
docker exec -it mosquitto kill -HUP 1Zusammenfassung
| Baustein | Verzeichnis | Daten | Zertifikat/Auth |
|---|---|---|---|
| Traefik | ~/traefik/ | letsencrypt/ (Bind-Mount) | stellt neues Let’s Encrypt Zertifikat aus |
| n8n | ~/n8n/ | data/ (Bind-Mount, migriert) | nutzt Traefik-Zertifikat |
| Mosquitto | ~/mosquitto/ | data/, config/, log/ (Bind-Mount) | nutzt Traefik-Zertifikat, eigene User/ACL |
Konsistenzprinzip: Alle drei Ordner folgen demselben Aufbau – Dienstname als Ordnername, .env für Variablen, compose.yaml für die Definition, alle persistenten Daten sichtbar als Unterordner statt versteckter Docker-Volumes.