Fixing Two Docker Issues: Port Mapping and Backend Routing

When I containerized my full-stack project using Docker Compose, I expected everything to work smoothly. The setup included a React frontend built with Vite and a FastAPI backend. Each had its own Dockerfile, and both were connected through a shared network defined in docker-compose.yml.
At first, the backend was running fine, but the frontend refused to load in the browser. Even after it finally appeared, it still could not communicate with the backend. These two problems turned out to be simple configuration issues related to port mapping and container networking.
Background of the Errors
My project structure had two services, one for the frontend and one for the backend. The backend started without issues on port 8000, but when I tried to open http://localhost:3000, the frontend did not show up.
The Docker logs showed the Vite server running on port 3000 inside the container. That meant the container was working fine internally, but somehow the port connection between the container and my local computer was not aligned.
Issue 1: Port Mapping (3000:80 vs 3000:3000)
The problem was in the ports configuration of the frontend service. Initially, it looked like this:
YAML
ports:
- "3000:80"
This configuration tells Docker to forward traffic from port 3000 on my computer to port 80 inside the container. However, the Vite server does not use port 80; it runs on port 3000 inside the container. Because of that mismatch, the browser could not connect.
I fixed it by changing the mapping to:
YAML
ports:
- "3000:3000"
This way, port 3000 on my computer connected directly to port 3000 inside the container. After restarting the containers, the frontend loaded correctly in the browser at http://localhost:3000.
The key point here is that the first number represents the host machine’s port, while the second represents the container’s port. Both must match the actual port where the application is listening inside the container.
Issue 2: Connecting Frontend to Backend (localhost vs backend)
Once the frontend was visible, it still could not reach the backend. The console showed network errors with messages like getaddrinfo ENOTFOUND backend.
The reason was that the frontend was trying to fetch data from http://localhost:8000. While this works locally, it fails inside Docker. Inside a container, localhost refers to that specific container itself, not the host computer or other containers.
Docker provides an internal network that allows containers to communicate using their service names. In my docker-compose.yml, the backend service was called backend. So instead of http://localhost:8000, the frontend needed to target http://backend:8000.
I added this to the frontend configuration:
YAML
environment:
- VITE_API_URL=http://backend:8000
My vite.config.js already used this variable in the proxy setup:
JavaScript
proxy: {
'/api': {
target: process.env.VITE_API_URL || 'http://localhost:8000',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
},
},
This configuration allowed the app to automatically use the correct backend address inside Docker, while still working with localhost during local development. After rebuilding the containers, the frontend could finally fetch data from the backend without any errors.
What I Learned
Both problems were simple but easy to overlook. The port mapping issue happened because I connected to the wrong internal port, and the backend routing problem came from misunderstanding how Docker networking works.
By mapping ports correctly and using service names instead of localhost, I made the containers communicate properly. Now the frontend and backend run smoothly together, and the setup is reliable whether I use Docker or run the services directly on my computer.


