A firewall for Docker that blocks accidental port exposure
Posted: Tue Aug 26, 2025 8:44 pm
When you start a Docker container with the parameter "-p 0.0.0.0:port_number:port_number" or in the docker-compose.yml file you have set "ports: ["port_number:port_number"]", in other words, when you expose an internal port to be available to the host server or other dockers, keep in mind that those ports actually become available over the Internet (anyone on the Internet can access that port on your server).
Even if you put DROP in the INPUT chain in iptables, those ports will still be visible over the Internet.
This happens because 'dockerd' inserts DNAT rules into the nat/PREROUTING and nat/DOCKER chains before your standard filter/INPUT chain.
Namely, a TCP/UDP packet comes from the Internet, goes through DNAT in nat/DOCKER, and ends up in filter/DOCKER.
Then the package is no longer intended for eth0 but for docker-bridge (docker0), so the package does not even reach the DROP action and the INPUT chain.
To ensure that no Docker ports are exposed to the Internet, do the following:
The source code of the script is:
Even if you put DROP in the INPUT chain in iptables, those ports will still be visible over the Internet.
This happens because 'dockerd' inserts DNAT rules into the nat/PREROUTING and nat/DOCKER chains before your standard filter/INPUT chain.
Namely, a TCP/UDP packet comes from the Internet, goes through DNAT in nat/DOCKER, and ends up in filter/DOCKER.
Then the package is no longer intended for eth0 but for docker-bridge (docker0), so the package does not even reach the DROP action and the INPUT chain.
To ensure that no Docker ports are exposed to the Internet, do the following:
Code: Select all
wget -nv https://dl.myvestacp.com/install-docker-firewall.sh -O install-docker-firewall.sh
bash install-docker-firewall.sh
Code: Select all
#!/bin/bash
# Get network interface for the internet
iface=$(ip r get 8.8.8.8 | grep -oP 'dev \K\S+')
cat <<EOF > /usr/local/sbin/docker-fw.sh
#!/bin/sh
iptables -C DOCKER-USER -i $iface -p tcp -j DROP 2>/dev/null || \
iptables -I DOCKER-USER -i $iface -p tcp -j DROP
iptables -C DOCKER-USER -i $iface -p udp -j DROP 2>/dev/null || \
iptables -I DOCKER-USER -i $iface -p udp -j DROP
EOF
chmod +x /usr/local/sbin/docker-fw.sh
cat <<EOF > /etc/systemd/system/docker-fw.service
[Unit]
Description=Post-Docker firewall rules
After=docker.service network-online.target
Requires=docker.service
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/docker-fw.sh
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now docker-fw.service