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

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 -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 -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:


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

  • 1
    While this works in principle, it requires me to deal with all the forwarding manually. I'm looking for a solution where Docker manages the forwarding rules as usual, but additional custom rules are allowed on top of them. – Peter Thomassen Dec 5 '16 at 10:20

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.


I'm a big fan of having as many services as possible to be routed through my nginx to be able to do internal testing and easy switching external access off, and logging. Since nginx is a perfect proxy also for any TCP connection, the only service not being tunneled through nginx for me is my sshd.

There is this doc describing how to load-balance between many MySQL receivers, but the most basic config in your case should be as simple as:

stream {
    server {
        listen 3306;
        deny   all;

Some more details and ideas can be found here. You could also add logging and many more things.

Docker param might be -p to be limited to localhost-access only.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.