How Docker Can Be Sneaky Around Your UFW Firewall šŸ³

Rithwik KrishnaRithwik Krishna
4 min read

The Price I Had to Pay!

I had no idea my cute, whale-faced Docker was secretly betraying my UFW firewall. Turns out, Docker completely bypassed UFW in my homelab, leaving the door wide open for a crypto-mining malware to sneak in and hijack my system. Hah! But thatā€™s a story for another time. I took the hit so you donā€™t have to.

In this post, we'll explore:

  • Why Docker ignores ufw rules by default

  • How Docker modifies iptables

  • How to properly configure your firewall to control container traffic


The Problem: Docker and UFW Donā€™t Play Nice

When you set up ufw rules, you expect them to govern all incoming and outgoing traffic. However, if you have Docker installed, you might notice that containers can expose ports even when ufw appears to block them.

Why does this happen?

Docker manipulates iptables directly, bypassing ufw rules in the process. It does this to enable NAT (Network Address Translation) and ensure containers can communicate with the outside world.

Try this:

sudo ufw deny 8080
sudo ufw status

Now, if you run a container exposing port 8080:

docker run -d -p 8080:80 nginx

Youā€™ll still be able to access http://your-server-ip:8080/! šŸ¤Æ This means Docker is overriding your ufw firewall.


Solving UFW and Docker Issues

This solution needs to modify only one UFW configuration file, while all Docker configurations and options remain at their default settings.

Step 1: Modify UFW Configuration

Edit the UFW configuration file /etc/ufw/after.rules and add the following rules at the end of the file:

# BEGIN UFW AND DOCKER
*filter
:ufw-user-forward - [0:0]
:ufw-docker-logging-deny - [0:0]
:DOCKER-USER - [0:0]
-A DOCKER-USER -j ufw-user-forward

-A DOCKER-USER -j RETURN -s 10.0.0.0/8
-A DOCKER-USER -j RETURN -s 172.16.0.0/12
-A DOCKER-USER -j RETURN -s 192.168.0.0/16

-A DOCKER-USER -p udp -m udp --sport 53 --dport 1024:65535 -j RETURN

-A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 192.168.0.0/16
-A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 10.0.0.0/8
-A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 172.16.0.0/12
-A DOCKER-USER -j ufw-docker-logging-deny -p udp -m udp --dport 0:32767 -d 192.168.0.0/16
-A DOCKER-USER -j ufw-docker-logging-deny -p udp -m udp --dport 0:32767 -d 10.0.0.0/8
-A DOCKER-USER -j ufw-docker-logging-deny -p udp -m udp --dport 0:32767 -d 172.16.0.0/12

-A DOCKER-USER -j RETURN

-A ufw-docker-logging-deny -m limit --limit 3/min --limit-burst 10 -j LOG --log-prefix "[UFW DOCKER BLOCK] "
-A ufw-docker-logging-deny -j DROP

COMMIT
# END UFW AND DOCKER

Step 2: Restart UFW

Apply the changes by restarting UFW:

sudo systemctl restart ufw

Or reload it:

sudo ufw reload

After this, the public network wonā€™t be able to access any published Docker ports. However, containers within the private network can still communicate with each other, and containers can also access external networks normally.

āš ļø Note: If the UFW rules do not take effect after restart, consider rebooting the server.


Allowing Public Access to Specific Containers

If you want the public network to access services provided by a Docker container, for example, a container running a web server on port 80, use the following command:

ufw route allow proto tcp from any to any port 80

This allows external access to any Docker container that has port 80 published.

Allowing Access to a Specific Container

If multiple containers use the same port, but you only want to expose one, use its private IP address. For example, if the container's private address is 172.17.0.2, allow access like this:

ufw route allow proto tcp from any to 172.17.0.2 port 80

Allowing UDP Services (e.g., DNS)

For UDP-based services, such as a DNS server running on port 53, allow external access with:

ufw route allow proto udp from any to any port 53

Or for a specific container with IP 172.17.0.2:

ufw route allow proto udp from any to 172.17.0.2 port 53

Final Thoughts

Dockerā€™s ability to override ufw can create security risks, but by properly configuring ufw rules within /etc/ufw/after.rules, you can regain control over your serverā€™s network security without modifying Dockerā€™s default settings.

āœ… Key takeaways:

  • Docker modifies iptables directly, often bypassing ufw

  • The solution involves modifying /etc/ufw/after.rules, ensuring UFW enforces its rules

  • Restarting UFW or rebooting the server may be necessary for changes to take effect

  • Public access to specific containers must be explicitly allowed using ufw route allow

1
Subscribe to my newsletter

Read articles from Rithwik Krishna directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Rithwik Krishna
Rithwik Krishna