Skip to content

Instantly share code, notes, and snippets.

@goll
Last active April 22, 2025 17:08
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.

@timka
Copy link

timka commented Apr 22, 2025

At least in Ubuntu 22.04 /etc/nftables.conf is a script with the #!/usr/sbin/nft -f shebang. You can't just pipe nft list ruleset to there.

But you can try replacing flush ruleset with stuff like flush table inet filter for all your inet tables followed by the respective rules and never mess with ip/ip6 tables where docker does its networking stuff. In theory you'll be able to just write your nftables rules this way and then apply your changes by simply rerunning the script and that won't affect docker on a running system while also giving you persistent declarative rules.

Haven't tried that yet though.

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