54

When the docker-demon starts it adds a couple of rules to iptables. When all rules are deleted via iptables -F i have to stop and restart the docker demon to re-create dockers rules.

Is there a way to have docker re-add it's additional rules?

kioopi
  • 2,170
  • 2
  • 18
  • 26

3 Answers3

53

the best way is to restart your docker service, then it'll re-add your docker rules to iptables. (on deb-based: sudo service docker restart)

however, if you just want to restore those rules without restarting your service, i saved mine so you can inspect, and adjust it to work for you, then load using sudo iptables-restore ./iptables-docker-ports.backup

edit and save this to ./iptables-docker-ports.backup

# Generated by iptables-save v1.4.21 on Thu Apr 30 20:48:42 2015
*nat
:PREROUTING ACCEPT [18:1080]
:INPUT ACCEPT [18:1080]
:OUTPUT ACCEPT [22:1550]
:POSTROUTING ACCEPT [22:1550]
:DOCKER - [0:0]
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
-A POSTROUTING -s 172.17.0.1/32 -d 172.17.0.1/32 -p tcp -m tcp --dport 80 -j MASQUERADE
-A DOCKER ! -i docker0 -p tcp -m tcp --dport 3001 -j DNAT --to-destination 172.17.0.1:80
COMMIT
# Completed on Thu Apr 30 20:48:42 2015
# Generated by iptables-save v1.4.21 on Thu Apr 30 20:48:42 2015
*filter
:INPUT ACCEPT [495:53218]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [480:89217]
:DOCKER - [0:0]
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT
-A DOCKER -d 172.17.0.1/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 80 -j ACCEPT
COMMIT
# Completed on Thu Apr 30 20:48:42 2015
theRemix
  • 2,154
  • 16
  • 16
  • 1
    Thanks a lot, it is the only post where I found the default docker configuration to reset my iptables rules, perfect ! – meucaa Jun 20 '17 at 13:16
  • 8
    THIS WILL STOP your container! Restarting the docker service stops all containers. Not a solution. – John Jul 21 '18 at 15:08
  • Indeed, I can't believe this is actually the accepted answer. :-) – Tony Mar 15 '23 at 17:42
10

If you're running Ubuntu on the host, you can use the iptables-save utility to save the iptables rules to a file after you start the docker daemon. Then, once you flush the old rules, you can simply restore the original docker rules using iptables-restore & the saved rules file.

If you don't want to restore all the old iptables rules, you can alter the saved rules file to keep only the ones you need.

If you're running another operating system, you might find a similar alternative.

dcro
  • 13,294
  • 4
  • 66
  • 75
  • 3
    Are the rules for docker always the same? Can I add them to my iptables-restore config file permanently? – Hubro Jun 01 '16 at 08:31
  • To elaborate: I use iptables-persistent and a custom rule file as a firewall. Any time I need to open a port I edit my rules file and apply it using `iptables-apply`. I keep a clean structure and lots of comments for documentation in my rules file, so overwriting it is not an option. – Hubro Jun 01 '16 at 08:41
  • 1
    be careful with blindly saving/restoring the rules as the IPs of containers can change when restarting them ! – pHiL Oct 27 '16 at 09:28
8

Docker in default configuration, when running in bridge mode, does manipulate iptables (a lot) unless you disable it (then you would have to configure your own NAT rules).

The default network-related configuration is probably following, although the config /etc/docker/daemon.json might not exist (and as of now you can't print effective configuration):

{
"userland-proxy": true,
"iptables": true,
"ip-forward": true,
"ip-masq": true,
"ipv6": false
}

After Docker daemon starts, it injects following rules (in filter):

-N DOCKER
-N DOCKER-ISOLATION-STAGE-1
-N DOCKER-ISOLATION-STAGE-2
-N DOCKER-USER

-A FORWARD -j DOCKER-USER
-A FORWARD -j DOCKER-ISOLATION-STAGE-1
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT

-A DOCKER-ISOLATION-STAGE-1 -i docker0 ! -o docker0 -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-1 -j RETURN
-A DOCKER-ISOLATION-STAGE-2 -o docker0 -j DROP
-A DOCKER-ISOLATION-STAGE-2 -j RETURN
-A DOCKER-USER -j RETURN

In order to understand what Docker does, here is a list of Docker-generated iptables rules with a short explanation. If you flush iptables rules, while Docker daemon and some containers are running, you might break access to existing containers (but probably won't break anything, more about this below).

After service docker restart all default rules are injected into firewall (you can check it by running iptables-save or iptables -S, iptables -S -t nat). Assuming you want to keep your containers running and only generate missing NAT rules.

docker ps gives us list of running containers:

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                         NAMES
865569da8d36        nginx               "nginx -g 'daemon of…"   17 hours ago        Up 17 hours         0.0.0.0:4564->80/tcp, 0.0.0.0:32237->80/tcp   jovial_sammet

And from docker inspect we can obtain the port mapping

$ docker inspect -f '{{.NetworkSettings.Ports}}' 865569da8d36
map[80/tcp:[{0.0.0.0 4564} {0.0.0.0 32237}]]

now we need just the internal IP address of Docker container:

$ docker inspect -f '{{.NetworkSettings.IPAddress}}' 865569da8d36
172.17.0.2

Now using some bash/jq we can generate the dynamic iptables rules:

$ bash docker_iptables --noop
iptables -A DOCKER -d 172.17.0.2
iptables -t nat -A DOCKER ! -i docker0 -p tcp -m tcp --dport 4564 -j DNAT --to-destination 172.17.0.2:80
iptables -A DOCKER -d 172.17.0.2
iptables -t nat -A DOCKER ! -i docker0 -p tcp -m tcp --dport 32237 -j DNAT --to-destination 172.17.0.2:80

So the answer to the question is: No, not without stopping all containers. But the rules can be re-added manually (NOTE: this script doesn't cover all Docker functionality, e.g. if you're exposing some service running in other network than Docker container).

When you start Docker container with exposed ports (-p):

docker run --rm -d -p 32237:80 -p 4564:80 nginx

Docker spins up also docker-proxy. What's that?

$ netstat -tulpn | grep docker-proxy
tcp        0      0 0.0.0.0:32237           0.0.0.0:*               LISTEN      20487/docker-proxy  
tcp        0      0 0.0.0.0:4564            0.0.0.0:*               LISTEN      20479/docker-proxy

The Linux kernel does not allow the routing of loopback traffic, and therefore it's not possible to apply netfilter NAT rules to packets originating from 127.0.0.0/8. docker-proxy is generally considered as an inelegant solution to such problems.

When you restore iptables without Docker rules, the container ports might be still available via docker-proxy. However this might bring some performance issues in networking, as docker-proxy won't be as fast as kernel's netfilter.

Tombart
  • 30,520
  • 16
  • 123
  • 136