How Docker Can Be Sneaky Around Your UFW Firewall š³


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 defaultHow 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 bypassingufw
The solution involves modifying
/etc/ufw/after.rules
, ensuring UFW enforces its rulesRestarting 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
Subscribe to my newsletter
Read articles from Rithwik Krishna directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
