Secure Docker with UFW: Fix Firewall Issues Without Disabling iptables
Running Docker containers on an Ubuntu server with UFW (Uncomplicated Firewall) can leave your ports exposed, like leaving your front door wide open. Docker’s default behavior bypasses UFW rules, potentially exposing internal services to the public internet. This guide shows you how to secure Docker with UFW using the ufw-docker script, ensuring robust firewall protection without sacrificing Docker’s networking capabilities. Let’s lock down your server while keeping your containers running smoothly.
Why Docker and UFW Don’t Play Nice
Docker manages its own iptables rules, which can conflict with UFW’s firewall settings. This means published container ports might be accessible externally, even if UFW is set to block them. For example, running docker run -p 0.0.0.0:8080:80 httpd:alpine exposes port 8080 publicly, ignoring UFW’s deny 8080 rule. This security gap can expose sensitive services, making proper configuration critical.
Common Issues with Docker and UFW
- Bypassing UFW: Docker’s iptables rules override UFW, allowing unauthorized access to container ports.
- Uncontrolled Traffic: Containers may send or receive traffic outside UFW’s control.
- Overly Strict Rules: Misconfigured UFW settings can block containers from accessing the network entirely.
Step-by-Step: Securing Docker with UFW
The ufw-docker project provides an elegant solution to align Docker with UFW without disabling iptables. Follow these steps to secure your setup.
1. Install the ufw-docker Script
Download and set up the ufw-docker utility to simplify firewall management:
sudo wget -O /usr/local/bin/ufw-docker \
https://github.com/chaifeng/ufw-docker/raw/master/ufw-docker
sudo chmod +x /usr/local/bin/ufw-docker
Then, apply the necessary UFW rules:
ufw-docker install
This backs up /etc/ufw/after.rules and adds Docker-compatible firewall rules.
2. Configure UFW for Docker
Manually, you can modify /etc/ufw/after.rules to ensure UFW controls Docker traffic. Add these 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
These rules allow private networks (e.g., 192.168.0.0/16) to communicate with containers while blocking public access to Docker ports by default.
3. Reload UFW and Restart Docker
Apply the changes and ensure both services are running:
sudo ufw reload
sudo systemctl restart docker
If rules don’t take effect, reboot the server.
4. Allow Specific Public Access (Optional)
To expose a container port (e.g., 80) to the public, use:
ufw route allow proto tcp from any to any port 80
For a specific container (e.g., IP 172.17.0.2):
ufw route allow proto tcp from any to 172.17.0.2 port 80
For UDP services like DNS (port 53):
ufw route allow proto udp from any to any port 53
Note: Always specify the container port (e.g.,
80), not the host port (e.g.,8080), when using-p 8080:80.
5. Verify the Configuration
Check your firewall setup to ensure it’s working:
-
View UFW Rules:
sudo ufw status verbose -
Inspect iptables:
sudo iptables -L -v -n -
Check UFW Logs:
sudo journalctl -u ufw --no-pager | tail -50
These commands confirm that Docker traffic is now controlled by UFW.
Advanced: Using ufw-docker for Granular Control
The ufw-docker script simplifies managing firewall rules, especially for Docker Swarm. Here’s how to use it:
-
Check Rules:
ufw-docker status -
Expose a Container Port:
ufw-docker allow httpd 80 -
Expose a Service in Swarm:
docker service create --name web --publish 8080:80 httpd:alpine ufw-docker service allow web 80 -
Remove Rules:
ufw-docker delete allow httpd
Supporting IPv6
To enable IPv6, add this to /etc/docker/daemon.json:
{
"experimental": true,
"ipv6": true,
"ip6tables": true,
"fixed-cidr-v6": "fd00:dead:beef::/48"
}
Restart Docker:
sudo systemctl restart docker
The ufw-docker script will update /etc/ufw/after6.rules for IPv6 support.
Best Practices for Docker and UFW
- Use Specific IPs: Restrict access to specific container IPs for better security.
- Monitor Logs: Regularly check UFW logs for blocked traffic.
- Test Access: Verify public access only reaches intended ports.
- Update Subnets: Use
ufw-docker install --docker-subnetsto adapt to new Docker networks.
Pro Tip: Combine
ufw-dockerwith monitoring tools like Zabbix to get alerts on unauthorized access attempts.
Conclusion: Secure Your Docker Environment
By integrating UFW with Docker using the ufw-docker script, you can close security gaps without disabling Docker’s iptables. This setup ensures containers communicate internally while blocking unwanted public access. Ready to secure your server? Explore more IT security tips at blog.1it.pro and elevate your infrastructure with 1it.pro.
🚀 Explore more guides on our blog 👉 blog.1it.pro
📧 Contact us: admin@1it.pro for expert IT guidance.
🌐 Explore more: Visit 1it.pro for top-tier IT solutions.