Container im Rechenzentrum – sicher erreichbar

Eine Applikation läuft im Rechenzentrum. Sie enthält sensible Daten: Kundendaten, interne Systeme, Produktionsdatenbanken. Direkt über das öffentliche Internet erreichbar zu sein ist keine Option – zu groß das Angriffspotential, zu hoch die Compliance-Anforderungen.

Die klassische Lösung: ein VPN-Tunnel zwischen dem Rechenzentrum und dem eigenen Netzwerk. Jede Verbindung zu den Applikationen läuft verschlüsselt durch diesen Tunnel – von außen ist nichts sichtbar, kein Port offen, keine Angriffsfläche.

Gluetun bringt dieses Konzept in die Docker-Welt. Ein Container baut den VPN-Tunnel auf, alle anderen Container hängen sich an seinen Netzwerk-Stack – ohne eigene VPN-Konfiguration, ohne Änderungen am Host-System.

⚠️ Niveau: Fortgeschritten. Kenntnisse in Docker Networking, VPN-Konzepten und Netzwerksegmentierung werden vorausgesetzt.


Anwendungsfall: Site-to-Datacenter

Firmennetzwerk (Standort)          Rechenzentrum
┌─────────────────────┐            ┌──────────────────────────┐
│                     │            │                          │
│  Mitarbeiter-PCs    │            │  Docker Host             │
│  interne Systeme    │            │  ┌────────────────────┐  │
│                     │◄─────────────►│      Gluetun       │  │
│  VPN-Gateway        │ WireGuard  │  │   VPN-Endpunkt     │  │
│                     │  Tunnel    │  └────────┬───────────┘  │
│                     │            │           │              │
└─────────────────────┘            │  ┌────────▼───────────┐  │
                                   │  │    Applikation A   │  │
                                   │  │    Applikation B   │  │
                                   │  │    Datenbank       │  │
                                   │  └────────────────────┘  │
                                   │                          │
                                   │  Kein Port nach außen    │
                                   │  offen – nur VPN-Zugang  │
                                   └──────────────────────────┘

Die Applikationen sind vom öffentlichen Internet vollständig isoliert. Erreichbar sind sie ausschließlich über den verschlüsselten WireGuard-Tunnel. Selbst wenn der Docker-Host kompromittiert wäre – ohne aktiven Tunnel kein Zugriff auf die Dienste.


Was ist Gluetun?

Gluetun ist ein Docker-Container der als VPN-Gateway für andere Container fungiert. Er unterstützt WireGuard und OpenVPN sowie über 70 VPN-Anbieter und benutzerdefinierte Konfigurationen.

Für professionelle Umgebungen relevant sind:

  • WireGuard-Support – modernes, performantes VPN-Protokoll mit minimalem Overhead
  • Integrierter Kill-Switch – bricht der Tunnel ab, blockiert Gluetun sofort allen Traffic der betroffenen Container
  • Feingranulare Firewall – ausgehende Verbindungen können auf bestimmte Subnetze beschränkt werden
  • network_mode: service: – Container teilen den Netzwerk-Stack von Gluetun ohne eigene Konfiguration

Das Kernkonzept: network_mode: service:

In Docker hat jeder Container normalerweise einen eigenen Netzwerk-Stack. Mit network_mode: service:gluetun entfällt das:

app-service:
  network_mode: "service:gluetun"

Der Container bekommt keinen eigenen Stack – er teilt vollständig den von Gluetun. Dasselbe Interface, dieselbe IP, dieselben Routen, denselben Tunnel.

Standardkonfiguration:
┌─────────────────┐    ┌─────────────────┐
│   app-service   │    │    Gluetun      │
│  eigene IP      │    │  VPN-Tunnel     │
│  eigene Routen  │    │                 │
└────────┬────────┘    └────────┬────────┘
     direkt Internet        VPN-Tunnel

Mit network_mode: service:gluetun:
┌──────────────────────────────────┐
│  Gluetun    │    app-service     │
│             │  (kein eigener     │
│          VPN-Tunnel  Stack)      │
└──────────────────┬───────────────┘
           ausschließlich VPN

Fällt der Tunnel aus, greift der Kill-Switch – app-service hat keine Netzwerkverbindung mehr bis der Tunnel wieder steht. Kein versehentlicher Klartext-Traffic über die Host-IP.

Ports – zentral bei Gluetun

Da alle Container denselben Netzwerk-Stack teilen, werden Ports ausschließlich am Gluetun-Container definiert. Ein ports:-Block an einem abhängigen Container wird ignoriert. Für Dienste die ausschließlich über den VPN-Tunnel erreichbar sein sollen, werden gar keine Ports nach außen geöffnet – der Zugriff erfolgt nur durch den Tunnel.


Architektur

                    Internet
                       │
              nur VPN-Port (UDP 51820)
                       │
        ┌──────────────▼──────────────┐
        │           Gluetun           │
        │    WireGuard VPN-Endpunkt   │
        │    Kill-Switch Firewall     │
        │    cap_add: NET_ADMIN       │
        └──────────────┬──────────────┘
                       │ geteilter Netzwerk-Stack
         ┌─────────────┼─────────────┐
         │             │             │
  ┌──────▼──────┐ ┌────▼────┐ ┌─────▼──────┐
  │ Applikation │ │   API   │ │ Datenbank  │
  │      A      │ │ Service │ │            │
  └─────────────┘ └─────────┘ └────────────┘

  Alle Container:
  - Kein direkter Internetzugang
  - Nur über VPN-Tunnel erreichbar
  - Kill-Switch bei Tunnelausfall

docker-compose.yml

services:
  gluetun:
    image: qmcgaw/gluetun
    container_name: gluetun
    restart: unless-stopped
    cap_add:
      - NET_ADMIN
    environment:
      - VPN_SERVICE_PROVIDER=custom
      - VPN_TYPE=wireguard
      - WIREGUARD_PRIVATE_KEY=${WIREGUARD_PRIVATE_KEY}
      - WIREGUARD_ADDRESSES=${WIREGUARD_ADDRESSES}
      - WIREGUARD_PUBLIC_KEY=${WIREGUARD_PUBLIC_KEY}
      - WIREGUARD_ENDPOINT_IP=${WIREGUARD_ENDPOINT_IP}
      - WIREGUARD_ENDPOINT_PORT=51820
      - FIREWALL_OUTBOUND_SUBNETS=${INTERNAL_SUBNET}
    volumes:
      - ./gluetun:/gluetun
    networks:
      - vpn_internal

  app-service:
    image: ihre-applikation:latest
    container_name: app-service
    restart: unless-stopped
    network_mode: "service:gluetun"
    depends_on:
      - gluetun
    volumes:
      - ./app-data:/data

networks:
  vpn_internal:
    name: vpn_internal
    driver: bridge

cap_add: NET_ADMIN

Gluetun benötigt NET_ADMIN um WireGuard-Interfaces, Routing-Tabellen und iptables-Regeln im Container verwalten zu können. Ohne diese Capability kann kein Tunnel aufgebaut und keine Kill-Switch-Firewall konfiguriert werden.

VPN_SERVICE_PROVIDER=custom

environment:
  - VPN_SERVICE_PROVIDER=custom
  - VPN_TYPE=wireguard
  - WIREGUARD_PRIVATE_KEY=${WIREGUARD_PRIVATE_KEY}
  - WIREGUARD_PUBLIC_KEY=${WIREGUARD_PUBLIC_KEY}
  - WIREGUARD_ENDPOINT_IP=${WIREGUARD_ENDPOINT_IP}
  - WIREGUARD_ENDPOINT_PORT=51820

custom erlaubt die Verwendung eines selbst betriebenen WireGuard-Servers statt eines kommerziellen Anbieters. Die Verbindungsparameter kommen direkt aus der WireGuard-Konfiguration des Gegenstücks – typischerweise ein VPN-Gateway am Firmenstandort oder ein dedizierter WireGuard-Server im eigenen Netzwerk.

FIREWALL_OUTBOUND_SUBNETS

- FIREWALL_OUTBOUND_SUBNETS=192.168.100.0/24

Gluetun blockiert standardmäßig allen Traffic der nicht durch den Tunnel geht. FIREWALL_OUTBOUND_SUBNETS definiert Subnetze die direkt – ohne VPN – erreichbar sein sollen. Sinnvoll für lokale Dienste wie einen Authentifizierungsserver der sich im selben Rechenzentrum befindet und nicht durch den Tunnel geroutet werden muss.


.env-Datei

Alle sensitiven Verbindungsparameter gehören ausnahmslos in eine .env-Datei:

WIREGUARD_PRIVATE_KEY=<privater-schlüssel-des-containers>
WIREGUARD_PUBLIC_KEY=<öffentlicher-schlüssel-des-gegenstücks>
WIREGUARD_ADDRESSES=10.x.x.x/32
WIREGUARD_ENDPOINT_IP=<ip-des-vpn-gateways>
INTERNAL_SUBNET=192.168.100.0/24
.env
gluetun/

Traefik-Integration

Wenn Traefik als Reverse Proxy eingesetzt wird, hängen die Labels an Gluetun – nicht an den Applikations-Containern, da diese keinen eigenen Netzwerk-Stack haben:

gluetun:
  labels:
    - "traefik.enable=true"
    - "traefik.http.routers.app.rule=Host(`app.example.com`)"
    - "traefik.http.routers.app.entrypoints=websecure"
    - "traefik.http.routers.app.tls.certresolver=hetzner"
    - "traefik.http.routers.app.service=app-svc"
    - "traefik.http.services.app-svc.loadbalancer.server.port=8080"
  networks:
    - vpn_internal
    - proxy

Für jeden Dienst hinter Gluetun wird ein eigener named Service definiert damit Traefik den richtigen Port ansteuert.


Start & Verifikation

# Zuerst nur Gluetun starten und Tunnel prüfen
docker compose up -d gluetun
docker logs gluetun | grep -i "connected\|tunnel\|ip"

# Netzwerk-Stack des Tunnels prüfen
docker exec gluetun wget -qO- ifconfig.me

# Erst nach bestätigtem Tunnel die Applikationen starten
docker compose up -d

Häufige Fehler

Container startet, hat aber keinen Netzwerkzugriff: Gluetun läuft, aber der Tunnel ist noch nicht aufgebaut. depends_on garantiert nur den Container-Start, nicht eine aktive VPN-Verbindung. In produktiven Umgebungen empfiehlt sich ein Healthcheck auf Gluetun.

Ports nicht erreichbar: Port beim Applikations-Container statt bei Gluetun definiert. Alle Ports müssen bei Gluetun stehen.

Lokale Dienste nicht erreichbar: Das Ziel-Subnetz fehlt in FIREWALL_OUTBOUND_SUBNETS. Gluetun blockiert standardmäßig alles was nicht durch den Tunnel geht.

Traefik routet nicht: Gluetun ist nicht im proxy-Netzwerk. Traefik kann nur Container erreichen die im selben Netzwerk liegen.


Fazit

network_mode: service:gluetun löst ein ernstes Infrastrukturproblem elegant: Applikationen mit sensiblen Daten im Rechenzentrum betreiben, ohne sie dem öffentlichen Internet auszusetzen. Der VPN-Tunnel ist die einzige Verbindung – alle anderen Netzwerkwege sind durch den Kill-Switch versiegelt. Die zentrale Konfiguration bei Gluetun hält die Applikations-Container frei von Netzwerk-Komplexität und macht das Setup wartbar und auditierbar.