Troubleshooting Docker Port Bindings

If you notice that a mapped port is taking too long to respond or not working then there are a number of steps you can take to see what's going wrong.

Take a look at what's running

On the host execute a docker ps -a.

Do you see your container running in the output list?

If it isn't there then it's likely that it didn't start correctly. You may want to check your command is correct for starting your container. Also check the output for the start command, you may see something like:

Bind for 0.0.0.0:80 failed: port is already allocated.

Which means that the host is already allocated that port to another application or Docker container.

I can see my container in the output list

If you can see your container in the output from docker ps -a what does the status say? If it says Exited (0) X seconds ago then it looks like the main process exited. This could mean that your application shut down prematurely or an error occurred that caused it to fail. The logs of the container might be able to give you a bit more information with docker logs <container-id>.

My container is still running

If the status is Up X seconds then it's alive! Great news! Let's take a look at the ports column.

A good port binding for 80 will look something like 0.0.0.0:80->80/tcp. This is saying that 0.0.0.0:80 (the host IP address from the container's perspective) on port 80 is being routed -> to port 80 on the container for the tcp protocol.

If you notice that the ports column for your container is empty or says something like 80/tcp then be aware that the port binding has not been set up correctly. Double check that your Docker run command is correct and that the -p argument is in the right place!

Beware you can't specify the -p parameter anywhere. The following two commands are not the same thing:
docker run -d <image-name> -p 80:80 (Wrong)
docker run -d -p 80:80 <image-name> (Right)

Everything looks okay but it still doesn't work

If everything looks correct and you're still not able to get a response then it's time to connect to the container to see whether the application itself is listening on the specified port. Use the following to connect to the running container:

docker exec -it <container-id> bash

(If you have any issues then the instructions on How to Connect to a Running Container go into a little more depth and provide some troubleshooting help.)

We're in!

The idea once we're inside is to make a request to the port that our application is supposed to be listening on and see what response we get. The best way of doing this is by using curl:

curl -I http://localhost:<port-number>

Make sure you replace the <port-number> above with the port number the application is listening on NOT the port you bound in Docker.

In this output you'll hopefully see something like

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0HTTP/2 200

This will give you the status code of the response. If you get a Failed to connect to localhost port <port-number>: Connection refused then it doesn't look like the application is listening on that port. Obviously change the curl request to reflect how your application responds.

If all else fails

Sometimes Docker just gets into a funky state and stops working. I'd suggest if you've got to this stage you consider the ol' turn it off and on again solution by restarting the docker engine.

service docker restart

If this still doesn't work, give the server a kick.

I hope this helps some of you debugging Docker port bindings.

Have fun!