Design wechseln

Docker-Container auf den Host zugreifen: Vollständiger Leitfaden zu host.docker.internal

Easton editorial illustration: observability control panel

Freitagnachmittag, 15 Uhr – ich starre auf die Fehlermeldung im Terminal: Connection refused.

Ehrlich gesagt war ich ziemlich frustriert. MySQL lief lokal einwandfrei, Navicat verband sich, die Kommandozeile funktionierte – nur die Anwendung im Container wollte nicht verbinden. Dreimal die Connection String geprüft: localhost:3306, alles korrekt. Benutzername und Passwort stimmten. Wo lag das Problem?

Am Ende war es das Wort localhost.

Wenn Ihnen das bekannt vorkommt – im Docker-Container schlägt die Verbindung zum Host über localhost oder 127.0.0.1 ständig fehl – ist dieser Artikel für Sie. Ich erkläre klar und direkt: Warum localhost im Container nicht das ist, was Sie erwarten, und wie Sie mit host.docker.internal elegant eine Lösung finden.

In diesem Artikel lernen Sie:

  • Die wirkliche Ursache der Netzwerk-Isolation (ohne Fachjargon)
  • Die richtige Konfiguration für Mac, Windows und Linux
  • Eine praktische Troubleshooting-Checkliste zum Nachschlagen

Warum localhost nicht funktioniert

Kurz gesagt: Der Container hat seine eigene Netzwerk-Welt.

Klingt abstrakt? Stellen Sie sich den Container als separates kleines Haus vor – mit eigener Adresse, eigenem Briefkasten, allem drum und dran. Wenn Sie im Container „localhost“ rufen oder 127.0.0.1 ansprechen, suchen Sie dieses Haus selbst – nicht den Host außerhalb.

Konkret:

  • Auf dem Host zeigt localhost auf den Host selbst
  • Im Container zeigt localhost auf den Container selbst
  • Zwei localhost – völlig verschiedene Dinge

Als ich das zum ersten Mal hörte, war ich überrascht. MySQL lief doch auf meinem Rechner – warum konnte der Container nicht verbinden? Genau deshalb: Der Container sucht MySQL in seiner eigenen Welt und findet es natürlich nicht.

Netzwerk-Isolation des Containers

Docker erstellt für jeden Container einen eigenen „Netzwerk-Namespace“ (keine Sorge wegen des Begriffs). Vereinfacht:

Jeder Container hat seine eigene Netzwerkkarte, eigene IP und eigene Routing-Tabelle. Wie zwei Wohnungen im selben Gebäude – gleicher Standort, aber getrennte Netzwerke.

Container und Host sind über die virtuelle Bridge docker0 verbunden. Container-IPs sind meist 172.17.0.x; aus Sicht des Containers ist der Host 172.17.0.1 (Gateway der Bridge).

localhost im Container meint 127.0.0.1 des Containers – nicht des Hosts. Deshalb schlägt die Verbindung zur MySQL auf dem Host fehl.

Typische Fehlermeldungen:

Error: connect ECONNREFUSED 127.0.0.1:3306

oder:

Can't connect to MySQL server on 'localhost' (111)

Klassischer Fehler: localhost im Container, um Host-Dienste zu erreichen.

Was ist host.docker.internal?

Wenn localhost nicht geht – wie erreicht der Container den Host?

Docker bietet eine elegante Lösung: host.docker.internal. Das ist eine spezielle Domain, die automatisch zur Host-IP aufgelöst wird. Denken Sie daran als „Spitzname“ des Hosts – unabhängig von der echten IP.

Beispiel: MySQL lauscht auf dem Host auf Port 3306 – im Container verbinden Sie so:

mysql://user:[email protected]:3306/dbname

Egal ob der Host 192.168.1.100 oder 10.0.0.5 hat – host.docker.internal zeigt immer auf die richtige Adresse.

Praktisch, oder?

Versionen und Plattform-Unterstützung

Hier gibt es eine wichtige Einschränkung.

Mac und Windows (Docker Desktop)

Mit Docker Desktop (der Version mit GUI) wird host.docker.internal seit Version 18.03 (März 2018) nativ unterstützt. Out of the box, keine Extra-Konfiguration.

Einfach im Code host.docker.internal verwenden:

const mysql = require('mysql2');
const connection = mysql.createConnection({
  host: 'host.docker.internal',  // So einfach
  port: 3306,
  user: 'root',
  password: 'your_password'
});

Linux (Docker Engine)

Auf Linux ist es anders. Docker läuft direkt auf dem System – ohne VM-Zwischenschicht wie auf Mac/Windows. host.docker.internal existiert standardmäßig nicht.

Ab Docker Engine 20.10 (Dezember 2020) lässt sich das manuell aktivieren. Wie genau, erkläre ich im nächsten Abschnitt.

Bei älteren Versionen gibt es Alternativen:

  • 172.17.0.1 (Standard-Gateway der Docker-Bridge)
  • Die tatsächliche Host-IP im Docker-Netzwerk
  • docker.for.mac.host.internal (nur ältere Mac-Versionen)

Konfiguration auf drei Plattformen

Hier die praxisnahen, kopierbaren Konfigurationen.

Mac/Windows (Docker Desktop)

Der einfachste Fall.

Methode 1: Direkt im Code

Keine Extra-Konfiguration nötig – einfach host.docker.internal verwenden:

# docker-compose.yml
version: '3'
services:
  app:
    image: myapp:latest
    environment:
      - DB_HOST=host.docker.internal  # Direkt nutzen
      - DB_PORT=3306

Methode 2: Explizit deklarieren (optional)

Nicht erforderlich, aber möglich mit extra_hosts:

version: '3'
services:
  app:
    image: myapp:latest
    extra_hosts:
      - "host.docker.internal:host-gateway"
    environment:
      - DB_HOST=host.docker.internal

host-gateway ist die Syntax ab Docker 20.10+ und bedeutet „Gateway-Adresse des Hosts“.

Mit docker run:

docker run -d \
  --add-host=host.docker.internal:host-gateway \
  -e DB_HOST=host.docker.internal \
  myapp:latest

Linux (Docker Engine)

Auf Linux etwas mehr Aufwand – manuelle Konfiguration nötig.

Methode 1: Empfohlen – host-gateway

Allgemeinste Methode für Docker 20.10+ auf allen Plattformen:

# docker-compose.yml
version: '3'
services:
  app:
    image: myapp:latest
    extra_hosts:
      - "host.docker.internal:host-gateway"  # Schlüssel-Konfiguration
    environment:
      - DB_HOST=host.docker.internal
      - DB_PORT=3306

Mit docker run:

docker run -d \
  --add-host=host.docker.internal:host-gateway \
  -e DB_HOST=host.docker.internal \
  myapp:latest

Vorteil: plattformübergreifend – dieselbe Konfiguration auf Mac, Windows und Linux.

Methode 2: Alternative – Docker-Bridge-IP

Wenn host-gateway nicht verfügbar ist (alte Docker-Version):

version: '3'
services:
  app:
    image: myapp:latest
    extra_hosts:
      - "host.docker.internal:172.17.0.1"  # Standard-Gateway
    environment:
      - DB_HOST=host.docker.internal

172.17.0.1 ist das Standard-Gateway des Docker-Bridge-Netzwerks. In den meisten Fällen korrekt, sofern Sie die Standard-Netzwerk-Konfiguration nicht geändert haben.

Methode 3: Ultimative Lösung – Host-Netzwerkmodus

Wenn nichts anderes hilft:

docker run -d \
  --network=host \
  -e DB_HOST=localhost \  # Jetzt funktioniert localhost
  myapp:latest

Oder in docker-compose:

version: '3'
services:
  app:
    image: myapp:latest
    network_mode: "host"  # Host-Netzwerk nutzen
    environment:
      - DB_HOST=localhost  # localhost geht direkt

Vorteile: Einfach – der Container nutzt den Netzwerk-Stack des Hosts; localhost ist wirklich localhost.

Nachteile:

  • Zerstört die Netzwerk-Isolation des Containers
  • Gemeinsame Ports mit dem Host, Konflikte möglich (z. B. Port 8080)
  • Nur auf Linux, nicht auf Mac/Windows
  • In Produktion nicht empfohlen – nur für lokale Entwicklung

Plattformübergreifende Konfiguration (stark empfohlen)

Wenn im Team Mac und Linux gemischt sind oder der Code in verschiedenen Umgebungen läuft:

# docker-compose.yml
version: '3'
services:
  app:
    image: myapp:latest
    extra_hosts:
      - "host.docker.internal:host-gateway"  # Auf allen Plattformen bekannt
    environment:
      - DB_HOST=host.docker.internal
      - DB_PORT=3306
      - DB_USER=root
      - DB_PASSWORD=your_password

Diese Konfiguration funktioniert auf Docker 20.10+ (Ende 2020) auf allen Plattformen. Wenn Ihre Docker-Version älter ist – ehrlich gesagt, Zeit für ein Upgrade.

Wichtige Host-Dienst-Konfiguration

Die Container-Seite allein reicht nicht.

Auch die Dienste auf dem Host müssen richtig konfiguriert sein – sonst schlägt die Verbindung trotzdem fehl. Das übersehen viele.

Dienst muss auf der richtigen Adresse lauschen

Der häufigste Stolperstein.

Viele Dienste lauschen standardmäßig nur auf 127.0.0.1 – also nur lokale Verbindungen. Docker-Container gelten nicht als „lokal“; Anfragen über die Docker-Bridge werden abgelehnt.

Der Dienst muss auf 0.0.0.0 lauschen – „alle Netzwerkschnittstellen“.

MySQL-Konfiguration

MySQL-Konfigurationsdatei, typischerweise:

  • Linux: /etc/mysql/mysql.conf.d/mysqld.cnf
  • Mac (Homebrew): /usr/local/etc/my.cnf
  • Windows: C:\ProgramData\MySQL\MySQL Server 8.0\my.ini

bind-address anpassen:

[mysqld]
# Vorher oft so:
# bind-address = 127.0.0.1

# So ändern:
bind-address = 0.0.0.0

MySQL neu starten:

# Linux
sudo systemctl restart mysql

# Mac
brew services restart mysql

# Windows
# MySQL-Dienst im Dienst-Manager neu starten

Redis-Konfiguration

redis.conf bearbeiten (meist /etc/redis/redis.conf oder /usr/local/etc/redis.conf):

# Diese Zeile finden
bind 127.0.0.1 -::1

# Ändern zu
bind 0.0.0.0

Redis neu starten:

# Linux
sudo systemctl restart redis

# Mac
brew services restart redis

PostgreSQL-Konfiguration

postgresql.conf bearbeiten:

listen_addresses = '*'  # Alle Adressen

Außerdem pg_hba.conf – Docker-Netzwerk erlauben:

# Zeile hinzufügen: 172.17.0.0/16 erlauben
host    all             all             172.17.0.0/16           md5

Benutzerrechte konfigurieren (MySQL)

Selbst wenn MySQL auf 0.0.0.0 lauscht, gibt es noch Benutzerrechte.

MySQL verwaltet Rechte nach „Benutzer@Quell-Host“. root@localhost und root@% sind unterschiedliche Benutzer.

Erlaubt der Benutzer nur localhost, schlägt die Container-Verbindung fehl. Berechtigung für das Docker-Netzwerk erteilen:

-- Option 1: Von jedem Host (einfach, weniger sicher)
GRANT ALL PRIVILEGES ON *.* TO 'your_user'@'%' IDENTIFIED BY 'your_password';

-- Option 2: Nur Docker-Netzwerk (sicherer)
GRANT ALL PRIVILEGES ON *.* TO 'your_user'@'172.17.0.%' IDENTIFIED BY 'your_password';

-- Rechte neu laden
FLUSH PRIVILEGES;

Bei MySQL 8.0+ etwas andere Syntax:

-- Benutzer anlegen
CREATE USER 'your_user'@'%' IDENTIFIED BY 'your_password';

-- Berechtigung erteilen
GRANT ALL PRIVILEGES ON *.* TO 'your_user'@'%';

FLUSH PRIVILEGES;

Firewall-Konfiguration

Manche System-Firewalls blockieren Container-Zugriff auf Host-Dienste.

Firewall-Status prüfen:

# Linux (ufw)
sudo ufw status

# Linux (firewalld)
sudo firewall-cmd --state

Docker-Netzwerk erlauben (Beispiel MySQL Port 3306):

# ufw
sudo ufw allow from 172.17.0.0/16 to any port 3306

# firewalld
sudo firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="172.17.0.0/16" port port="3306" protocol="tcp" accept'
sudo firewall-cmd --reload

Sicherheitshinweise

Lauschen auf 0.0.0.0 birgt Risiken – der Dienst ist im Netzwerk erreichbar.

In Produktion:

  1. Nur bestimmte Schnittstelle: Wenn bekannt, welche Netzwerkkarte Docker nutzt

    bind-address = 172.17.0.1
  2. Mit Firewall kombinieren: Nur Docker-Netzwerk erlauben

  3. Eigener Datenbank-Container: Datenbank nicht auf dem Host, sondern per Docker Compose im gleichen Netzwerk – sicherer

Lokale Entwicklung:

Ehrlich gesagt ist 0.0.0.0 für lokale Entwicklung meist unproblematisch. Ihr Rechner ist kein Server – von außen kommt niemand rein.

Troubleshooting-Checkliste

Verbindungsproblem? Schritt für Schritt durchgehen.

Problem 1: Connection refused (Verbindung abgelehnt)

Häufigster Fehler:

Error: connect ECONNREFUSED host.docker.internal:3306

oder:

Can't connect to MySQL server on 'host.docker.internal' (111)

Mögliche Ursachen und Schritte:

Schritt 1: Dienst auf dem Host prüfen

Auf dem Host:

# MySQL prüfen
sudo systemctl status mysql    # Linux
brew services list              # Mac

# Lauscht der Port?
netstat -an | grep 3306
# oder
lsof -i :3306

Wenn der Dienst nicht läuft – zuerst starten.

Schritt 2: Listen-Adresse prüfen

Auf dem Host:

# Auf welcher Adresse lauscht MySQL?
sudo netstat -tlnp | grep 3306

Erwartete Ausgabe:

tcp  0  0 0.0.0.0:3306  0.0.0.0:*  LISTEN  1234/mysqld

Entscheidend ist die dritte Spalte. 0.0.0.0:3306 = alle Adressen, OK. 127.0.0.1:3306 = nur lokal – Container kommt nicht durch.

Lösung: bind-address auf 0.0.0.0 setzen (siehe Abschnitt „Host-Dienst-Konfiguration“).

Schritt 3: Firewall prüfen

Firewall temporär deaktivieren zum Testen:

# Linux (ufw)
sudo ufw disable

# Linux (firewalld)
sudo systemctl stop firewalld

# Mac
# Systemeinstellungen -> Sicherheit -> Firewall -> Aus

Wenn es ohne Firewall funktioniert – Firewall-Regeln setzen und wieder aktivieren.

Problem 2: Connection timeout (Verbindungs-Timeout)

Fehlermeldung:

Error: connect ETIMEDOUT host.docker.internal:3306

Timeout ist oft hartnäckiger – Pakete gehen raus, Antwort kommt nicht.

Schritte:

Schritt 1: host.docker.internal auflösbar?

Im Container:

# Container betreten
docker exec -it your_container sh

# Ping testen
ping host.docker.internal

Ping schlägt fehl oder „unknown host“ – host.docker.internal ist nicht konfiguriert.

Linux-Nutzer: Prüfen, ob --add-host=host.docker.internal:host-gateway in docker-compose oder docker run gesetzt ist.

Schritt 2: Portnummer korrekt?

Wirklich 3306? Vielleicht anderer MySQL-Port?

Auf dem Host prüfen:

# Tatsächlichen MySQL-Port anzeigen
sudo netstat -tlnp | grep mysqld

Schritt 3: Netzwerk vom Container zum Host

Im Container:

# Port erreichbar?
telnet host.docker.internal 3306

# Ohne telnet: nc
nc -zv host.docker.internal 3306

Port nicht erreichbar – Firewall und Dienst-Konfiguration erneut prüfen.

Problem 3: Unknown host (host.docker.internal nicht auflösbar)

Fehlermeldung:

getaddrinfo ENOTFOUND host.docker.internal

DNS-Auflösung schlägt fehl – der Container kennt die Domain nicht.

Lösung:

extra_hosts in der Container-Konfiguration:

services:
  app:
    extra_hosts:
      - "host.docker.internal:host-gateway"

Oder bei docker run:

docker run --add-host=host.docker.internal:host-gateway ...

Problem 4: Authentifizierung fehlgeschlagen (Access denied)

Fehlermeldung:

Access denied for user 'root'@'172.17.0.2' (using password: YES)

Verbindung zu MySQL klappt – aber Benutzerrechte stimmen nicht.

Lösung:

MySQL-Benutzer berechtigen:

-- Aktuelle Benutzer anzeigen
SELECT user, host FROM mysql.user WHERE user='root';

-- Nur root@localhost vorhanden? root@% oder [email protected].% anlegen
CREATE USER 'root'@'%' IDENTIFIED BY 'your_password';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%';
FLUSH PRIVILEGES;

Problem 5: Plattformübergreifende Konfiguration inkonsistent

Mac-Nutzer und Linux-Nutzer, dieselbe docker-compose.yml – auf Mac OK, auf Linux nicht.

Lösung:

Einheitlich host-gateway – auf allen Plattformen:

services:
  app:
    extra_hosts:
      - "host.docker.internal:host-gateway"

Docker ≥ 20.10 voraussetzen. Bei veralteten Versionen im Team – Upgrade empfehlen.

Schnelle Merkregel

Bei Verbindungsproblemen in dieser Reihenfolge prüfen:

  1. Dienst läuft?systemctl status / brew services list
  2. Lauscht richtig?netstat -tlnp, 0.0.0.0 oder 127.0.0.1?
  3. Container konfiguriert?extra_hosts oder --add-host?
  4. DNS OK? → Im Container ping host.docker.internal
  5. Port erreichbar? → Im Container telnet oder nc
  6. Firewall? → Temporär deaktivieren zum Testen
  7. Rechte OK? → MySQL-Benutzer @localhost oder @%?

In neun von zehn Fällen liegt es an den ersten drei Punkten.

Praxisbeispiele

Theorie genug – zwei konkrete Beispiele.

Beispiel 1: Spring-Boot-App verbindet sich mit Host-MySQL

Szenario: Spring-Boot-Projekt in Docker, lokale MySQL-Datenbank auf dem Host.

Schritt 1: Spring Boot konfigurieren

application.yml:

spring:
  datasource:
    # host.docker.internal für Host-MySQL
    url: jdbc:mysql://host.docker.internal:3306/mydb?useSSL=false&serverTimezone=UTC
    username: root
    password: your_password
    driver-class-name: com.mysql.cj.jdbc.Driver

Schritt 2: Docker Compose

docker-compose.yml:

version: '3.8'

services:
  app:
    build: .
    ports:
      - "8080:8080"
    extra_hosts:
      - "host.docker.internal:host-gateway"  # Schlüssel-Konfiguration
    environment:
      # Optional per Umgebungsvariable
      SPRING_DATASOURCE_URL: jdbc:mysql://host.docker.internal:3306/mydb
      SPRING_DATASOURCE_USERNAME: root
      SPRING_DATASOURCE_PASSWORD: your_password

Schritt 3: Host-MySQL konfigurieren

/etc/mysql/mysql.conf.d/mysqld.cnf bearbeiten:

[mysqld]
bind-address = 0.0.0.0

MySQL neu starten:

sudo systemctl restart mysql

Benutzer berechtigen:

CREATE USER 'root'@'%' IDENTIFIED BY 'your_password';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%';
FLUSH PRIVILEGES;

Schritt 4: Starten und testen

docker-compose up --build

Log HikariPool-1 - Start completed = Datenbankverbindung erfolgreich.

Troubleshooting aus der Praxis:

Beim ersten Mal Connection refused. Ablauf:

  1. MySQL läuft? systemctl status mysql → ja
  2. Listen-Adresse? netstat -tlnp | grep 3306127.0.0.1:3306
  3. bind-address = 0.0.0.0, MySQL neu starten
  4. Erneut starten – Verbindung OK

Beispiel 2: Node.js-App verbindet sich mit Host-Redis

Szenario: Node.js-Projekt, Redis als Cache, Redis läuft lokal auf dem Host.

Schritt 1: Node.js-Code

// redis-client.js
const redis = require('redis');

const client = redis.createClient({
  host: process.env.REDIS_HOST || 'host.docker.internal',
  port: process.env.REDIS_PORT || 6379,
  // Bei Redis-Passwort
  password: process.env.REDIS_PASSWORD
});

client.on('connect', () => {
  console.log('Redis connected successfully');
});

client.on('error', (err) => {
  console.error('Redis error:', err);
});

module.exports = client;

Schritt 2: Docker Compose

docker-compose.yml:

version: '3.8'

services:
  app:
    build: .
    ports:
      - "3000:3000"
    extra_hosts:
      - "host.docker.internal:host-gateway"
    environment:
      NODE_ENV: development
      REDIS_HOST: host.docker.internal
      REDIS_PORT: 6379

Schritt 3: Host-Redis konfigurieren

/etc/redis/redis.conf oder /usr/local/etc/redis.conf:

# bind-Zeile finden
bind 127.0.0.1 ::1

# Ändern zu
bind 0.0.0.0

Bei protected-mode yes auch anpassen:

protected-mode no  # OK für lokale Entwicklung, nicht in Produktion

Redis neu starten:

# Linux
sudo systemctl restart redis

# Mac
brew services restart redis

Schritt 4: Verifizieren

App starten:

docker-compose up

Redis connected successfully = alles OK.

Plattformübergreifend:

Früher musste man zwischen Mac und Linux unterscheiden – heute reicht host.docker.internal überall, solange docker-compose extra_hosts: ["host.docker.internal:host-gateway"] enthält.

Beispiel 3: Vollständige Entwicklungsumgebung

Praktisches Template – App-Container verbindet sich mit Host-MySQL und Redis:

# docker-compose.yml
version: '3.8'

services:
  app:
    build: .
    ports:
      - "8080:8080"
    extra_hosts:
      - "host.docker.internal:host-gateway"
    environment:
      # Datenbank
      DB_HOST: host.docker.internal
      DB_PORT: 3306
      DB_NAME: myapp
      DB_USER: root
      DB_PASSWORD: your_password

      # Redis
      REDIS_HOST: host.docker.internal
      REDIS_PORT: 6379

      # App
      NODE_ENV: development
      PORT: 8080
    volumes:
      - .:/app
      - /app/node_modules  # node_modules nicht mounten
    command: npm run dev  # Hot Reload im Dev-Modus

Zugehörige Host-Konfiguration:

# MySQL
# /etc/mysql/mysql.conf.d/mysqld.cnf bearbeiten
bind-address = 0.0.0.0
# Neustart: sudo systemctl restart mysql

# Redis
# /etc/redis/redis.conf bearbeiten
bind 0.0.0.0
protected-mode no
# Neustart: sudo systemctl restart redis

# Firewall (falls nötig)
sudo ufw allow from 172.17.0.0/16 to any port 3306
sudo ufw allow from 172.17.0.0/16 to any port 6379

Diese Konfiguration funktioniert auf Mac und Linux – kopieren und loslegen.

Zusammenfassung

Kernpunkte in drei Sätzen:

1. Prinzip verstehen

Der Container hat sein eigenes Netzwerk – localhost im Container meint den Container, nicht den Host. Das ist Netzwerk-Namespace-Isolation by Design, kein Bug.

2. Die richtige Methode wählen

Je nach Umgebung:

UmgebungEmpfohlene LösungKonfiguration
Mac/Windows (Docker Desktop)host.docker.internal direktKeine Extra-Konfiguration
Linux (Docker Engine 20.10+)extra_hosts: host-gatewaydocker-compose oder —add-host
Plattformübergreifendes Teamextra_hosts: host-gatewayEinheitliche Konfiguration
Älteres Linux172.17.0.1extra_hosts mit fester IP
Letzter Ausweg--network=hostNur lokale Entwicklung

3. Host-Dienste richtig konfigurieren

Container-Seite allein reicht nicht:

  • Listen-Adresse auf 0.0.0.0
  • MySQL-Benutzer für Docker-Netzwerk berechtigen
  • Firewall für Docker-Netzwerk öffnen

Entscheidungsbaum

Bei Verbindungsproblemen:

Keine Verbindung zum Host?

Mac/Windows oder Linux?

Mac/Windows:
  → host.docker.internal direkt nutzen
  → Wenn nicht: Host-Dienst-Konfiguration prüfen

Linux:
  → Docker ≥ 20.10?
      Ja → extra_hosts: host-gateway
      Nein → extra_hosts: 172.17.0.1
  → Host-Dienst-Konfiguration prüfen
  → Firewall prüfen

Alles probiert?
  → Checkliste Schritt für Schritt
  → Letzter Ausweg: --network=host (nur Entwicklung)

Abschließend

Container-Entwicklung ist praktisch, aber das Netzwerk hat Fallstricke. Mit host.docker.internal und host-gateway lösen Sie die meisten Probleme.

Diesen Artikel bookmarken – beim nächsten Verbindungsproblem einfach nachschlagen. Wenn Kollegen dasselbe Problem haben, teilen Sie den Link.

Haben Sie seltsame Container-Netzwerk-Probleme erlebt oder bessere Lösungen? Schreiben Sie gerne in die Kommentare – vielleicht hilft es anderen.

Vollständiger Ablauf: Docker-Container auf Host-Dienste zugreifen

host.docker.internal nutzen, um Container-Zugriff auf Host-Dienste zu lösen – für Mac, Windows und Linux

⏱️ Estimated time: 15 min

  1. 1

    Step 1: Ursache und Lösung verstehen

    Ursache: localhost oder 127.0.0.1 im Container verbindet nicht zum Host, weil localhost im Container auf den Container selbst zeigt – nicht auf den Host. Spezielle Konfiguration ist nötig.

    Lösung: host.docker.internal als „magische Domain“ nutzen; sie wird automatisch zur Host-IP aufgelöst.

    Plattformen:
    • Mac/Windows: Docker Desktop unterstützt nativ, keine Extra-Konfiguration
    • Linux: Docker 20.10+, mit --add-host oder extra_hosts in docker-compose
  2. 2

    Step 2: Konfiguration auf Mac/Windows

    Schritte auf Mac/Windows:

    1. host.docker.internal direkt nutzen:
    docker run -e DATABASE_URL=host.docker.internal:3306 my-app

    2. localhost in der App-Konfiguration ersetzen:
    • Connection String: host.docker.internal:3306
    • Umgebungsvariable: DATABASE_HOST=host.docker.internal

    3. Verbindung prüfen:
    • Im Container: docker exec -it container-name ping host.docker.internal
    • App-Verbindung direkt testen

    Hinweis: Mac/Windows brauchen keine Extra-Konfiguration – Docker Desktop erledigt das automatisch.
  3. 3

    Step 3: Linux-Konfiguration und Troubleshooting

    Konfiguration auf Linux:

    1. Docker ≥ 20.10 (empfohlen):
    docker run --add-host=host.docker.internal:host-gateway my-app

    Oder in docker-compose.yml:
    extra_hosts:
    - "host.docker.internal:host-gateway"

    2. Docker < 20.10:
    docker run --add-host=host.docker.internal:172.17.0.1 my-app

    3. Vollständige Checkliste:
    • Dienst auf dem Host läuft (netstat -tuln | grep 3306)
    • Port erreichbar (telnet host.docker.internal 3306)
    • host.docker.internal statt localhost
    • Auf Linux --add-host setzen
    • Firewall prüfen (iptables -L)
    • Dienst hört auf 0.0.0.0, nicht nur 127.0.0.1

FAQ

Warum verbindet localhost im Container nicht zum Host?
Netzwerk-Isolation: Jeder Container hat einen eigenen Netzwerk-Namespace; localhost im Container zeigt auf 127.0.0.1 des Containers, nicht des Hosts.

Analog zu zwei getrennten Häusern auf derselben Maschine – jedes hat seine eigene Adresse. localhost im Container meint das interne Netz des Containers, nicht das des Hosts.

Lösung: host.docker.internal nutzen – die Domain wird zur Host-IP aufgelöst.
Wird host.docker.internal auf allen Plattformen unterstützt?
Plattform-Unterstützung:

• Mac/Windows (Docker Desktop): nativ, keine Konfiguration
• Linux (Docker 20.10+): --add-host manuell setzen
• Linux (Docker < 20.10): 172.17.0.1 als Host-IP

Für plattformübergreifende Teams: extra_hosts in docker-compose vereinheitlichen.
host.docker.internal konfiguriert, Verbindung schlägt trotzdem fehl?
Troubleshooting:

1. Dienst auf dem Host prüfen:
netstat -tuln | grep PORT

2. Listen-Adresse prüfen:
Dienst muss auf 0.0.0.0 lauschen, nicht nur 127.0.0.1

3. Netzwerk testen:
docker exec -it container-name ping host.docker.internal
docker exec -it container-name telnet host.docker.internal PORT

4. Firewall:
iptables -L (Linux)
Windows-Firewall

5. Letzter Ausweg (nur Entwicklung):
--network=host (zerstört Container-Isolation)
Sollte man host.docker.internal in Produktion nutzen?
Nicht empfohlen. In Produktion besser:

• Servicenamen (Docker-Compose-Netzwerk) oder Containernamen
• Explizite IP-Adressen
• Service Discovery (z. B. Consul, etcd)

host.docker.internal eignet sich für:
• Lokale Entwicklung
• Debugging und Tests
• Zugriff auf Host-Tools (Datenbank, Redis)

In Produktion führt es zu:
• Abhängigkeit von Host-Netzwerk
• Verlust von Container-Vorteilen
• Höherer Betriebskomplexität

12 Min. Lesezeit · Veröffentlicht am: 17. Dez. 2025 · Aktualisiert am: 14. Juli 2026

Ähnliche Beiträge

Kommentare

Melde dich mit GitHub an, um einen Kommentar zu hinterlassen

Easton BlogEaston Blog