Port forwarding 80 and 443 to Docker Container

I’ve finally exhausted my search skills after many days and need to ask for help. I’ve got Traefik running as a rootless docker container exposing ports 10080 and 10443 which I’d like to forward ports 80 and 443 to respectively. I have Tailscale running already using nftables so I’d like to keep that setup, even though I did disable that and try the iptables method found in the wiki for rootless docker without success. For nftables I’ve tried the following 2 methods derived from the Networking wiki entry:

    let
      ipAddress = "10.21.32.1";
    in {
    networking = {
      firewall = {
        enable = true;
        allowedTCPPorts = [
          80
          443
        ];
      };
      nat = {
        enable = true;
        internalInterfaces = ["lo"];
        externalInterface = "enp1s0f1";
        forwardPorts = [
          {
            sourcePort = 80;
            proto = "tcp";
            destination = "${ipAddress}:10080";
          }
          {
            sourcePort = 443;
            proto = "tcp";
            destination = "${ipAddress}:10443";
          }
        ];
      };
    };
  };

and

    let
      ipAddress = "10.21.32.1";
    in {
    networking = {
      firewall = {
        enable = true;
        allowedTCPPorts = [
          80
          443
        ];
      };
      nftables = {
        enable = true;
        ruleset = ''
          table ip nat {
            chain PREROUTING {
              type nat hook prerouting priority dstnat; policy accept;
              iifname "enp1s0f1" tcp dport 80 redirect to :10080
            }
            chain PREROUTING {
              type nat hook prerouting priority dstnat; policy accept;
              iifname "enp1s0f1" tcp dport 443 redirect to :10443
            }
          }
        '';
      };
    };
  };

In both cases I’m unable to access services behind Traefik. When I check the ports using nmap it reports closed unless I sudo.

[nix-shell:]$ nmap -p 443 10.21.32.1
Starting Nmap 7.991 ( https://nmap.org ) at 2026-09-28 14:57 -0500
Nmap scan report for kaDT1.local (10.21.32.1)
Host is up (0.000028s latency).

PORT    STATE  SERVICE
443/tcp closed https

Nmap done: 1 IP address (1 host up) scanned in 0.03 seconds

[nix-shell:]$ sudo nmap -p 443 10.21.32.1
Starting Nmap 7.991 ( https://nmap.org ) at 2026-09-28 14:57 -0500
Nmap scan report for kaDT1.local (10.21.32.1)
Host is up.

PORT    STATE    SERVICE
443/tcp filtered https

Nmap done: 1 IP address (1 host up) scanned in 2.06 seconds

[nix-shell:~/nixParts]$

Curl likewise returns curl: (7) Failed to connect to 10.21.32.1:80 after 0 ms: Could not connect to server for when I check ports 80, 443, and the FQDN of the service.

I’m assuming there’s something simple I’m missing here but I’ve run out of documentation and forum posts online to read.

Got it working tonight although I don’t wholly understand why. I had the idea to put the ports that Traefik is using into allowedTCPPorts since I had a vague memory that rootful docker overrides firewall settings (though not sure if this is actually true) and got it working. After some more testing I noticed I could remove 80/443 from the allowedTCPPorts list and things kept forwarding correctly although curiously nmap still returns

Starting Nmap 7.991 ( https://nmap.org ) at 2026-09-28 23:55 -0500
Nmap scan report for chonkpad.local (10.21.32.1)
Host is up (0.00012s latency).
Not shown: 997 closed tcp ports (conn-refused)
PORT    STATE SERVICE
22/tcp  open  ssh
80/tcp  open  http
443/tcp open  https

which doesn’t make sense to me since I removed 80/443 from allowedTCPPorts. I’m going to mark this as solved but if anyone with more experience wants to clear up what’s happening under the hood here I’d love to learn more.

Working config is below. The table traefikPortForward is all that should be needed for a server hosting remotely accessed services. I had to add the traefikLocalDev table as well since the container is current being run and accessed on the same machine.

    # port forward 80/443 to traefik ports 10080/10443
    networking = {
      firewall = {
        enable = true;
        allowedTCPPorts = [
          # ports 80/443 dont need allowed to be forwarded?
          # 80
          # 443
          10080 # traefik http
          10443 # traefik https
        ];
      };

      nftables = {
        enable = true;
        ruleset = ''
          table ip traefikPortForward {
            chain PREROUTING {
              type nat hook prerouting priority dstnat; policy accept;
              iifname "enp1s0f1" tcp dport 80  dnat to 10.21.32.1:10080
              iifname "enp1s0f1" tcp dport 443 dnat to 10.21.32.1:10443
            }
          }

          # hairpin, only uncomment if host and client are same machine
          table ip traefikLocalDev {
            chain PREROUTING {
              type nat hook output priority -100; policy accept;
              oifname "lo" tcp dport 80  redirect to :10080
              oifname "lo" tcp dport 443 redirect to :10443
            }
          }
        '';
      };
    };

Side note: I’ve put 3 different chunks of nix into this thread and all have different syntax highlighting…is there a better way to past code to ensure uniform syntax highlighting?