From 3f6dcab01fd7e82636b6aa6e2340740f4b73c252 Mon Sep 17 00:00:00 2001 From: John Patrick Teruel Date: Fri, 24 Apr 2026 20:04:21 +0800 Subject: [PATCH] Fix frontend-to-backend networking in Docker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Frontend in Docker container can't reach localhost:8000 on the host. Implemented Docker networking fix using host.docker.internal. Changes: • Updated frontend/src/App.tsx to use host.docker.internal:8000 in production - Automatically switches between localhost:8000 (dev) and host.docker.internal:8000 (Docker) • Added frontend/.env.example with API configuration • Updated docker-compose.yml frontend environment: - Added VITE_API_URL=http://host.docker.internal:8000 - Added comments explaining the networking approach • Enhanced DOCKER_QUICK_START.md troubleshooting section - Added detailed networking explanation - Instructions for verifying host.docker.internal works - Linux-specific workarounds How it works: • Docker Desktop automatically maps host.docker.internal to localhost on the host machine • Frontend (running in Docker) uses host.docker.internal:8000 • API & Consumer (running on host) listen on localhost:8000 • Both reference the same service, just from different network contexts Workflow remains: Terminal 1: docker compose up (infra + frontend in Docker) Terminal 2: uvicorn api.main:app --reload (your host machine) Terminal 3: cd consumer && python pipeline.py (your host machine) Frontend automatically reaches API at http://host.docker.internal:8000 without any manual configuration needed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- DOCKER_QUICK_START.md | 28 ++++++++++++++++++++++++++-- docker-compose.yml | 4 ++++ frontend/.env.example | 10 ++++++++++ frontend/src/App.tsx | 5 ++++- 4 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 frontend/.env.example diff --git a/DOCKER_QUICK_START.md b/DOCKER_QUICK_START.md index 66a49eb..9ee1383 100644 --- a/DOCKER_QUICK_START.md +++ b/DOCKER_QUICK_START.md @@ -38,6 +38,8 @@ This starts: - ✅ Redis - ✅ React Frontend (auto-built and running) +**Important**: The frontend is configured to reach the API at `http://host.docker.internal:8000` (special Docker networking that reaches your host machine from inside the container). + ### Step 2: Start API (New Terminal) ```bash @@ -164,20 +166,42 @@ docker compose up --build frontend ### Frontend can't connect to API ```bash -# Make sure API is running +# Make sure API is running on host at port 8000 curl http://localhost:8000/health # Should return: {"status": "healthy", ...} + +# If API is running but frontend still fails: +# The frontend uses host.docker.internal:8000 to reach the host +# This is a Docker Desktop feature that maps to localhost on the host + +# Verify it's working with: +docker exec $(docker ps -q -f name=payguard-frontend) \ + wget --spider -q http://host.docker.internal:8000 +# Should work without error ``` ### Port 3000 already in use ```bash # Find and kill process -kill -9 $(lsof -t -i :3000) +lsof -t -i :3000 # Or use different port in docker-compose.yml # Change: "3000:3000" to "3001:3000" ``` +### "host.docker.internal" not recognized (Linux only) +On Linux, `host.docker.internal` may not work. Instead: +```bash +# Option 1: Pass host IP to container +docker compose up --build +# Then edit docker-compose.yml frontend environment: +# VITE_API_URL=http://172.17.0.1:8000 (default Docker gateway) + +# Option 2: Use network_mode: host (shares host network) +# Add to frontend service: network_mode: "host" +# Then remove ports, depends_on conditions +``` + ## Full System Architecture ``` diff --git a/docker-compose.yml b/docker-compose.yml index aac212a..885d526 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -67,7 +67,11 @@ services: retries: 5 environment: - NODE_ENV=production + - VITE_API_URL=http://host.docker.internal:8000 restart: unless-stopped + # NOTE: Frontend connects to API running on host machine via host.docker.internal + # This allows docker compose up to start infrastructure + frontend, + # while API and Consumer run locally on the same machine volumes: redis_data: diff --git a/frontend/.env.example b/frontend/.env.example new file mode 100644 index 0000000..c3213e2 --- /dev/null +++ b/frontend/.env.example @@ -0,0 +1,10 @@ +# Frontend environment configuration + +# API Base URL - overrides the default in App.tsx +# Default behavior: +# - Development (npm run dev): http://localhost:8000 +# - Production (Docker): http://host.docker.internal:8000 +# VITE_API_URL=http://localhost:8000 + +# Node environment (set by docker-compose.yml) +NODE_ENV=production diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 3534e3d..5a10102 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -28,7 +28,10 @@ interface Result { timestamp: string; } -const API_BASE_URL = 'http://localhost:8000'; +// Use host.docker.internal when running in Docker, localhost when running locally +const API_BASE_URL = process.env.NODE_ENV === 'production' + ? 'http://host.docker.internal:8000' + : 'http://localhost:8000'; const App: React.FC = () => { const [auth, setAuth] = useState({