others-how to solve the docker nginx 111: Connection refused problem?
1. Purpose
In this post, I will demonstrate how to solve the following error when using nginx in docker:
2022/11/09 09:05:41 [error] 63#63: *32 connect() failed (111: Connection refused) while connecting to upstream, client: 10.13.4.3, server: test.bswen.com, request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:3000/", host: "test.bswen.com"
2022/11/09 09:05:41 [warn] 63#63: *32 upstream server temporarily disabled while connecting to upstream, client: 10.13.4.3, server: test.bswen.com, request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:3000/", host: "test.bswen.com"
2022/11/09 09:05:41 [error] 63#63: *32 connect() failed (111: Connection refused) while connecting to upstream, client: 10.13.4.3, server: test.bswen.com, request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:3000/", host: "test.bswen.com"
2022/11/09 09:05:41 [warn] 63#63: *32 upstream server temporarily disabled while connecting to upstream, client: 10.13.4.3, server: test.bswen.com, request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:3000/", host: "test.bswen.com"
10.13.4.3 - - [09/Nov/2022:09:05:41 +0000] "GET / HTTP/1.1" 502 497 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.3 Safari/605.1.15" "-"
2022/11/09 09:10:38 [error] 63#63: *35 connect() failed (111: Connection refused) while connecting to upstream, client: 152.89.196.211, server: test.bswen.com, request: "GET /?XDEBUG_SESSION_START=phpstorm HTTP/1.1", upstream: "http://127.0.0.1:3000/?XDEBUG_SESSION_START=phpstorm", host: "test.bswen.com:80"
2022/11/09 09:10:38 [warn] 63#63: *35 upstream server temporarily disabled while connecting to upstream, client: 152.89.196.211, server: test.bswen.com, request: "GET /?XDEBUG_SESSION_START=phpstorm HTTP/1.1", upstream: "http://127.0.0.1:3000/?XDEBUG_SESSION_START=phpstorm", host: "test.bswen.com:80"
152.89.196.211 - - [09/Nov/2022:09:10:38 +0000] "GET /?XDEBUG_SESSION_START=phpstorm HTTP/1.1" 502 497 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36" "-"
2022/11/09 09:10:38 [error] 63#63: *35 connect() failed (111: Connection refused) while connecting to upstream, client: 152.89.196.211, server: test.bswen.com, request: "GET /?XDEBUG_SESSION_START=phpstorm HTTP/1.1", upstream: "http://127.0.0.1:3000/?XDEBUG_SESSION_START=phpstorm", host: "test.bswen.com:80"
2022/11/09 09:10:38 [warn] 63#63: *35 upstream server temporarily disabled while connecting to upstream, client: 152.89.196.211, server: test.bswen.com, request: "GET /?XDEBUG_SESSION_START=phpstorm HTTP/1.1", upstream: "http://127.0.0.1:3000/?XDEBUG_SESSION_START=phpstorm", host: "test.bswen.com:80"
^C
The core error message is:
connect() failed (111: Connection refused) while connecting to upstream
The nginx configuration is as follows:
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
upstream yapi_up {
server 127.0.0.1:3000;
}
include /etc/nginx/conf.d/*.conf;
}
server {
listen 80;
listen [::]:80;
server_name test.bswen.com localhost;
location / {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://yapi_up;
}
The deployment of nginx and the service on the host is as follows:
- There is a web service listening on 127.0.0.1:3000
- The nginx is deployed in a docker container, and using port mapping from container’s port 80 to host’s port 80
- The nginx is using
proxy_pass
function to proxy the incoming request from outside the container to the local web service
But when we tried to access from the host’s ip address, we got this error:
2022/11/09 09:10:38 [error] 63#63: *35 connect() failed (111: Connection refused) while connecting to upstream, client: 152.89.196.211, server: test.bswen.com, request: "GET /?XDEBUG_SESSION_START=phpstorm HTTP/1.1", upstream: "http://127.0.0.1:3000/?XDEBUG_SESSION_START=phpstorm", host: "test.bswen.com:80"
2022/11/09 09:10:38 [warn] 63#63: *35 upstream server temporarily disabled while connecting to upstream, client: 152.89.196.211, server: test.bswen.com, request: "GET /?XDEBUG_SESSION_START=phpstorm HTTP/1.1", upstream: "http://127.0.0.1:3000/?XDEBUG_SESSION_START=phpstorm", host: "test.bswen.com:80"
^C
Test the local web service’s availability:
[root@mx ~]# curl http://localhost:3000 -vvv
* About to connect() to localhost port 3000 (#0)
* Trying ::1...
* Connected to localhost (::1) port 3000 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Host: localhost:3000
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Length: 1746
< Last-Modified: Wed, 09 Nov 2022 06:53:05 GMT
< Cache-Control: max-age=0
< Content-Type: text/html; charset=utf-8
< Date: Thu, 10 Nov 2022 06:00:48 GMT
< Connection: keep-alive
< Keep-Alive: timeout=5
<
<!DOCTYPE html>
<html>
<head>
...
It’s running fine.
It seems that the local web service that is listening on port 3000 is refusing to let the client connect to it. why?
2. Solution
Solution #1
The above problem can be depicted by the following diagram:
The nginx in a docker container is just trying to access the upstream service using the following url:
proxy_pass http://127.0.0.1:3000
And the docker container of nginx is started as follows:
docker container run \
--rm \
--name mynginx1 \
--volume "$PWD/conf":/etc/nginx \
-p 0.0.0.0:80:80 \
-d \
nginx
You can see that the nginx is listening on port 80 inside the container, which is mapped to the host’s port 80.
Actually, the connection from nginx to upstream is just happened inside the docker container, which using a special network. So ,the real connection is as following diagram shows: The connection is proxied inside the container, does not reach the outside.
By default , the docker container is a bridge network using docker0
as the bridge from container to host and other containers.
[root@mx nginx]# ip addr show docker0
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:72:69:75:17 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:72ff:fe69:7517/64 scope link
valid_lft forever preferred_lft forever
[root@mx nginx]
Then we can change the upstream url inside the nginx configuration from 127.0.0.1
to the docker0
’s address:
proxy_pass http://172.17.0.1:3000
This solution can be described as following diagram:
However, under Windows and macOS platforms, there is no docker0 virtual network card. At this time, you can use the special DNS name host.docker.internal
to resolve the host IP.
proxy_pass http://host.docker.internal:3000
Solution #2
Instead of using the bridge network, we can choose the host
network for nginx container.
In Docker, a host is a machine that runs one or more containers. Docker network host, also known as Docker host networking, is a networking mode in which a Docker container shares its network namespace with the host machine.
User-defined bridge networks are best when you need multiple containers to communicate on the same Docker host. Host networks are best when the network stack should not be isolated from the Docker host, but you want other aspects of the container to be isolated.
We can start our nginx using docker as follows:
docker run -d --name mynginx1 --network host nginx
Notice that we do not use -p
for port mapping again, because every port is bound to the host’s network interface, e.g. If there is a port 80 listening inside container, then there is a port 80 listening on the host.
Now we can change the nginx configuration as follows:
proxy_pass http://127.0.0.1:3000
Using the host network does not require modifying nginx.conf, and localhost can still be used, so the versatility is better than the previous method. However, since the isolation of the host network is not as good as that of the bridge network, the security of using the host network is not as high as that of the bridge network.
3. Summary
In this post, I demonstrated how to solve the 111: Connection refused problem
when using nginx in docker, the key point is to understand the network model of docker . That’s it, thanks for your reading.