Docker Community Forums

Share and learn in the Docker community.

Restricting exposed Docker ports with iptables

Dear Community!

I want to restrict general Docker exposed ports access.
Most of my exposed ports are using reverse-proxy so it will be enough if these exposed ports will be only accessible through localhost.

I know that I could do port mapping in Docker, but it will be better for me if simply doing a -p 8080:80 would only allow access from localhost.

Right now for testing, I have a port mapped like this in a docker-compose.yml file:

     - 222:22

I have added a rule like this to the DOCKER-USER chain, but I can still access this 222 port from outside:

-A DOCKER-USER -i eth0 -p tcp -m tcp --dport 222 -j DROP

Why this rule is not working?

Also there are a few ports which should be accessible from our VPN network.
So I would think that a DROP policy on the DOCKER-USER chain would be great for me and then I would allow these specific ports.

Can someone help me debug this and get it working?


Two things to bear in mind when working with docker’s firewall rules:

To avoid your rules being clobbered by docker, use the DOCKER-USER chain
Docker does the port-mapping in the PREROUTING chain of the nat table. This happens before the filter rules, so --dest and --dport will see the internal IP and port of the container. To access the original destination, you can use -m conntrack --ctorigdstport.
For example:

iptables -A DOCKER-USER -i eth0 -s -p tcp -m conntrack --ctorigdstport 3306 --ctdir ORIGINAL -j ACCEPT
iptables -A DOCKER-USER -i eth0 -s -p tcp -m conntrack --ctorigdstport 3306 --ctdir ORIGINAL -j ACCEPT
iptables -A DOCKER-USER -i eth0 -p tcp -m conntrack --ctorigdstport 3306 --ctdir ORIGINAL -j DROP
NOTE: Without --ctdir ORIGINAL, this would also match the reply packets coming back for a connection from the container to port 3306 on some other server, which is almost certainly not what you want! You don’t strictly need this if like me your first rule is -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT, as that will deal with all the reply packets, but it would be safer to still use --ctdir ORIGINAL anyway.

Thanks I have also found this stackoverflow post.

I’m using the DOCKER-USER chain only for Docker related iptables rules.
Your rules seems really great, but I don’t know how I can apply this generally for all ports.
So I don’t want to create a new rule for every newly opened port like this one:

iptables -A DOCKER-USER -i eth0 -p tcp -m conntrack --ctorigdstport 3306 --ctdir ORIGINAL -j DROP

and then define specific rules for each port. I want something general which defaults to drop for all ports.

That would be really great, because multiple users are creating Docker containers on this server and I don’t want new ports to get exposed automatically, just by adding a manual ACCEPT rule for each port.