Docker: correct way to restrict access to certain IP addresses

I have a Docker container exposing port 3306 to the Internet. I would like to restrict access to certain public IP addresses. As an example, let's use 1.2.3.4.

As an additional condition, I want the rules to survive restarting the Docker daemon and rebooting the server. This allows me to use iptables-persistent (iptables-save/iptables-restore) to restore the rules when the server is rebooted, without having the dockerd startup interfering with it.

I tried the following:

  1. Modifying the FORWARD chain:

    iptables -I FORWARD -p tcp --dport 3306 -j REJECT
    iptables -I FORWARD -p tcp --dport 3306 -s 1.2.3.4 -j ACCEPT
    

    This works when done after starting the Docker daemon. When restarting the daemon, Docker inserts additional rules at the top of the chain, and my custom rules end up being ignored.

  2. Modifying the DOCKER chain:

    iptables -N DOCKER # if chain does not yet exist
    iptables -I DOCKER -p tcp --dport 3306 -j REJECT
    iptables -I DOCKER -p tcp --dport 3306 -s 1.2.3.4 -j ACCEPT
    

    This works until dockerd is restarted. It looks like dockerd clears the DOCKER chain upon restart, and all the custom rules are gone.

  3. Use --iptables=false. While this works in principle, this solution breaks the standard Docker forwarding features, and requires setting up the forwarding rules manually.

I would be surprised if there is no proper way to do this. Any ideas?

PS: I did some reading, to no avail (e.g. Steps for limiting outside connections to docker container with iptables?, Docker - Exposed ports accessible from outside - iptables rules ignored, but these questions don't seem to deal with the restarting issue.)


dockersd can be run with the option:

--iptables=false

If not run manually but used as service it's sufficient to add or modify the following line in the configuration file /etc/docker/daemon.json :

"iptables": false,

More detailed documentation can be found here


I have found https://serverfault.com/a/933803/592497 to be most valuable information to be able to expose certain ports among your internal network but block to the outside. For example a database container.

The main point is that you have to use the DOCKER-USER chain as this one will not be overwritten by Docker.

This will also solve your problem to have these rules persistent after reboot or serive restart.