16. September 2026

Docker-Ports mit UFW absichern – ufw-docker richtig einrichten

ufw-docker sichert Docker-Ports mit UFW-Firewall auf einem Linux-Server ab

Docker und die Ubuntu-Firewall UFW werden häufig gemeinsam auf Servern eingesetzt. Dabei gibt es jedoch eine wichtige Besonderheit: Ein mit Docker veröffentlichter Port kann trotz aktivierter UFW-Firewall von außen erreichbar sein.

Das Projekt ufw-docker schließt diese Lücke, ohne Dockers eigene Firewall- und Netzwerkverwaltung zu deaktivieren.

Projektseite:

https://github.com/chaifeng/ufw-docker

Das Problem: Docker umgeht UFW-Regeln

Normalerweise lässt sich ein Server mit UFW nach dem Prinzip „standardmäßig alles blockieren und nur benötigte Ports freigeben“ absichern:

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp
sudo ufw enable

Der Status sieht anschließend beispielsweise so aus:

Status: active

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW       Anywhere

Starten wir nun einen Docker-Container und veröffentlichen dessen Port:

docker run -d \
  --name nginx-test \
  -p 8080:80 \
  nginx:alpine

würde man erwarten, dass Port 8080 durch UFW blockiert wird. In vielen Docker-Konfigurationen ist der Port jedoch trotzdem von außen erreichbar.

Auch eine explizite Sperre löst das Problem nicht zuverlässig:

sudo ufw deny 8080/tcp

Der Grund dafür liegt in der Paketverarbeitung des Linux-Kernels. Docker erstellt eigene iptables- beziehungsweise nftables-Regeln und verarbeitet weitergeleiteten Datenverkehr teilweise, bevor die normalen UFW-Regeln für den Host greifen.

Das kann dazu führen, dass veröffentlichte Container-Ports unbeabsichtigt im Internet erreichbar sind. Genau dieses Verhalten beschreibt auch die Dokumentation von ufw-docker.

Was macht ufw-docker?

ufw-docker verbindet die Docker-Firewallkette DOCKER-USER mit den Forwarding-Regeln von UFW.

Dadurch können Zugriffe auf veröffentlichte Container-Ports über normale UFW-Routing-Regeln gesteuert werden.

Die Lösung verfolgt dabei mehrere wichtige Ziele:

  • Dockers iptables-Funktion bleibt aktiviert.
  • Container können weiterhin untereinander kommunizieren.
  • Container behalten ihren Zugriff auf das Internet.
  • Veröffentlichte Ports werden nicht automatisch aus dem Internet erreichbar.
  • Einzelne Container und Ports können gezielt freigegeben werden.
  • IPv4 und IPv6 werden unterstützt.
  • Docker-Netzwerke müssen nicht vollständig manuell verwaltet werden.

ufw-docker ergänzt dafür unter anderem Regeln in:

/etc/ufw/after.rules
/etc/ufw/after6.rules

Außerdem verwendet das Projekt die von Docker vorgesehene Firewallkette:

DOCKER-USER

Voraussetzungen

Für die Installation benötigen wir:

  • Ubuntu oder ein anderes System mit UFW
  • eine funktionierende Docker-Installation
  • Git
  • Root- beziehungsweise sudo-Rechte
  • aktiviertes IP-Forwarding

Zunächst aktualisieren wir die Paketquellen und installieren UFW sowie Git:

sudo apt update
sudo apt install -y ufw git

Anschließend prüfen wir Docker:

docker --version

Und UFW:

sudo ufw status verbose

Wichtige Vorbereitung

Docker sollte seine Firewallregeln weiterhin selbst verwalten dürfen.

In /etc/docker/daemon.json sollte daher nicht folgende Option stehen:

{
  "iptables": false
}

Falls diese Einstellung vorhanden ist, sollte sie entfernt werden.

Eine mögliche Standardkonfiguration könnte beispielsweise so aussehen:

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}

Anschließend wird Docker neu gestartet:

sudo systemctl restart docker

Auch die UFW-Forwarding-Policy sollte nicht aufgrund älterer Anleitungen pauschal auf ACCEPT gesetzt worden sein. ufw-docker ist darauf ausgelegt, mit Dockers normaler Firewallverwaltung und einer restriktiven UFW-Konfiguration zusammenzuarbeiten.

SSH-Zugriff freigeben

Bevor UFW aktiviert oder neu konfiguriert wird, muss der SSH-Port freigegeben werden. Andernfalls besteht die Gefahr, sich vom Server auszusperren.

Bei Verwendung des Standardports:

sudo ufw allow 22/tcp

Alternativ kann das vordefinierte OpenSSH-Profil verwendet werden:

sudo ufw allow OpenSSH

Danach setzen wir die grundlegenden Richtlinien:

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw default deny routed

UFW kann nun aktiviert werden:

sudo ufw enable

ufw-docker herunterladen

Das Repository wird nach /opt geklont:

cd /opt
sudo git clone https://github.com/chaifeng/ufw-docker.git
cd ufw-docker

Das Hauptskript muss ausführbar sein:

sudo chmod +x ufw-docker

ufw-docker systemweit installieren

Für eine dauerhafte Installation verwenden wir:

sudo ./ufw-docker install --system

Die Option --system installiert das Programm unter:

/usr/local/bin/ufw-docker

Zusätzlich werden eine Manpage und ein systemd-Dienst eingerichtet. Der Dienst führt nach dem Start von Docker ein erneutes Laden der Regeln aus.

Nach der Installation starten wir UFW neu:

sudo systemctl restart ufw

Anschließend empfiehlt sich ein Neustart des Servers:

sudo reboot

Nach dem Neustart prüfen wir beide Dienste:

sudo systemctl status docker
sudo systemctl status ufw

Falls der ufw-docker-Dienst installiert wurde:

sudo systemctl status ufw-docker

Installation überprüfen

ufw-docker bringt eine eigene Prüffunktion mit:

sudo ufw-docker check

Die aktuell verwalteten Freigaben können mit folgendem Befehl angezeigt werden:

sudo ufw-docker list

Alternativ:

sudo ufw-docker status

Auch UFW selbst zeigt die erzeugten Regeln an:

sudo ufw status numbered

Docker-Netzwerke automatisch erkennen

Standardmäßig berücksichtigt ufw-docker die privaten IPv4-Netze:

10.0.0.0/8
172.16.0.0/12
192.168.0.0/16

Für IPv6 wird standardmäßig der ULA-Bereich verwendet:

fd00::/8

Bei individuellen Docker-Netzwerken kann ufw-docker die vorhandenen Subnetze automatisch ermitteln:

sudo ufw-docker install --docker-subnets --system

Die entsprechende Prüfung erfolgt mit:

sudo ufw-docker check --docker-subnets

Alternativ können Netzwerke explizit angegeben werden:

sudo ufw-docker install \
  --docker-subnets \
  172.20.0.0/16 \
  172.21.0.0/16 \
  192.168.100.0/24 \
  fd00:20::/64 \
  --system

Das Skript unterstützt sowohl automatisch erkannte als auch manuell angegebene Docker- und interne Netzwerke.

Erster Funktionstest

Wir starten erneut einen Nginx-Container:

docker run -d \
  --name nginx-test \
  -p 8080:80 \
  nginx:alpine

Lokal sollte der Dienst erreichbar sein:

curl http://127.0.0.1:8080

Von einem externen Rechner sollte der Zugriff zunächst blockiert werden:

http://SERVER-IP:8080

Damit ist sichergestellt, dass ein veröffentlichter Docker-Port nicht automatisch öffentlich erreichbar wird.

Einen Container-Port freigeben

Um den Nginx-Container gezielt freizugeben, verwenden wir:

sudo ufw-docker allow nginx-test 80/tcp

Wichtig ist dabei:

Bei ufw-docker wird normalerweise der Port innerhalb des Containers angegeben, nicht der veröffentlichte Host-Port.

Bei dieser Zuordnung:

ports:
  - "8080:80"

ist:

  • 8080 der Host-Port
  • 80 der Container-Port

Der korrekte Befehl lautet daher:

sudo ufw-docker allow nginx-test 80/tcp

und nicht:

sudo ufw-docker allow nginx-test 8080/tcp

Das Skript ermittelt über docker inspect die IP-Adressen, Netzwerke und veröffentlichten Ports des Containers und erzeugt daraus passende UFW-Route-Regeln.

Alle veröffentlichten Ports eines Containers freigeben

Werden Port und Protokoll weggelassen, kann ufw-docker alle veröffentlichten Ports des Containers berücksichtigen:

sudo ufw-docker allow nginx-test

Für öffentlich erreichbare Server ist eine einzelne, explizite Freigabe jedoch meist sicherer:

sudo ufw-docker allow nginx-test 80/tcp

Eine Freigabe wieder entfernen

Die Regel für einen bestimmten Port wird folgendermaßen gelöscht:

sudo ufw-docker delete allow nginx-test 80/tcp

Alle Freigaben eines Containers lassen sich entfernen mit:

sudo ufw-docker delete allow nginx-test

Anschließend kontrollieren wir den Status:

sudo ufw-docker list
sudo ufw status numbered

Zugriff nur aus dem Heimnetz erlauben

Nicht jeder Container muss öffentlich erreichbar sein. Administrationsoberflächen wie Portainer, Grafana, Prometheus oder ein Traefik-Dashboard sollten häufig nur über das Heimnetz oder ein VPN erreichbar sein.

Eine solche Einschränkung kann direkt mit UFW als Routing-Regel umgesetzt werden.

Angenommen, der Container besitzt die IP-Adresse:

172.20.0.10

und soll auf Port 3000 nur aus dem Netz 192.168.1.0/24 erreichbar sein:

sudo ufw route allow proto tcp \
  from 192.168.1.0/24 \
  to 172.20.0.10 \
  port 3000

Für ein WireGuard-Netz könnte die Regel beispielsweise so aussehen:

sudo ufw route allow proto tcp \
  from 10.10.10.0/24 \
  to 172.20.0.10 \
  port 3000

Dabei ist zu beachten, dass sich die IP-Adresse eines Containers nach einer Neuerstellung ändern kann. Für dauerhaft IP-basierte Regeln empfiehlt sich daher eine feste Container-IP oder eine erneute Ausführung von ufw-docker reload.

Beispiel mit Docker Compose

Eine einfache compose.yml könnte so aussehen:

services:
  nginx:
    image: nginx:alpine
    container_name: webserver
    restart: unless-stopped

    ports:
      - "8080:80"

    networks:
      web:
        ipv4_address: 172.30.0.10

networks:
  web:
    name: web
    driver: bridge

    ipam:
      config:
        - subnet: 172.30.0.0/24

Der Stack wird gestartet mit:

docker compose up -d

Danach geben wir den Container-Port 80 frei:

sudo ufw-docker allow webserver 80/tcp

Die Regel kann überprüft werden mit:

sudo ufw-docker list webserver

Beispiel für Traefik

Bei einem Reverse-Proxy-Setup sollten im Normalfall nur Traefik beziehungsweise der verwendete Proxy öffentlich erreichbar sein.

Eine typische Portkonfiguration sieht so aus:

services:
  traefik:
    image: traefik:v3
    container_name: traefik
    restart: unless-stopped

    ports:
      - "80:80"
      - "443:443"

    networks:
      - proxy

networks:
  proxy:
    name: proxy

Die Freigaben erfolgen mit:

sudo ufw-docker allow traefik 80/tcp
sudo ufw-docker allow traefik 443/tcp

Andere Container benötigen keine veröffentlichten Ports, sofern Traefik sie über das gemeinsame Docker-Netzwerk erreicht:

services:
  wordpress:
    image: wordpress:latest

    networks:
      - proxy
      - backend

networks:
  proxy:
    external: true

  backend:
    internal: true

Dadurch ergibt sich ein übersichtliches Sicherheitsmodell:

Internet
   |
   v
UFW / ufw-docker
   |
   v
Traefik: 80 und 443
   |
   v
interne Docker-Netzwerke
   |
   +-- WordPress
   +-- Grafana
   +-- Authelia
   +-- weitere Dienste

Nur der Reverse Proxy ist direkt nach außen freigegeben. Die eigentlichen Anwendungen bleiben innerhalb der Docker-Netzwerke.

UDP-Port freigeben

Für einen DNS-Container wie Pi-hole oder dnscrypt-proxy wird neben TCP häufig UDP benötigt.

Beispiel:

sudo ufw-docker allow pihole 53/udp
sudo ufw-docker allow pihole 53/tcp

Auch hier wird der Container-Port verwendet.

Die zugrunde liegende UFW-Regel entspricht prinzipiell:

sudo ufw route allow proto udp from any to CONTAINER-IP port 53

Regeln nach einer Container-Neuerstellung aktualisieren

Wird ein Container neu erstellt, kann er eine andere interne IP-Adresse erhalten. Die vorhandene Firewallregel verweist dann möglicherweise noch auf die alte Adresse.

ufw-docker kann die Regeln neu laden:

sudo ufw-docker reload

Dabei liest das Skript die vorhandenen, von ufw-docker markierten Regeln aus und gleicht sie erneut mit den aktuell laufenden Containern ab. Nicht mehr vorhandene Regeln werden entfernt und geänderte Container-IP-Adressen aktualisiert.

Bei systemweiter Installation übernimmt dies zusätzlich der systemd-Dienst nach dem Start von Docker.

Logs kontrollieren

Blockierte Docker-Verbindungen werden mit folgendem Präfix protokolliert:

[UFW DOCKER BLOCK]

Die Meldungen können über das Journal gesucht werden:

sudo journalctl -k | grep "UFW DOCKER BLOCK"

Alternativ:

sudo dmesg | grep "UFW DOCKER BLOCK"

Je nach UFW-Konfiguration befinden sich die Meldungen auch in:

/var/log/ufw.log

Die letzten Einträge lassen sich anzeigen mit:

sudo tail -f /var/log/ufw.log

Falls das Logging noch nicht aktiviert ist:

sudo ufw logging medium

Firewallregeln überprüfen

Die wichtigsten Prüfkommandos sind:

sudo ufw status verbose
sudo ufw status numbered
sudo ufw-docker status
sudo ufw-docker check

Die DOCKER-USER-Kette lässt sich mit iptables anzeigen:

sudo iptables -L DOCKER-USER -n -v --line-numbers

Auf nftables-basierten Systemen kann zusätzlich geprüft werden:

sudo nft list ruleset

Docker selbst zeigt seine veröffentlichten Ports mit:

docker ps --format "table {{.Names}}\t{{.Ports}}"

Eine detaillierte Prüfung eines Containers erfolgt mit:

docker inspect webserver

Sicherheitsprüfung mit nmap

Die Firewall sollte nicht nur vom Server selbst, sondern auch von einem externen System getestet werden.

Beispiel:

nmap -Pn -p 22,80,443,8080 SERVER-IP

Vor der Freigabe könnte das Ergebnis so aussehen:

22/tcp    open
80/tcp    filtered
443/tcp   filtered
8080/tcp  filtered

Nach der Freigabe von Traefik:

sudo ufw-docker allow traefik 80/tcp
sudo ufw-docker allow traefik 443/tcp

sollten nur die gewünschten Ports erreichbar sein:

22/tcp    open
80/tcp    open
443/tcp   open
8080/tcp  filtered

Die Prüfung sollte nach Möglichkeit über einen echten externen Internetanschluss erfolgen, beispielsweise über ein Mobilfunknetz.

IPv6 nicht vergessen

Ein häufiger Fehler besteht darin, nur IPv4 zu testen.

Besitzt der Server eine öffentliche IPv6-Adresse, müssen auch die IPv6-Regeln geprüft werden:

sudo ufw status verbose

In /etc/default/ufw sollte IPv6 aktiviert sein:

IPV6=yes

Danach:

sudo systemctl restart ufw

ufw-docker bearbeitet neben /etc/ufw/after.rules auch:

/etc/ufw/after6.rules

Das aktuelle Skript erzeugt dabei eigene IPv6-Forwarding- und Logging-Regeln und verwendet ebenfalls die DOCKER-USER-Kette.

Ein externer IPv6-Portscan kann beispielsweise so ausgeführt werden:

nmap -6 -Pn -p 22,80,443 SERVER-IPV6

Manuelle Alternative ohne Hilfsskript

ufw-docker kann auch ohne dauerhafte Installation des Skripts verwendet werden. Das Projekt ergänzt dazu einen Regelblock in /etc/ufw/after.rules, der unter anderem folgende Ketten verbindet:

DOCKER-USER
ufw-user-forward
ufw-docker-logging-deny

Ein wesentlicher Bestandteil ist:

-A DOCKER-USER -j ufw-user-forward

Dadurch werden UFW-Routing-Regeln für den Docker-Datenverkehr berücksichtigt.

Bestehende sowie zugehörige Verbindungen werden erlaubt:

-A DOCKER-USER -m conntrack --ctstate RELATED,ESTABLISHED -j RETURN

Ungültige Verbindungen werden verworfen:

-A DOCKER-USER -m conntrack --ctstate INVALID -j DROP

Neue Verbindungen aus öffentlichen Netzen zu privaten Docker-Netzen werden anschließend blockiert und protokolliert. Die vollständigen Regeln und ihre Funktionsweise sind in der Projekt-README dokumentiert.

Die Installation über das mitgelieferte Skript ist jedoch komfortabler, da:

  • vorhandene Dateien gesichert werden,
  • IPv4 und IPv6 berücksichtigt werden,
  • individuelle Docker-Subnetze unterstützt werden,
  • Regeln für einzelne Container automatisch erzeugt werden,
  • ein systemd-Dienst eingerichtet werden kann,
  • veraltete Container-IP-Adressen aktualisiert werden können.

ufw-docker deinstallieren

Die Installation kann mit folgendem Befehl entfernt werden:

sudo ufw-docker uninstall

Danach sollte UFW neu gestartet werden:

sudo systemctl restart ufw

Das Skript entfernt die von ufw-docker eingefügten Regelblöcke aus den IPv4- und IPv6-Konfigurationsdateien, entfernt die installierte Programmdatei, die Manpage und den systemd-Dienst. Vor Änderungen werden Sicherungskopien der UFW-Dateien angelegt.

Typische Fehler

Der Port ist weiterhin öffentlich erreichbar

Zunächst sollte geprüft werden, ob die Regeln installiert wurden:

sudo ufw-docker check

Danach:

sudo iptables -L DOCKER-USER -n -v

Falls die Änderungen nach einem UFW-Neustart nicht greifen, sollte der Server vollständig neu gestartet werden:

sudo reboot

Der falsche Port wurde freigegeben

Bei:

ports:
  - "8080:80"

muss Port 80 angegeben werden:

sudo ufw-docker allow containername 80/tcp

Nicht Port 8080.

Die Regel verweist auf eine alte Container-IP

Nach einer Neuerstellung:

sudo ufw-docker reload

Oder die Regel entfernen und neu anlegen:

sudo ufw-docker delete allow containername 80/tcp
sudo ufw-docker allow containername 80/tcp

SSH ist nach Aktivierung von UFW nicht mehr erreichbar

Vor Aktivierung der Firewall muss der SSH-Port freigegeben werden:

sudo ufw allow OpenSSH

Bei einem individuellen SSH-Port, beispielsweise 2222:

sudo ufw allow 2222/tcp

Ein internes Netz wird blockiert

Das benötigte Netz kann bei der Installation explizit angegeben werden:

sudo ufw-docker install \
  --docker-subnets \
  172.20.0.0/16 \
  10.10.10.0/24 \
  fd00:20::/64 \
  --system

Dabei sollten nur tatsächlich vertrauenswürdige Netze aufgenommen werden.

Empfohlene Basiskonfiguration

Für einen Server mit SSH und einem Traefik-Reverse-Proxy ergibt sich beispielsweise folgende Konfiguration:

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw default deny routed

sudo ufw allow 22/tcp
sudo ufw enable

cd /opt
sudo git clone https://github.com/chaifeng/ufw-docker.git
cd ufw-docker

sudo chmod +x ufw-docker
sudo ./ufw-docker install --docker-subnets --system

sudo systemctl restart ufw
sudo reboot

Nach dem Neustart:

sudo ufw-docker allow traefik 80/tcp
sudo ufw-docker allow traefik 443/tcp

Überprüfung:

sudo ufw status numbered
sudo ufw-docker list
sudo ufw-docker check

Fazit

Die Kombination aus Docker und UFW kann ein falsches Sicherheitsgefühl vermitteln. Ein mit Docker veröffentlichter Port ist nicht automatisch durch die normalen UFW-Eingangsregeln geschützt.

ufw-docker löst dieses Problem, indem es UFW mit der Docker-Kette DOCKER-USER verbindet. Dadurch können veröffentlichte Container-Ports zentral über UFW gesteuert werden, während Docker seine Netzwerk- und NAT-Regeln weiterhin selbst verwaltet.

Für öffentlich erreichbare Docker-Server ist das besonders sinnvoll:

  • Standardmäßig bleiben Container-Ports geschlossen.
  • Nur benötigte Dienste werden gezielt freigegeben.
  • Reverse Proxies wie Traefik können als einziger Einstiegspunkt dienen.
  • Interne Dienste bleiben in privaten Docker-Netzwerken.
  • IPv4 und IPv6 können gemeinsam abgesichert werden.
  • Änderungen lassen sich mit bekannten UFW-Befehlen kontrollieren.

Trotzdem ersetzt ufw-docker keine vollständige Sicherheitsstrategie. Container sollten regelmäßig aktualisiert, unnötige Portfreigaben vermieden und öffentlich erreichbare Dienste zusätzlich durch TLS, Authentifizierung, Rate-Limits und Sicherheitssoftware geschützt werden.

Weiterführende Links

Leave a Reply

Your email address will not be published. Required fields are marked *


Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre, wie deine Kommentardaten verarbeitet werden.

WordPress Cookie Plugin von Real Cookie Banner