In case you are using Docker on Linux systems (pretty much the standard), it is important to be aware of the fact that Docker is is using iptables rules to provide network isolation. This is something that usually happens automatically under the hood, so many people - like me - don't dive into the details of what's going on there. The other day however, I came across the fact that I probably should have given some more attention to how this actually works.

If you're using one of the major cloud providers (AWS, Azure, Google, IBM, ...), they will provide you with a "real" firewall one way or the other, and that's a good thing. If however you are self-hosting a web-facing machine for test purposes, you might be using ufw, the "uncomplicated firewall". This is an easy-to-use tool that lets you set up policies concerning which protocols from which sources are allowed to reach out to which port on particular network interfaces. When it comes to Docker, you should be aware of one important fact:

Docker does not honor ufw rules

Let's say e.g. you have a Docker container on your web-facing test server that is running NGINX, and you used the  -p 8080:8080 parameter to make this http server available outside of the container listing on port 8080. Now, the web - i.e. everyone - will be able to connect to this NGINX instance via http://yourdomain:8080/. Let's assume for a minute that you decide to make this endpoint unavailable to the public. Easy, he? You ssh to your machine, and a one-liner will do the job for you:

sudo ufw deny 8080

Mission accomplished. Are you sure? Go ahead, open the browser on your desktop machine, and navigate to http://yourdomain:8080...and you will see that NXGINX is still serving contents to the public. How is this even possible 😵??  You did close port #8080. Well, as mentioned earlier: Docker is manipulating iptables rules, but it doesn't give a sh.. about ufw, at least not out of the box.

Docker typically sets up two custom iptables chains. They're named DOCKER and DOCKER-USER. The DOCKER chain is used by Docker itself, and you don't want to mess with it. If you have rules/policies that you want to see applied, you should add them to the DOCKER-USER chain. The default behaviour is that all external source IP addresses are allowed to connect to your Docker host.

So, if you want to only allow external traffic from a particular IP address, you will have to add a corresponding rule to the DOCKER-USER chain:

iptables -I DOCKER-USER -i eth0 ! -s 192.168.1.11 -j DROP

(this is assuming that your host's external network interface is named eth0, and the only source IP you want to allow is 192.168.1.11).

One final note: some posts in various blogs and support sites suggest you go and turn off iptables manipulation by Docker (there is a key named iptables in the Docker configuration that defaults to true and can be set to false). This is not a good idea, as it will also turn off a lot of the wanted behaviour.

Hope this helps.