Dashboard von macOS Browser mit Docker Gateway nicht erreichbar
Wenn der OpenClaw Gateway an Loopback innerhalb von Docker auf macOS bindet, ist das Dashboard vom Host-Browser aus aufgrund der Container-Netzwerkisolierung nicht erreichbar.
🔍 Symptome
Das OpenClaw-Dashboard ist nach einem Upgrade auf Version 3.9 vom macOS-Host-Browser aus nicht mehr erreichbar. Die Telegram-Bot-Integration funktioniert weiterhin normal.
Netzwerk-Level-Fehler-Manifestation
$ curl -v http://127.0.0.1:18789/
* Connected to 127.0.0.1 port 18789
> GET / HTTP/1.1
> Host: 127.0.0.1:18789
>
* Empty reply from server
* Connection died, errnum=0, curlcode=22
curl: (52) Empty reply from serverVerhalten an allen Endpoints
# All routes return identical empty response
$ curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:18789/
000
$ curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:18789/healthz
000
$ curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:18789/ui/
000Container-Health bestätigt laufenden Dienst
$ docker compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
openclaw-gateway openclaw/gateway "/entrypoint.sh gate…" gateway 10 minutes ago Up (healthy) 18789/tcpDiagnose: Loopback-Binding-Verifizierung
# Exec into container to verify listening address
$ docker exec -it openclaw-gateway sh -c "netstat -tlnp | grep 18789"
tcp 0 0 127.0.0.1:18789 0.0.0.0:* LISTEN 1/openclaw-gateway
# From inside container, the service responds
$ docker exec -it openclaw-gateway curl -s http://127.0.0.1:18789/healthz
{"status":"ok","version":"3.9.0"}Geräte-Pairing wird nie registriert
$ docker compose run --rm openclaw-cli devices list
[]Es erscheinen keine ausstehenden Geräteanfragen, da die Browserverbindung nie mit dem Gateway hergestellt wird.
🧠 Ursache
Docker Desktop für macOS Netzwerk-Architektur
Die Grundursache liegt in einem fundamentalen Unterschied, wie Docker Desktop das Container-Netzwerk auf macOS im Vergleich zu Linux-Hosts handhabt.
Auf Linux Docker-Hosts, wenn ein Container einen Dienst an 127.0.0.1:18789 bindet, ist der Port vom Host aus erreichbar, da das Docker-Bridge-Netzwerk die Loopback-Schnittstelle des Hosts teilt. Bei Docker Desktop für macOS werden Container jedoch in einer leichtgewichtigen Linux-VM ausgeführt, was eine Netzwerkisolierungsgrenze erzeugt:
┌─────────────────────────────────────────────────────────────────┐
│ macOS Host │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Docker Desktop Linux VM │ │
│ │ ┌─────────────────────────────────────────────────┐ │ │
│ │ │ Container Network (bridge) │ │ │
│ │ │ │ │ │
│ │ │ openclaw-gateway:127.0.0.1:18789 │ │ │
│ │ │ │ │ │
│ │ └─────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ Browser: http://127.0.0.1:18789 ──┐ │
│ │ BLOCKED │
│ ↓ │
└─────────────────────────────────────────────────────────────────┘Binding-Konfigurationsanalyse
Die Umgebungsvariable OPENCLAW_GATEWAY_BIND steuert die Listen-Adresse:
| Bind-Wert | Innerhalb des Containers | Vom macOS-Host | Anmerkungen |
|---|---|---|---|
loopback oder 127.0.0.1 | ✓ Erreichbar | ✗ Blockiert | Dienst bindet nur an Container-Loopback |
0.0.0.0 | ✓ Erreichbar | ✓ Erreichbar | Lauscht auf allen Schnittstellen inkl. Docker-Virtueller Schnittstelle |
| Unspecified (default) | Variiert je nach Version | Variiert | Oft Standard auf Loopback aus Sicherheitsgründen |
Versions-Regressionsanalyse
Die Regression zwischen v2.9 und v3.9 deutet auf eine Konfigurationsänderung hin:
- v2.9: Gateway war möglicherweise standardmäßig an
0.0.0.0gebunden, oder die Port-Veröffentlichung war konfiguriert - v3.9: Standard wurde auf
loopback-Binding geändert, oder explizites Binding wurde für Sicherheitshärtung erforderlich
Warum Telegram weiterhin funktioniert
Der Telegram-Bot verwendet einen anderen Verbindungsmechanismus:
Telegram Bot Flow (not affected):
┌──────────────┐ ┌─────────────────────────────────────┐
│ Telegram │ │ Container │
│ Servers │ ────── │ openclaw-gateway ── Webhook/Poll │
│ │ │ (outbound connection, no inbound) │
└──────────────┘ └─────────────────────────────────────┘
Dashboard Flow (broken):
┌──────────────┐ ┌─────────────────────────────────────┐
│ macOS │ │ Container │
│ Chrome │ ─X──── │ openclaw-gateway:127.0.0.1:18789 │
│ Browser │ blocked │ (loopback-only inbound) │
└──────────────┘ └─────────────────────────────────────┘Telegram funktioniert, weil OpenClaw ausgehende Verbindungen zu den Telegram-Servern initiiert. Dashboard-Zugriff erfordert eingehende Verbindungen vom Browser zum Gateway.
🛠️ Schritt-für-Schritt-Lösung
Lösung 1: An alle Schnittstellen binden (Empfohlen)
Ändern Sie die Gateway-Binding-Konfiguration, um Verbindungen von der Docker-Virtuellen Schnittstelle zuzulassen.
Vorher (docker-compose.yml):
services:
gateway:
image: openclaw/gateway:latest
environment:
- OPENCLAW_GATEWAY_BIND=loopback # Current setting
ports:
- "18789:18789"Nachher (docker-compose.yml):
services:
gateway:
image: openclaw/gateway:latest
environment:
- OPENCLAW_GATEWAY_BIND=0.0.0.0 # Changed setting
ports:
- "18789:18789"Änderungen anwenden:
$ docker compose down gateway
$ docker compose up -d gateway
$ sleep 2
$ curl -s http://127.0.0.1:18789/healthz
{"status":"ok","version":"3.9.0"}Lösung 2: Dynamische Gateway-Adresse (Alternativ)
Verwenden Sie den Docker-Service-Namen beim Zugriff von innerhalb Docker Compose, und die Docker Desktop-Host-IP beim Zugriff vom macOS-Host.
# Get the Docker Desktop VM IP on macOS
$ docker run -it --rm --network host alpine ip route | grep default | awk '{print $3}'
192.168.65.0
# Or use the special host.docker.internal mapping
$ curl -s http://host.docker.internal:18789/healthzdocker-compose.yml mit host.docker.internal:
services:
gateway:
image: openclaw/gateway:latest
environment:
- OPENCLAW_GATEWAY_BIND=127.0.0.1 # Keep loopback for internal
extra_hosts:
- "host.docker.internal:host-gateway"
cli:
depends_on:
- gateway
environment:
- OPENCLAW_GATEWAY_URL=http://host.docker.internal:18789Lösung 3: Reverse Proxy Container (Production-Grade)
Deployen Sie einen nginx-Sidecar für ordnungsgemäßes Reverse Proxying mit zusätzlichen Sicherheitsvorteilen.
docker-compose.yml:
services:
gateway:
image: openclaw/gateway:latest
environment:
- OPENCLAW_GATEWAY_BIND=127.0.0.1 # Internal-only
expose:
- "18789"
nginx:
image: nginx:alpine
ports:
- "18789:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- gateway
cli:
depends_on:
- gateway
environment:
- OPENCLAW_GATEWAY_URL=http://gateway:18789nginx.conf:
events {
worker_connections 1024;
}
http {
server {
listen 80;
server_name _;
# Proxy WebSocket connections for dashboard streaming
location / {
proxy_pass http://gateway:18789;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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_read_timeout 86400;
}
}
}Lösung 4: SSH-Tunnel (Maximale Sicherheit)
Für Umgebungen, in denen das Offenlegen eines Ports unerwünscht ist, verwenden Sie einen SSH-Tunnel.
# On macOS host, establish tunnel
$ ssh -L 18789:localhost:18789 docker-desktop-host
# Then in another terminal
$ open http://127.0.0.1:18789/🧪 Verifizierung
Schritt 1: Gateway-Bind-Adresse bestätigen
# Check inside container
$ docker exec openclaw-gateway sh -c "ss -tlnp | grep 18789"
LISTEN 0 128 0.0.0.0:18789 0.0.0.0:* users:(("openclaw-gateway",pid=1,fd=3))
# Should show 0.0.0.0, NOT 127.0.0.1Schritt 2: HTTP-Endpoint-Antwort verifizieren
$ curl -s -w "\nHTTP Status: %{http_code}\n" http://127.0.0.1:18789/healthz
{"status":"ok","version":"3.9.0"}
HTTP Status: 200Schritt 3: WebSocket-Konnektivität testen (Dashboard verwendet WebSocket)
# Install websocat if needed
$ brew install websocat
# Test WebSocket upgrade
$ websocat ws://127.0.0.1:18789/api/v1/stream
# Should establish connection and wait for eventsSchritt 4: Bestätigen, dass Geräte-Pairing funktioniert
# In one terminal, watch for devices
$ docker compose run --rm openclaw-cli devices list
# Should show [] initially
# Open browser to http://127.0.0.1:18789/ and trigger pairing
# Re-check devices
$ docker compose run --rm openclaw-cli devices list
[
{
"id": "browser-xxxx",
"type": "dashboard",
"status": "pending",
"created_at": "2025-01-15T10:30:00Z"
}
]Schritt 5: Vollständiger Dashboard-Flow-Test
# Get dashboard URL with token
$ docker compose run --rm openclaw-cli dashboard --no-open
Opening dashboard at: http://127.0.0.1:18789/?token=eyJhbGc...
# Open in browser (should load pairing screen)
$ open http://127.0.0.1:18789/
# Approve pending device
$ docker compose run --rm openclaw-cli devices approve browser-xxxx
# Refresh browser (should now show full dashboard)
$ open http://127.0.0.1:18789/Schritt 6: Container-Health-Status verifizieren
$ docker compose ps
NAME IMAGE STATUS
openclaw-gateway openclaw/gateway Up (healthy)⚠️ Häufige Fehler
Fehler 1: Docker Desktop-Netzwerkadresse vergessen
# INCORRECT: Assumes 127.0.0.1 works
$ curl http://127.0.0.1:18789/healthz
curl: (52) Empty reply from server
# CORRECT: Use host.docker.internal on macOS
$ curl http://host.docker.internal:18789/healthz
{"status":"ok","version":"3.9.0"}Fehler 2: Port-Veröffentlichung ohne Schnittstellen-Binding
Selbst mit -p 18789:18789, wenn OPENCLAW_GATEWAY_BIND=loopback gesetzt ist, blockiert Docker Desktop weiterhin die Verbindung, da der Container nur auf seinem internen Loopback lauscht.
Fehler 3: Firewall blockiert Docker Desktop
# macOS firewall may block Docker Desktop incoming connections
# Verify in System Preferences > Security & Privacy > Firewall
# Test with verbose curl to see connection status
$ curl -v http://host.docker.internal:18789/healthzFehler 4: Docker Desktop-Ressourcenbeschränkungen
# Check Docker Desktop resources
# Settings > Resources > Memory should be >= 4GB
# Container may be OOMKilled, check logs
$ docker compose logs gateway | grep -i memoryFehler 5: Versionsspezifische Konfigurationsabweichung
Konfigurationsdateien von v2.9 sind möglicherweise nicht mit v3.9-Standards kompatibel.
# Check for deprecated environment variables
$ docker compose config | grep -i bind
# Compare with current defaults
$ docker exec openclaw-gateway env | grep OPENCLAWFehler 6: WebSocket-Proxy-Konfiguration in nginx
Bei Verwendung eines Reverse Proxys müssen WebSocket-Upgrades explizit konfiguriert werden, andernfalls hängt das Dashboard möglicherweise unbegrenzt.
# Verify WebSocket headers are forwarded
$ curl -I -N \
-H "Upgrade: websocket" \
-H "Connection: Upgrade" \
http://127.0.0.1:18789/api/v1/stream
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: UpgradeFehler 7: Token-Ablauf während des Testens
Dashboard-Tokens können während der Entwicklungstests schnell ablaufen. Rufen Sie die URL immer vor dem Testen erneut ab.
# Get fresh token
$ docker compose run --rm openclaw-cli dashboard --no-open
Opening dashboard at: http://127.0.0.1:18789/?token=fresh_token_here🔗 Zugehörige Fehler
Direkt zugehörige Fehler
curl: (52) Empty reply from server— Gateway an Loopback innerhalb des Containers gebunden, vom macOS-Host aus nicht erreichbar. Lösung: Setzen SieOPENCLAW_GATEWAY_BIND=0.0.0.0.ERR_CONNECTION_REFUSED— Browser kann die Docker Desktop-VM nicht erreichen. Überprüfen Sie die host.docker.internal-Auflösung oder ob Docker Desktop läuft.ERR_CONNECTION_TIMED_OUT— Port nicht veröffentlicht oder Firewall blockiert. Überprüfen Sie Docker Desktop-Netzwerk und macOS-Firewall-Regeln.
Kontextuell zugehörige Fehler
upstream prematurely closed connection— nginx-Proxy-Fehlkonfiguration bei WebSocket. Stellen Sie sicher, dassproxy_read_timeout 86400gesetzt ist.502 Bad Gateway— nginx kann Gateway-Container nicht erreichen. Überprüfen Sie Container-Netzwerk unddepends_on-Konfiguration.devices listgibt leeres Array zurück — Browser-WebSocket-Verbindung nie hergestellt. Überprüfen Sie Binding-Konfiguration und Browser-Konsole auf Verbindungsfehler.Docker Desktop: connection refused to 127.0.0.1— Bekannte Einschränkung bei macOS-Loopback und Docker Desktop. Verwenden Sie host.docker.internal oder 0.0.0.0-Binding.
Historische Probleme
- GitHub Issue #2341 — "Gateway binds to loopback breaking macOS access" — Bestätigtes Docker Desktop-Netzwerkisolierungsproblem.
- GitHub Issue #1892 — "Dashboard unreachable from Windows Docker Desktop" — Ähnliche Grundursache, Windows-spezifischer Netzwerk-Stack.
- GitHub Issue #3107 — "Request: document macOS Docker Desktop networking requirements" — Dokumentationsanfrage für dieses spezifische Szenario.
Zugehörige Konfigurationsdokumentation
OPENCLAW_GATEWAY_BIND— Steuert die Netzwerkschnittstellen-Bindung. Werte:loopback,0.0.0.0, oder spezifische IP-Adresse.OPENCLAW_GATEWAY_URL— Überschreibt Gateway-Verbindungs-URL für CLI-Tools. Erforderlich bei Verwendung von nicht-Standard-Port oder host.docker.internal.docker-compose ports vs expose—portsveröffentlicht zum Host,exposemacht Port nur für verknüpfte Dienste verfügbar.