Diese Anleitung behandelt eines der wichtigsten Sicherheitsmuster unseres realen Ubuntu-24.04-Self-Hosted-AI-Stacks: App-Ports nicht auf 0.0.0.0 veröffentlichen, sondern an 127.0.0.1 binden und öffentlichen Zugriff über Nginx und HTTPS bereitstellen. Das Muster wurde für Portainer 9443, Ollama 11434, Open WebUI 3000 und n8n 5678 verwendet.
Internet :443
↓
Nginx + TLS
├─ 127.0.0.1:9443 → Portainer
├─ 127.0.0.1:3000 → Open WebUI
├─ 127.0.0.1:5678 → n8n
└─ Ollama 127.0.0.1:11434 + private Docker networkEin Publish wie -p 8080:80 ohne Host-IP kann den Port standardmäßig auf allen Hostadressen veröffentlichen. Dadurch können Admin- oder API-Ports unbeabsichtigt extern erreichbar werden.
Mit einer expliziten Host-IP 127.0.0.1 ist der veröffentlichte Port nur vom Docker-Host erreichbar. Genau dieses Muster verwenden wir im Self-Hosted-AI-Stack.
docker run -p 8080:80 nginxdocker run -p 127.0.0.1:8080:80 nginxIm realen Ubuntu-24.04-Stack wurden Portainer 9443, Ollama 11434, Open WebUI 3000 und n8n 5678 hostseitig nur an 127.0.0.1 gebunden.
Webdienste mit öffentlichem Zugriff wurden über Nginx 80/443 veröffentlicht. Ollama blieb eine Backend-API auf localhost und im privaten Docker-Netz.
127.0.0.1:9443 → Portainer127.0.0.1:11434 → Ollama127.0.0.1:3000 → Open WebUI127.0.0.1:5678 → n8n0.0.0.0:80 / :443 → NginxDie Ports-Spalte von docker ps ist ein schneller Sicherheitscheck. 127.0.0.1:5678->5678/tcp bedeutet Loopback-Binding; 0.0.0.0:5678->5678/tcp bedeutet Veröffentlichung auf allen IPv4-Hostinterfaces.
Diese Kontrolle sollte für Admin-Panels, Datenbanken, lokale LLM-APIs und Automatisierungseditoren Routine sein.
docker ps --format 'table {{.Names}}\t{{.Ports}}'Zusätzlich zur Docker-Ausgabe sollte die Linux-Socket-Tabelle geprüft werden. Im finalen Design lauschen App-Ports auf 127.0.0.1, Nginx dagegen öffentlich auf 80/443.
Beide Prüfungen zusammen bestätigen, dass Docker-Publishing und Betriebssystem-Sockets der gewünschten Architektur entsprechen.
ss -lntp | grep -E ':80|:443|:9443|:11434|:3000|:5678'Wenn die Anwendung auf localhost lauscht, kann Nginx öffentliche HTTPS-Anfragen an das lokale Upstream weiterleiten. Für n8n verwendeten wir proxy_pass http://127.0.0.1:5678; Open WebUI folgt demselben Muster auf 127.0.0.1:3000.
So lassen sich TLS, Domains, Access Logs, Rate Limits und optionale Authentifizierung an einem öffentlichen Einstiegspunkt bündeln.
location / {
proxy_pass http://127.0.0.1:5678;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}Upgrade- und Connection-Header sind hop-by-hop. Ein Reverse Proxy muss die nötigen Upgrade-Informationen explizit an WebSocket-Upstreams weitergeben.
Wir verwendeten ein Nginx-map für connection_upgrade und leiteten HTTP/1.1, Upgrade und Connection im location-Block weiter.
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;Für Benutzerzugriff braucht eine localhost-only Anwendung eine öffentliche Domain- und TLS-Schicht. Nach erfolgreichem Nginx-Test wurden Zertifikate installiert und HTTPS-Antworten geprüft.
certbot renew --dry-run testet die Verlängerung ohne das Live-Zertifikat zu ersetzen.
nginx -tcurl -I https://n8n.ekasunucu.comcertbot renew --dry-runDocker verwaltet Firewall- und NAT-Regeln für veröffentlichte Ports. Die offizielle Docker-Dokumentation weist darauf hin, dass ohne Host-IP veröffentlichte Ports extern erreichbar sein können und Docker-iptables-Regeln Erwartungen aus einer reinen UFW-Konfiguration umgehen können.
Die primäre Kontrolle sollte deshalb direkt im Publish-Ausdruck liegen: -p 127.0.0.1:HOST:CONTAINER. Die Host-Firewall bleibt eine zusätzliche Schicht.
-p 5678:5678-p 127.0.0.1:5678:5678Portainer, Open WebUI und n8n benötigen Browserzugriff; daher verwendeten wir localhost-App-Ports plus Nginx-Domain und HTTPS. Öffentliche Benutzer sehen nur den TLS-Einstiegspunkt.
Ollama blieb Backend-API: Hostzugriff über 127.0.0.1:11434, Dockerzugriff über ollama:11434 und kein öffentlicher 11434-Listener.
portainer.ekasunucu.com → Nginx → 127.0.0.1:9443openwebui.ekasunucu.com → Nginx → 127.0.0.1:3000n8n.ekasunucu.com → Nginx → 127.0.0.1:5678Ollama → 127.0.0.1:11434 + eka-ai private networkPublished-Port-Mappings eines laufenden Containers werden normalerweise nicht in-place geändert. Container mit denselben Volumes, Environment- und Netzwerkparametern neu erstellen, aber localhost-only -p verwenden.
Vorher docker inspect sichern. Named Volumes können Daten unabhängig vom Container erhalten, trotzdem vor Produktionsänderungen Backup oder Snapshot erstellen.
docker inspect n8n > /root/n8n-before-port-fix.jsondocker rm -f n8ndocker run -d --name n8n --restart=always --env-file /root/n8n.env -p 127.0.0.1:5678:5678 -v n8n_data:/home/node/.n8n docker.n8n.io/n8nio/n8n:latestdocker ps zeigt Mappings, ss die tatsächlichen Sockets, nginx -t die Konfiguration, eine echte HTTPS-Anfrage den öffentlichen Endpoint und Certbot dry-run die Renewal-Kette.
Erwartet: App-Ports auf 127.0.0.1, öffentliche Webeingänge nur über Nginx 80/443, funktionierendes HTTPS und erfolgreiche Renewal-Simulation.
docker ps --format 'table {{.Names}}\t{{.Ports}}'ss -lntp | grep -E ':80|:443|:9443|:11434|:3000|:5678'nginx -tcurl -I https://n8n.ekasunucu.comcertbot renew --dry-runGehen alte docker-run-Parameter bei einem Imageupdate verloren, kann ein neu erstellter Dienst versehentlich auf 0.0.0.0 veröffentlicht werden. Port-Mapping-Prüfung sollte Teil jedes Deployments sein.
Bindings, Nginx-Upstreams, HTTPS-Health und privates Docker-Netz gemeinsam zu prüfen reduziert unbeabsichtigte öffentliche Exposition.
docker ps --format 'table {{.Names}}\t{{.Ports}}'ss -lntpdocker network inspect eka-ainginx -tOhne Host-IP kann Docker den Port standardmäßig auf allen Hostadressen veröffentlichen.
Der veröffentlichte Port wird auf die Loopback-Adresse des Docker-Hosts beschränkt.
Es steht typischerweise für alle geeigneten IPv4-Hostinterfaces des lauschenden oder veröffentlichten Ports.
Ports-Spalte in docker ps und die Listening-Sockets mit ss -lntp prüfen.
In dieser Architektur nein; 127.0.0.1:5678 plus Nginx HTTPS.
Wir banden ihn nur an localhost und veröffentlichten die Domain über Nginx.
Nein; hostseitig 127.0.0.1 und containerseitig privates Docker-Netzwerk.
Host-Binding nur auf 127.0.0.1:9443, Domainzugriff über Nginx.
Nginx nimmt öffentlichen Domain-/TLS-Traffic an und leitet ihn an die lokale Backend-Anwendung weiter.
Upgrade- und Connection-Informationen müssen vom Reverse Proxy explizit weitergereicht werden.
Nicht nur auf UFW verlassen; Docker verwaltet eigene Firewall-/NAT-Regeln. Host-Bind korrekt wählen.
Normalerweise Container mit korrekten Volumes, Environment, Netzwerken und Publish-Mapping neu erstellen.
Mit certbot renew --dry-run.
docker ps, ss, Nginx-Konfiguration, HTTPS-Health, private Netzwerke und Zertifikatserneuerung erneut prüfen.
Portainer, Ollama, Open WebUI, n8n und weitere Docker-Dienste hinter Nginx und HTTPS auf einem eigenen EKA-Sunucu-Linux-VPS betreiben.
Aktualisiert: 10.08.2026