SSD Nodes Learn Hosting plans →
Anleitungen Matt ConnorVon Matt Connor · Aktualisiert 2026-08-25

Docker-Container über Gluetun-VPN routen

Bei Gluetun verschwinden veröffentlichte Ports und Service-Namen durch den gemeinsamen Netzwerk-Namespace. Erfahren Sie, warum das so ist und welche Compose-Datei funktioniert.

Warum Ports verschwinden, wenn Sie Docker-Container über ein VPN routen

Um Docker-Container über ein VPN zu routen, geben Sie einem Container den Tunnel und verbinden die anderen mit network_mode: "service:gluetun" mit dessen Netzwerk-Namespace. Diese Verbindung sorgt häufig für Überraschungen. Der verbundene Container hat kein eigenes Netzwerk mehr. Deshalb verschwinden seine veröffentlichten Ports und sein Docker-Service-Name. Veröffentlichen Sie die Ports stattdessen am VPN-Container. Andere Container erreichen die Anwendung dann über den Namen des VPN-Containers.

Wenn Sie am verbundenen Container einen ports:-Block belassen, verweigert Docker dessen Erstellung vollständig:

Error response from daemon: conflicting options: port publishing and the container type network mode

Das verwendete Tool ist Gluetun. Dabei handelt es sich um einen Container, der über WireGuard oder OpenVPN eine Verbindung zu einem kommerziellen VPN-Anbieter (virtuelles privates Netzwerk) herstellt und eine eigene Firewall mitbringt. Release v3.41.3 ist im August 2026 aktuell. Die Beispiele verwenden Mullvad mit WireGuard. Sie benötigen daher ein Konto und einen Schlüssel Ihres Anbieters. Wenn Sie den Tunnel lieber auf eigener Hardware terminieren möchten, richtet einen eigenen WireGuard-Server auf einem VPS betreiben die Gegenstelle ein. wg-easy in Docker stellt dafür eine Weboberfläche bereit.

Was network_mode: "service:gluetun" tatsächlich macht

Ein Docker-Container erhält normalerweise einen eigenen Netzwerk-Namespace: eigene Schnittstellen, Routing-Tabelle, Firewall-Regeln und Listening-Sockets. Der Modus service: überspringt diesen Schritt und startet den Container im Namespace von gluetun. Ein Namespace bedeutet eine IP-Adresse. Dadurch ändern sich sechs Dinge.

  • Die Anwendung hat keine eigene Adresse. Ihre Adresse ist die Adresse von gluetun.
  • Die Anwendung ist mit keinem Docker-Netzwerk verbunden. Ihr Servicename wird daher nie registriert und nie aufgelöst. Andere Container müssen gluetun verwenden.
  • Container innerhalb des Namespace erreichen einander über localhost.
  • Zwei Container in einem Namespace können nicht am selben Port lauschen. Die Gluetun-Dokumentation formuliert es eindeutig: Es gibt keine Umgehung.
  • Capabilities gehören zu einem Container, nicht zu einem Namespace. Gluetun besitzt NET_ADMIN und /dev/net/tun, weil es die Tunnel-Schnittstelle erstellt. Der verbundene Container erbt diese Capabilities nicht.
  • Compose lehnt jede Datei ab, in der ein Dienst gleichzeitig network_mode und networks setzt. Verbinden Sie gluetun mit Ihren Netzwerken. Die Anwendung nutzt diese Verbindung mit.

Ein Neustart von gluetun trennt alles, was daran angeschlossen ist. Dieses Verhalten ist dokumentiert. Deshalb startet gluetun den VPN-Prozess innerhalb des Containers neu, anstatt den Container bei einem Verbindungsfehler zu beenden. Nachdem Sie gluetun selbst neu gestartet oder neu erstellt haben, starten Sie die daran angeschlossenen Container neu.

Die funktionierende Compose-Datei

services:
  gluetun:
    image: qmcgaw/gluetun:v3
    container_name: gluetun
    cap_add:
      - NET_ADMIN
    devices:
      - /dev/net/tun:/dev/net/tun
    environment:
      - VPN_SERVICE_PROVIDER=mullvad
      - VPN_TYPE=wireguard
      - SERVER_CITIES=Amsterdam
      - TZ=Europe/Amsterdam
    env_file:
      - ./gluetun.env
    volumes:
      - ./gluetun:/gluetun
    ports:
      - 127.0.0.1:8080:8080/tcp
    restart: unless-stopped

  qbittorrent:
    image: lscr.io/linuxserver/qbittorrent:latest
    container_name: qbittorrent
    network_mode: "service:gluetun"
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Europe/Amsterdam
      - WEBUI_PORT=8080
    volumes:
      - ./qbittorrent:/config
      - ./downloads:/downloads
    depends_on:
      gluetun:
        condition: service_healthy
    restart: unless-stopped

Der Tag :v3 ist das neueste stabile Release der v3-Serie. Der Tag :latest verweist auf den letzten Commit des master-Branches, also auf den Entwicklungsstand. Verwenden Sie daher :v3 auf einem Rechner, auf dem Sie nicht unerwartet Fehler suchen möchten.

WEBUI_PORT=8080 muss dem veröffentlichten Port entsprechen, weil qBittorrent innerhalb des Netzwerk-Namespace von gluetun gebunden wird und die Publish-Regel den Host-Datenverkehr dort an Port 8080 weiterleitet. Wenn Sie eine der beiden Zahlen ändern, antwortet der Port nicht. 127.0.0.1:8080:8080 hält die Weboberfläche an der Loopback-Adresse des Hosts. Ein einfaches 8080:8080 veröffentlicht den Port auf allen Schnittstellen und legt eine eigene Firewall-Regel an. Dadurch können veröffentlichte Docker-Ports direkt an ufw vorbeigehen.

Starten Sie die Container und prüfen Sie sie anschließend in dieser Reihenfolge:

docker compose up -d
docker compose ps
docker compose logs gluetun | tail -30

docker compose ps sollte gluetun als healthy und qbittorrent als running anzeigen. Prüfen Sie anschließend die externe IP-Adresse innerhalb des Namespace. Diese Prüfung entscheidet über alles Weitere:

docker run --rm --network=container:gluetun alpine:3.22 sh -c "apk add wget && wget -qO- https://ipinfo.io"

Das Feld ip in dieser JSON-Antwort sollte die Adresse Ihres VPN-Anbieters enthalten. Wenn dort die eigene Adresse Ihres Servers steht, befindet sich die Anwendung nicht im Tunnel. Dann funktioniert nichts im weiteren Verlauf wie beschrieben.

Halten Sie die Schlüssel aus der Compose-Datei heraus

gluetun.env enthält die Zugangsdaten und bleibt außerhalb von Git:

WIREGUARD_PRIVATE_KEY=wOEI9rqqbDwnN8/Bpp22sVz48T71vJ4fYmFWujulwUU=
WIREGUARD_ADDRESSES=10.64.222.21/32

Beide Werte stammen aus einer WireGuard-Konfigurationsdatei, die Sie im Kontobereich Ihres Providers erzeugen. Setzen Sie die Dateiberechtigungen auf 600. Machen Sie sich klar, was dadurch erreicht wird: Der Schlüssel bleibt aus Ihrem Repository heraus, aber docker inspect gluetun gibt weiterhin jede Umgebungsvariable für alle aus, die Zugriff auf den Docker-Socket haben. Umgebungsdateien und Secrets in Docker Compose beschreibt die besseren Optionen.

Wie ein Container außerhalb des Tunnels mit einem Container innerhalb des Tunnels kommuniziert

Beide Richtungen funktionieren. Für jede Richtung wird ein anderer Name verwendet. Die beiden Container benötigen ein gemeinsames Docker-Netzwerk. Das ist das Netzwerk von gluetun, da der angehängte Container kein eigenes Netzwerk besitzt. So sind Docker-Compose-Netzwerke verbunden erläutert die Standardeinstellungen.

Für Verbindungen von außen nach innen verwenden Sie den Namen von gluetun und den Port, auf dem die Anwendung lauscht. Ein Reverse-Proxy-Container erreicht die Weboberfläche von qBittorrent unter gluetun:8080. Dafür ist kein Eintrag ports: erforderlich, weil der Datenverkehr zwischen Containern im Docker-Netzwerk bleibt und keinen Host-Port verwendet.

Für Verbindungen von innen nach außen verwenden Sie den Servicenamen des anderen Containers, zum Beispiel postgres:5432. Gluetun löst andere Containernamen seit v3.41 innerhalb seines Netzwerk-Namespace auf. Wenn ein Name nicht aufgelöst wird, pinnen Sie daher diese Version oder eine neuere Version.

Die Firewall von Gluetun entscheidet, wer eine Verbindung zu Gluetun öffnen darf. Datenverkehr aus dem eigenen Docker-Netzwerk von gluetun ist erlaubt. Ein Client aus einem anderen Subnetz, ein Laptop in Ihrem LAN oder ein Container in einem separaten Bridge-Netzwerk wird verworfen, bis Sie dieses Subnetz angeben:

FIREWALL_OUTBOUND_SUBNETS=192.168.1.0/24

Die dokumentierte Bedeutung ist genau: kommagetrennte Subnetze, auf die Gluetun und die Container mit seinem Netzwerk-Stack zugreifen dürfen.

Eingehende Verbindungen aus dem Internet sind ein separates Problem. Peers eines Torrent-Clients erreichen ihn über die VPN-Seite. Daher bewirkt die Veröffentlichung von Port 6881 auf dem Host nichts. Sie benötigen einen weitergeleiteten Port von Ihrem Anbieter und müssen diesen Port in FIREWALL_VPN_INPUT_PORTS angeben. Dadurch werden Ports von der Seite des VPN-Servers zugelassen. Genau dieser Teil bleibt in den meisten mit Docker Compose erstellten Media-Stacks fehlerhaft.

Der Kill Switch: Was passiert, wenn der Tunnel ausfällt

Dieses Muster rechtfertigt seine Komplexität im Fehlerfall. Der angebundene Container hat keine zweite Route. Sein einziger Weg aus der Maschine führt über den Namespace, den er gemeinsam nutzt. Wenn der Tunnel ausfällt, gibt es daher keinen Ausweichweg. Die Firewall von Gluetun erzwingt dieselbe Regel von der anderen Seite: Ausgehender Datenverkehr läuft über den Tunnel oder zum Endpunkt des VPN-Servers. Alles andere wird verworfen. Es gibt kein Zeitfenster, in dem Pakete während der Wiederherstellung der Verbindung über das normale Interface nach außen gelangen.

Gluetun überwacht seine eigene Verbindung. Jede Minute sendet es einen ICMP-Echo-Request (Ping) an die Adressen in HEALTH_ICMP_TARGET_IPS. Standardmäßig ist dort 1.1.1.1,8.8.8.8 eingetragen. Alle fünf Minuten baut es eine vollständige TCP- und TLS-Verbindung (Transport Layer Security) zu HEALTH_TARGET_ADDRESSES auf. Der Standardwert ist cloudflare.com:443,github.com:443. Wenn diese Prüfungen fehlschlagen, startet Gluetun das VPN im Container neu und schreibt dies ins Log:

WARN [vpn] restarting VPN because it failed to pass the healthcheck: periodic check: dialing: dial tcp4: lookup cloudflare.com: i/o timeout

Lesen Sie die Logs des angebundenen Containers mit diesem Ablauf im Hinterkopf. Zeilen wie connection refused, operation not permitted und i/o timeout innerhalb der Anwendung sind Folgen eines ausgefallenen Tunnels und keine Ursachen. Die Gluetun-Dokumentation weist ausdrücklich darauf hin, weil gemeldete Folgen sonst stundenlang untersucht werden, obwohl die eigentliche Ursache an anderer Stelle liegt.

HEALTH_RESTART_VPN=on ist standardmäßig aktiviert und sollte aktiviert bleiben. Deaktivieren Sie es nur, wenn Sie gezielt einen bestimmten Fehler untersuchen. Andernfalls bleibt ein ausgefallener Tunnel ausgefallen.

Reihenfolge: Der Stack darf erst starten, wenn der Tunnel aktiv ist

Das Image enthält einen Docker-Healthcheck:

HEALTHCHECK --interval=5s --timeout=5s --start-period=10s --retries=1 CMD /gluetun-entrypoint healthcheck

Dieser Befehl startet eine zweite, kurzlebige Instanz von gluetun. Sie fragt den Health-Server der laufenden Instanz unter http://127.0.0.1:9999/ ab. Ein funktionierender Tunnel antwortet mit 200 OK. Ein fehlerhafter Tunnel antwortet mit 500 Internal server error und einer Fehlerzeichenfolge. Nach einem einzigen Fehlschlag wird der Container als fehlerhaft markiert.

condition: service_healthy wartet auf diesen Zustand. Das einfache depends_on: [gluetun] wartet nur, bis der Container gestartet wurde. Das geschieht mehrere Sekunden vor Abschluss des Handshakes. Die Anwendung startet daher in einem nicht funktionierenden Netzwerk und gibt den ersten Verbindungsversuch häufig auf. Healthchecks in Docker Compose erläutert die Syntax und die Zeitsteuerungsfelder.

Eine Einschränkung führt häufig zu Problemen. Compose wertet diese Bedingung einmal aus, wenn der Container erstellt wird. Wenn gluetun später fehlerhaft wird, stoppt oder startet Compose die Anwendung nicht automatisch neu. In diesem Fall greift stattdessen die interne Auto-Healing-Funktion von gluetun. Deshalb startet sie den VPN-Prozess und nicht den Container neu.

Prüfen Sie vor dem Vertrauen in die Konfiguration auf DNS-Leaks

DNS (Domain Name System) ist der Leak, der auch bei einem korrekt eingerichteten Tunnel bestehen bleibt. Gluetun verwendet seinen eigenen Resolver innerhalb des Namespace und leitet Abfragen standardmäßig über DoT (DNS over TLS) an Cloudflare weiter: DNS_UPSTREAM_RESOLVER_TYPE=dot und DNS_UPSTREAM_RESOLVERS=cloudflare. Lassen Sie beide Einstellungen unverändert. Ihre DNS-Abfragen sind dann verschlüsselt und werden durch den Tunnel übertragen.

Die Einstellung, die dies verhindert, ist DNS_UPSTREAM_PLAIN_ADDRESSES. Sie wird häufig aktiviert, wenn ein Name nicht aufgelöst werden kann und stattdessen der Router oder der Resolver des Providers antworten soll. Die Gluetun-Dokumentation beschreibt die Konsequenz eindeutig: Der gesamte DNS-Verkehr wird nicht durch den VPN-Tunnel übertragen, sondern verlässt ihn und wird dadurch offengelegt. Ihr Datenverkehr bleibt privat. Die Liste der aufgerufenen Hostnamen jedoch nicht. Die entsprechende Fehlkonfiguration bei WireGuard wird unter DNS, das über einen WireGuard-Tunnel nicht mehr aufgelöst wird beschrieben.

Setzen Sie für den Test HTTPPROXY=on auf gluetun und veröffentlichen Sie 8888:8888/tcp. Richten Sie anschließend einen Browser auf diesen Proxy und laden Sie einen DNS-Leak-Test. Das Ergebnis sollte Ihren Provider oder Cloudflare nennen, niemals Ihren Heimrouter. Die Gluetun-Dokumentation weist darauf hin, dass einige Leak-Tests ungewöhnliche Ergebnisse anzeigen. Der Resolver innerhalb des Namespace ist ein lokaler zwischenspeichernder Vermittler und nicht der Server, der die Anfrage letztlich beantwortet. Ein falsches Land oder der Resolver Ihres eigenen ISP ist daher das relevante Signal.

Tailscale neben dem VPN-Sidecar hinzufügen und welches davon Vorrang hat

Tailscale ist ein auf WireGuard basierendes Overlay-Netzwerk, mit dem Sie Ihre eigenen Systeme erreichen können. Viele Betreiber verwenden es neben einem Provider-VPN, um einen administrativen Zugang zur Umgebung zu behalten. Die beiden Netzwerke kommen sich nur selten in die Quere. Der Grund dafür ist wichtig. Die Tailscale-Dokumentation beschreibt das Standardverhalten: Tailscale fungiert als Overlay-Netzwerk, leitet nur Datenverkehr zwischen Geräten mit aktiviertem Tailscale weiter und verändert den öffentlichen Internetverkehr nicht.

Die Antwort hängt daher von einer Einstellung ab.

  • Tailscale in einem eigenen Container mit der Standardkonfiguration: Tailscale sieht den ausgehenden Datenverkehr der Anwendung nie. Gluetun übernimmt den gesamten Datenverkehr. Tailscale erreicht die Anwendung über gluetun:8080, genau wie jeder andere externe Container.
  • Tailscale am Namespace von gluetun mit network_mode: "service:gluetun": Tailscale benötigt ein eigenes cap_add von net_admin und net_raw, weil Berechtigungen nicht automatisch mit dem Namespace übernommen werden. Im standardmäßigen Userspace-Networking-Modus ist TS_USERSPACE aktiviert. tailscaled erstellt dann überhaupt kein Interface und arbeitet als SOCKS5- oder HTTP-Proxy. Daher kann es das Routing nicht ändern. Gluetun übernimmt weiterhin den gesamten Datenverkehr.
  • Dasselbe mit TS_USERSPACE=false: tailscaled erstellt ein Tunnelgerät und installiert Routen, jedoch nur für den Tailnet-Bereich 100.64.0.0/10 sowie für Subnetzrouten, die Sie mit TS_ROUTES bekanntgeben. Der öffentliche Datenverkehr wird weiterhin über gluetun geleitet.
  • Jede der genannten Varianten mit ausgewähltem Exit Node, sudo tailscale set --exit-node=<exit-node-ip>: Tailscale übernimmt die Standardroute und hat Vorrang. Kombinieren Sie diese Konfiguration nicht mit gluetun. Eine Standardroute hat genau einen Besitzer.

Wenn diese bekanntgegebenen Routen der eigentliche Zweck sind und Sie das gesamte private Netzwerk hinter dem System erreichen möchten statt nur das System selbst, beschreibt einen Tailscale-Subnet-Router auf einem VPS betreiben die Routenfreigabe, IP-Weiterleitung und das clientseitige Flag, das TS_ROUTES allein nicht setzt.

Wenn Tailscale Ihnen eine administrative URL statt einer Route bereitstellen soll, setzen tailscale serve und tailscale funnel HTTPS für Ihr Tailnet vor gluetun:8080. Nur funnel macht den Dienst im öffentlichen Internet erreichbar.

Ein Nebeneffekt wird sichtbar, wenn Tailscale innerhalb des Tunnels ausgeführt wird. Die Peers sehen dann die Adresse des VPN-Providers. Daher verwendet Tailscale häufiger Relays. tailscale status zeigt neben einem Peer relay "..." statt direct an, wenn dies geschehen ist. Die Verbindung funktioniert, ist aber langsamer. Wenn Sie tatsächlich nur das Overlay benötigen, ist der Unterschied zwischen einfachem WireGuard und Tailscale der bessere Ausgangspunkt.

Was fehlschlägt und welche Meldung angezeigt wird

Docker verweigert die Erstellung des App-Containers. Error response from daemon: conflicting options: port publishing and the container type network mode bedeutet, dass auf dem angebundenen Dienst noch ein ports:-Block vorhanden ist. Verschieben Sie ihn zu gluetun.

Compose verweigert die gesamte Datei. Ein Dienst kann nicht gleichzeitig network_mode und networks setzen. Legen Sie die Netzwerke auf gluetun.

Ein anderer Container kann die App nicht auflösen. curl: (6) Could not resolve host: qbittorrent ist das erwartete Verhalten, weil der angebundene Container keinem Netzwerk beigetreten ist und keinen Namen registriert hat. Verwenden Sie gluetun und den Port.

Der zweite angebundene Container startet nicht. Zwei Prozesse in demselben Namespace können nicht an denselben Port gebunden werden. Der unterlegene Prozess meldet, dass die Adresse bereits verwendet wird. Ändern Sie den internen Port der App oder starten Sie ein zweites gluetun.

Die App hat kein Netzwerk mehr, nachdem Sie gluetun geändert haben. Durch einen Neustart oder eine Neuerstellung von gluetun verlieren alle daran angebundenen Container ihre Verbindung. Starten Sie diese Container neu.

Kleine Seiten werden geladen, große Seiten bleiben hängen. Das ist ein MTU-Problem (Maximum Transmission Unit). Der Tunnel fügt zusätzlichen Overhead hinzu. Irgendwo im Übertragungsweg werden die zu großen Pakete verworfen, ohne dass ein Fehler zurückgemeldet wird. Verringern Sie WIREGUARD_MTU, versuchen Sie 1400 und anschließend 1320.

Gluetun wird nie als fehlerfrei gemeldet. Die Startprüfung nennt die ersten Verdächtigen: WARN [vpn] restarting VPN because it failed to pass the healthcheck: startup check: dialing: dial tcp4: lookup cloudflare.com: i/o timeout. Prüfen Sie, ob der Schlüssel abgelaufen ist. Prüfen Sie anschließend, ob die Serverliste veraltet ist und ob die Firewall auf dem Host ausgehendes UDP blockiert.

FAQ

Warum funktionieren die veröffentlichten Ports meines Containers hinter Gluetun nicht mehr?

Weil network_mode: "service:gluetun" den Container in den Netzwerk-Namensraum von gluetun einbindet. Ein Namensraum hat eine IP-Adresse und einen Satz lauschender Ports. Die Anwendung lauscht weiterhin, aber die Portfreigabe muss auf dem Container definiert sein, dem der Namensraum gehört. Verschieben Sie die Liste ports: in den gluetun-Service. Wenn sie beim eingebundenen Service verblieben ist, erstellt Docker den Service nicht einmal: Error response from daemon: conflicting options: port publishing and the container type network mode.

Wie erreiche ich einen Container innerhalb des VPN-Tunnels von einem Container außerhalb des Tunnels?

Verwenden Sie den Servicenamen von gluetun und den Port, auf dem die Anwendung lauscht, zum Beispiel gluetun:8080. Der eingebundene Container gehört keinem eigenen Docker-Netzwerk an. Deshalb wird sein eigener Name nie aufgelöst. Für Datenverkehr zwischen Containern ist keine Veröffentlichung erforderlich. In die andere Richtung erreicht ein Container innerhalb des Namensraums einen Container außerhalb über dessen Servicenamen, beispielsweise postgres:5432, ab Gluetun v3.41. Ein Client in einem anderen Subnetz, etwa ein Laptop in Ihrem LAN, wird von der Firewall von gluetun verworfen, bis Sie dieses Subnetz zu FIREWALL_OUTBOUND_SUBNETS hinzufügen.

Funktioniert Gluetun als Kill Switch, wenn die VPN-Verbindung abbricht?

Ja, und zwar aus zwei Gründen gleichzeitig. Der eingebundene Container hat außer der Route im gemeinsam genutzten Namensraum keine weitere Route. Wenn der Tunnel ausfällt, hat er daher keinen Pfad aus dem Rechner heraus. Die Firewall von Gluetun erlaubt ausgehenden Datenverkehr außerdem nur durch den Tunnel und zum Endpunkt des VPN-Servers. Gluetun startet das VPN intern anschließend neu und protokolliert WARN [vpn] restarting VPN because it failed to pass the healthcheck, statt den Prozess zu beenden. Andernfalls würde jeder eingebundene Container seine Netzwerkverbindung verlieren, sobald gluetun selbst neu startet.

Tailscale und Gluetun im selben Stack: Welcher Dienst leitet ausgehenden Datenverkehr weiter?

Gluetun, außer in einer Konfiguration. Tailscale leitet standardmäßig nur Datenverkehr zwischen Geräten in Ihrem Tailnet weiter und lässt öffentlichen Datenverkehr unverändert. Im standardmäßigen Userspace-Modus des Container-Images erstellt Tailscale überhaupt kein Interface und kann daher das Routing nicht beeinflussen. Mit TS_USERSPACE=false installiert Tailscale nur Routen für 100.64.0.0/10 und Ihre angekündigten Subnetze. Die Ausnahme ist ein Exit Node: sudo tailscale set --exit-node=<exit-node-ip> macht Tailscale zur Standardroute, die dann verwendet wird. Legen Sie fest, welches Produkt die Standardroute verwaltet, statt beide zu kombinieren.