Search code examples
dockernginxiptables

problems running a docker container behind nginx and/or firewall


I'm running docker behind nginx, with the registry container and my own container running a gunicorn django webapp.

The django webapp runs fine outside the docker container. However, as soon I try and run the django webapp from within the container, the webapp fails with this message from nginx:

2018/03/20 15:39:30 [error] 14767#0: *360 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: 10.38.181.123, server: app.ukrdc.nhs.uk, request: "POST /convert/pv-to-rda/ HTTP/1.1", upstream: "http://127.0.0.1:9300/convert/pv-to-rda/", host: "app.ukrdc.nhs.uk"

when I do a get on the webapp.

The registry container works fine.

  1. I've exposed the right port in the Dockerfile

  2. Run command is:

    docker run -ti -p 9300:9300 ukrdc/ukrdc-webapi

  3. Added the port to the iptables.

(output from iptables -S

-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-N DOCKER
-A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 5000 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 9300 -j ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -i docker0 -o docker0 -j ACCEPT
-A DOCKER -d 172.17.0.1/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 5000 -j ACCEPT
-A DOCKER -d 172.17.0.20/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 9300 -j ACCEPT)

The signs point to something being wrong with my container and/or firewall rules, but I'm not sure what. I think I'm doing the same as the registry container.

Running on Centos 6.9 with Docker version 1.7.1, build 786b29d/1.7.1

The answer is:

run the django app with

 exec gunicorn mysite.wsgi \
-    -b 127.0.0.1:9300 \
+    -b 0.0.0.0:9300 \
    --name ukrdc_django \
    --workers 3 \
    --log-level=info \

I'd bound it to the local loop-back address. It's now bound to all addresses, and now works.


Solution

  • Try adding -P to the run command:

    docker run -P <container>
    

    That will automatically publish the exposed ports. Note the difference: exposing a port makes it available to other containers on the docker network, where as publishing the port makes it available to the host machine, as well as other containers on the network.

    I think you're using EXPOSE when you really want a -P or -p flag on your docker run command, where "P" is for "publish". According to the docker docs, EXPOSE is just for linking ports between containers, where as docker run -P <container> or docker run -p 1234:1234/tcp <container> will actually make a port or ports available outside the container so nginx can reach it from the host machine. Another option is you could run nginx in a container on the same network (there is an easy-to-use standard nginx container out there), and then nginx could reach all of the exposed ports on the network, but you would need to publish at least one of the nginx container's ports anyway in that instance.

    Here's another SO post that helped me a lot with expose vs. publish:

    Difference between "expose" and "publish" in docker