Skip to content

Instantly share code, notes, and snippets.

@goll
Last active March 24, 2025 06:19
Docker nftables configuration for Debian 10

Not happy with Docker modifying your precious firewall rules?

Prerequisites

Install Docker CE and nftables:

$ sudo apt-get install nftables
$ sudo systemctl --now enable nftables

Installing

Manually (create/modify daemon.json before starting docker.service):

$ sudo systemctl start docker
$ sudo systemctl stop docker containerd
$ sudo iptables-save > iptables-docker.conf
$ sudo iptables-restore-translate -f iptable-docker.conf > docker.nft
$ sudo nft flush ruleset
$ sudo nft -f docker.nft
$ sudo nft -s list ruleset > /etc/nftables-docker.conf

tl;dr

$ curl -fsSLO https://gist.github.com/goll/bdd6b43c2023f82d15729e9b0067de60/raw/nftables-docker.sh
$ sudo bash -x nftables-docker.sh

For a persistent config just overwrite /etc/nftables.conf with /etc/nftables-docker.conf

If you prefer manual start/stop you can create an alias for example:

alias dock-on='sudo nft -f /etc/nftables-docker.conf && sudo systemctl start docker'
alias dock-off='sudo systemctl stop docker containerd && sudo nft -f /etc/nftables.conf && sudo ip l d docker0'
table ip filter {
chain INPUT {
type filter hook input priority 0; policy accept;
}
chain FORWARD {
type filter hook forward priority 0; policy accept;
counter jump DOCKER-USER
counter jump DOCKER-ISOLATION-STAGE-1
oifname "docker0" ct state established,related counter accept
oifname "docker0" counter jump DOCKER
iifname "docker0" oifname != "docker0" counter accept
iifname "docker0" oifname "docker0" counter accept
}
chain OUTPUT {
type filter hook output priority 0; policy accept;
}
chain DOCKER {
}
chain DOCKER-ISOLATION-STAGE-1 {
iifname "docker0" oifname != "docker0" counter jump DOCKER-ISOLATION-STAGE-2
counter return
}
chain DOCKER-ISOLATION-STAGE-2 {
oifname "docker0" counter drop
counter return
}
chain DOCKER-USER {
counter return
}
}
table ip nat {
chain PREROUTING {
type nat hook prerouting priority -100; policy accept;
fib daddr type local counter jump DOCKER
}
chain INPUT {
type nat hook input priority 100; policy accept;
}
chain POSTROUTING {
type nat hook postrouting priority 100; policy accept;
oifname != "docker0" ip saddr 172.17.0.0/16 counter masquerade
}
chain OUTPUT {
type nat hook output priority -100; policy accept;
ip daddr != 127.0.0.0/8 fib daddr type local counter jump DOCKER
}
chain DOCKER {
iifname "docker0" counter return
}
}
#!/bin/bash
systemctl stop docker containerd
tee /etc/docker/daemon.json << EOF
{
"iptables": false
}
EOF
curl -fsSLO https://gist.github.com/goll/bdd6b43c2023f82d15729e9b0067de60/raw/nftables-docker.conf -o /etc/nftables-docker.conf && nft -f /etc/nftables-docker.conf
systemctl start docker
@fabienengels
Copy link

So you manage your exposed ports manually ?

@obarisk
Copy link

obarisk commented May 16, 2021

If expored by docker-proxy, this ruleset work well. Without docker-proxy, it requies dnat.

@CRAG666
Copy link

CRAG666 commented Mar 2, 2022

I followed the entire tutorial to the letter and I have problems connecting to the internet from the container

@TimB87
Copy link

TimB87 commented Mar 6, 2022

This works for me on CRUX, thanks for sharing!

@CRAG666
Copy link

CRAG666 commented May 24, 2022

@goll I also have problems connecting from localhost, When I use Docker Compose

@ukd1
Copy link

ukd1 commented Aug 5, 2022

Thanks for this!

@mihaigalos
Copy link

This worked for me after a restart of the system, not before. I suspect it's because the docker socket that got recreated.

@zmitya
Copy link

zmitya commented Mar 15, 2023

It is very strange, because Docker sets up its FORWARD chain's policy as "drop" (for a reason). But in your case it is accept for some reason.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment