Skip to content

Instantly share code, notes, and snippets.

@mikroskeem
Last active October 27, 2023 06:33
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mikroskeem/a7e994c8de974d1ffc63f86d8c901bf7 to your computer and use it in GitHub Desktop.
Save mikroskeem/a7e994c8de974d1ffc63f86d8c901bf7 to your computer and use it in GitHub Desktop.
Stay using nftables in combination with Docker, and set up separate network namespace to make it happy.
{ pkgs, ... }:
# Based on https://wiki.archlinux.org/title/Nftables#Working_with_Docker
let
dockerHostName = "dockernet";
hostip = "${pkgs.util-linux}/bin/nsenter --target 1 --net -- ${ip}";
ip = "${pkgs.iproute2}/bin/ip";
dockerNsSetupScript = pkgs.writeShellScript "docker-netns-setup" ''
set -exuo pipefail
# clean up previous veth interface, if exists
${hostip} link delete ${dockerHostName} || true
# create veth
${hostip} link add ${dockerHostName} type veth peer name docker0_ns
${hostip} link set docker0_ns netns "$BASHPID"
${ip} link set docker0_ns name eth0
# bring host veth pair online
${hostip} addr add 10.0.0.1/24 dev ${dockerHostName}
${hostip} link set ${dockerHostName} up
# bring ns veth pair online
${ip} addr add 10.0.0.100/24 dev eth0
${ip} link set eth0 up
${ip} route add default via 10.0.0.1 dev eth0
'';
dockerNsTeardownScript = pkgs.writeShellScript "docker-netns-teardown" ''
set -exuo pipefail
${hostip} link delete ${dockerHostName} || true
'';
in
{
systemd.services.docker.serviceConfig.PrivateNetwork = true;
systemd.services.docker.serviceConfig.ExecStartPre = [
""
"${dockerNsSetupScript}"
];
systemd.services.docker.serviceConfig.ExecStopPost = [
""
"${dockerNsTeardownScript}"
];
}
{ pkgs, lib, config, ... }:
let
nftablesStartScript = pkgs.writeScript "nftables-rules" ''
#!${pkgs.nftables}/bin/nft -f
flush ruleset
include "${config.networking.nftables.rulesetFile}"
'';
in
{
networking.nftables.enable = true;
networking.nftables.ruleset = ''
table ip nat {
chain prerouting {
type nat hook prerouting priority dstnat; policy accept;
tcp dport { 8080 } dnat to 10.0.0.100;
}
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
iifname dockernet masquerade;
}
}
'';
# XXX: default script is checking if ip_tables is loaded, and fails hard if it is.
# In our case, that's unwanted
# iptables and nftables work just fine together at least on >5.x kernels.
systemd.services.nftables.serviceConfig.ExecStart = lib.mkForce nftablesStartScript;
systemd.services.nftables.serviceConfig.ExecReload = lib.mkForce nftablesStartScript;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment