When you run a Docker container with port mapping like this:
docker run --name some_container_1 -p 8080:80 -d some_image
You might notice that the exposed port (8080 in this case) becomes accessible from external networks, even when your iptables INPUT chain has restrictive rules. This behavior occurs because Docker manipulates iptables rules in a special way.
Docker creates its own networking rules in these chains:
- FORWARD chain for container-to-container communication
- DOCKER chain for port forwarding
- NAT table for address translation
The key issue is that Docker bypasses the INPUT chain completely when handling incoming connections to published ports.
Instead of modifying the INPUT chain, we need to add restrictions to the DOCKER chain. Here's how to limit access to only IP 123.456.789.0:
# First, delete the existing rule in DOCKER chain
sudo iptables -D DOCKER -d 172.17.0.2/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 80 -j ACCEPT
# Add new restricted rule
sudo iptables -I DOCKER -d 172.17.0.2/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 80 -s 123.456.789.0 -j ACCEPT
To make these changes permanent:
# Save current rules
sudo iptables-save > /etc/iptables/rules.v4
# On Debian/Ubuntu, install persistent package
sudo apt-get install iptables-persistent
For newer Docker versions, you can use the --iptables=false
flag when starting Docker, then manage all rules manually:
# Stop Docker
sudo systemctl stop docker
# Edit Docker service file
sudo nano /etc/systemd/system/docker.service.d/override.conf
# Add:
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd --iptables=false
# Reload and restart
sudo systemctl daemon-reload
sudo systemctl start docker
To confirm your restrictions are working:
# Check active rules
sudo iptables -L DOCKER -n -v
# Test connectivity
curl -I http://your-server:8080 # From allowed IP
curl -I http://your-server:8080 # From blocked IP
If you encounter problems:
- Check Docker logs:
journalctl -u docker.service
- Verify rule order:
sudo iptables -L DOCKER -n --line-numbers
- Test with temporary rule:
sudo iptables -I DOCKER 1 -j LOG
to see traffic
When running a Docker container with port mapping like:
docker run --name some_container_1 -p 8080:80 -d some_image
The container's port 80 becomes accessible on the host's port 8080. By default, Docker bypasses the host's iptables INPUT chain rules, making the port accessible from external networks when you might want to restrict access.
From the provided iptables output, we can see Docker creates its own chains and rules:
Chain DOCKER (1 references)
num pkts bytes target prot opt in out source destination
1 24 1524 ACCEPT tcp -- !docker0 docker0 0.0.0.0/0 172.17.0.2 tcp dpt:80
This rule allows all traffic to reach the container's port 80, regardless of the INPUT chain restrictions.
To restrict access to only specific IPs (like 123.456.789.0), we need to modify Docker's forwarding rules:
# First, flush existing Docker rules
sudo iptables -t filter -F DOCKER
# Then add the restricted rule
sudo iptables -t filter -A DOCKER -d 172.17.0.2/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 80 -s 123.456.789.0/24 -j ACCEPT
# Add a DROP rule for other sources
sudo iptables -t filter -A DOCKER -d 172.17.0.2/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 80 -j DROP
To make these changes permanent:
sudo apt-get install iptables-persistent
sudo netfilter-persistent save
For newer Docker versions, you can use the --iptables=false flag when starting the daemon and manage all rules manually:
dockerd --iptables=false
Then create custom rules in the INPUT chain:
sudo iptables -A INPUT -p tcp --dport 8080 -s 123.456.789.0/24 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 8080 -j DROP
After applying these rules, verify with:
sudo iptables -t filter -L DOCKER -n -v
You should see your restricted rules in place.