Beim Einrichten meines EuroOffice Documentservers habe ich den Container-Port nicht einfach mit 8030:80 veröffentlicht. In meiner Compose-Datei steht stattdessen:
ports:
- "127.0.0.1:8030:80"Code-Sprache: CSS (css)
Die Zeile ist etwas länger, hat aber einen wichtigen Vorteil: Der Dienst ist nur auf dem Server selbst erreichbar. Besucher greifen nicht direkt auf Port 8030 zu. Der öffentliche Zugriff läuft kontrolliert über Nginx und die dafür eingerichtete Domain.
Drei Angaben in einer Zeile
Die Portfreigabe besteht aus drei Teilen:
127.0.0.1 : 8030 : 80
Host-IP Host ContainerCode-Sprache: CSS (css)
127.0.0.1 ist die lokale IPv4-Adresse des Servers. Port 8030 ist der Anschluss auf dem Host. Die letzte Zahl bezeichnet den Port innerhalb des Containers, auf dem der Documentserver lauscht.
Rufe ich auf dem Server http://127.0.0.1:8030 auf, wird die Anfrage an Port 80 im Container weitergeleitet.
Was passiert ohne 127.0.0.1?
Eine verkürzte Freigabe würde so aussehen:
ports:
- "8030:80"Code-Sprache: JavaScript (javascript)
Ohne angegebene Host-Adresse veröffentlicht Docker den Port standardmäßig auf allen Host-Adressen. Der Dienst kann dadurch – abhängig von Firewall, Routing und Docker-Konfiguration – auch direkt von außen erreichbar werden. Das ist für einen Dienst hinter einem Reverse Proxy normalerweise unnötig.
Die Bindung an 127.0.0.1 verkleinert die Angriffsfläche. Selbst wenn eine Firewall-Regel später versehentlich geändert wird, lauscht der veröffentlichte Port weiterhin nur auf der lokalen Schnittstelle.
Nginx übernimmt den öffentlichen Zugriff
Mein Nginx läuft direkt auf dem Host. Er nimmt die HTTPS-Verbindung auf Port 443 entgegen und leitet sie intern zum Container weiter. Der entscheidende Teil einer vereinfachten Konfiguration sieht so aus:
server {
listen 443 ssl;
server_name office.example.de;
location / {
proxy_pass http://127.0.0.1:8030;
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;
}
}Code-Sprache: PHP (php)
Zertifikatspfade und weitere Sicherheitsoptionen sind in diesem gekürzten Beispiel bewusst nicht enthalten. Wichtig ist der Datenweg: Browser zu Nginx, Nginx zu 127.0.0.1:8030 und von dort zu Port 80 im Container.
Prüfen, worauf der Port wirklich lauscht
Ob die Bindung wie gewünscht funktioniert, lässt sich direkt auf dem Server kontrollieren:
ss -ltnp | grep ':8030'Code-Sprache: JavaScript (javascript)
In der Ausgabe sollte 127.0.0.1:8030 erscheinen – nicht 0.0.0.0:8030. Ein lokaler Funktionstest ist ebenfalls schnell erledigt:
curl -I http://127.0.0.1:8030Code-Sprache: JavaScript (javascript)
Zusätzlich zeigt docker compose ps die eingerichtete Portzuordnung an.
Wichtig bei Nginx im Container
Das Beispiel gilt, wenn Nginx wie bei mir direkt auf dem Server läuft. Befindet sich auch Nginx in einem Container, zeigt dessen 127.0.0.1 nur auf den Nginx-Container selbst. Dann verbindet man beide Container besser über ein gemeinsames Docker-Netzwerk und spricht den Dienst über seinen Servicenamen an.
Für einen Reverse Proxy auf dem Host ist 127.0.0.1:8030:80 dagegen eine einfache und gut nachvollziehbare Lösung. Der Dienst bleibt intern, während Nginx den einzigen vorgesehenen Weg nach außen bereitstellt.
Passend dazu: WordPress mit Docker Compose und externem Nginx installieren – sauber und sicher.
Artikelbild: Foto von Taylor Vick auf Unsplash.
Weiterführende Dokumentation: Port publishing and mapping bei Docker.
Wie ist deine Meinung?
Schreib gern einen Kommentar unter dem Artikel oder diskutiere mit anderen im Matrix-Kanal:
#dasnetzundich:matrix.org