When running multiple services in Docker Compose, a common pain point is getting services to communicate with each other. The configuration you shared attempts to proxy requests from Nginx to a Node.js server, but there's a critical networking issue.
In your nginx.conf, you're using proxy_pass http://localhost:8000
which won't work because:
- localhost refers to the Nginx container's own loopback interface
- The Node.js server runs in a separate container with its own network namespace
Docker Compose automatically creates a dedicated network for your services where:
- Each service can be reached by its service name
- DNS resolution is automatically configured
- Containers can communicate over this private network
Here's the corrected version of your setup:
version: '3.8'
services:
server:
build:
context: ../../
dockerfile: ./packages/website/Dockerfile
command: node /cutting/index.js
environment:
PORT: 8000
NODE_ENV: production
restart: always
expose:
- "8000" # Explicitly expose the port to other containers
nginx:
build:
context: ./
dockerfile: ./nginx/Dockerfile
ports:
- "80:80" # Changed from 8000:8000 to standard HTTP port
depends_on:
- server
restart: always
The key change is in the proxy_pass directive:
server {
# ... other config remains the same ...
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
# Changed from localhost to service name
proxy_pass http://server:8000;
}
}
When implementing this solution:
- Use
depends_on
carefully - it only waits for container startup, not application readiness - Consider adding health checks to your services
- For production, use proper restart policies and logging
- You might want to add a custom network with specific settings
For more complex scenarios, you might want this setup:
version: '3.8'
services:
server:
# ... previous config ...
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 3
nginx:
# ... previous config ...
depends_on:
server:
condition: service_healthy
When running Nginx and Node.js in separate Docker containers, you can't use localhost:8000
in your Nginx configuration because each container has its own network namespace. Instead, you need to use Docker's internal DNS resolution.
version: '3'
services:
node_app:
build:
context: ../../
dockerfile: ./packages/website/Dockerfile
command: node /cutting/index.js
environment:
PORT: 8000
NODE_ENV: production
restart: always
expose:
- "8000"
nginx:
build:
context: ./
dockerfile: ./nginx/Dockerfile
depends_on:
- node_app
ports:
- "80:80"
restart: always
The key change is in the proxy_pass directive:
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://node_app:8000;
}
- Use the service name (
node_app
) instead of localhost - Added
expose
to make the Node.js port available to other containers - Changed Nginx's external port mapping to standard HTTP port 80
- Removed the
tail -f /dev/null
command as it's not needed
To test if containers can communicate:
docker-compose exec nginx ping node_app
For better performance, consider adding these to your Nginx config:
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;