When implementing reverse proxy setups with Dockerized Nginx applications, a common pattern emerges where:
- Each microservice runs in its own container with exposed ports
- The main Nginx proxy routes traffic based on hostnames
- Port forwarding bridges container networks with host interfaces
In this scenario, we observe:
2016/06/04 13:26:58 [error] 5#5: *2 connect() failed (111: Connection refused)
while connecting to upstream, client: 100.100.100.100,
server: static.myserver.net, request: "GET / HTTP/1.1",
upstream: "http://127.0.0.1:8000/", host: "static.myserver.net"
Despite these key observations:
- Direct access to
myserver.net:8000
works externally curl http://127.0.0.1:8000
succeeds on the host- Application logs show no requests received
The critical misunderstanding lies in Docker's networking model. When containers expose ports like:
docker run -p 8000:80 my-app
This creates port forwarding between:
- The container's port 80 (internal bridge network)
- The host's port 8000 (external interface)
The current proxy setup:
server {
listen 80;
server_name static.myserver.net;
location / {
proxy_pass http://127.0.0.1:8000;
}
}
Fails because:
- The proxy container runs in its own network namespace
- 127.0.0.1 resolves to the proxy container's loopback
- The target app lives in a different network segment
The proper approach involves:
1. Creating a Shared Network
docker network create app-network
2. Launching Containers on the Network
docker run --network app-network --name my-app -p 8000:80 my-app
docker run --network app-network -p 80:80 nginx-proxy
3. Updated Proxy Configuration
server {
listen 80;
server_name static.myserver.net;
location / {
proxy_pass http://my-app:80;
}
}
For those needing host-based access:
Host Network Mode
docker run --network host nginx-proxy
Explicit IP Binding
proxy_pass http://host.docker.internal:8000;
When debugging similar issues:
# Check container IPs
docker network inspect app-network
# Test connectivity between containers
docker exec -it nginx-proxy curl http://my-app:80
# Verify port exposure
ss -tulnp | grep 8000
When implementing a reverse proxy setup with Nginx, few things are more frustrating than seeing that dreaded "connection refused" error. Let me walk through a real-world scenario I recently encountered while setting up a Docker-based hosting environment.
In this setup, we have:
- Multiple web apps, each running in their own Docker container with Nginx
- Each container exposes port 80, mapped to different host ports (e.g., 8000, 8001)
- A main Nginx proxy on the host handling requests on port 80
- DNS entries pointing to the host IP
Despite everything appearing correctly configured, requests to static.myserver.net
resulted in 502 errors with this log entry:
2016/06/04 13:26:58 [error] 5#5: *2 connect() failed (111: Connection refused) while connecting to upstream,
client: 100.100.100.100, server: static.myserver.net,
request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:8000/",
host: "static.myserver.net"
Here's what I checked:
- Container Networking: The Docker container might be using bridge networking, making
127.0.0.1
inaccessible from the host. - Port Binding: While
myserver.net:8000
worked externally, the proxy needed internal access. - Firewall Rules: Local firewall might be blocking container-to-container communication.
For Docker containers, we need to use the special host.docker.internal
DNS name (or the container's IP in bridge networks):
server {
listen 80;
server_name static.myserver.net;
location / {
proxy_pass http://host.docker.internal:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
If you're using Docker Compose, you can leverage internal networking:
version: '3'
services:
proxy:
image: nginx
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
depends_on:
- app
app:
image: your-app-image
expose:
- "80"
Then in your Nginx config:
proxy_pass http://app:80;
Always include these headers for proper proxying:
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_set_header X-Forwarded-Proto $scheme;
- Verify container ports are properly exposed and published
- Check Docker network configuration
- Test connectivity between containers using
docker exec
andcurl
- Examine both Nginx access and error logs