Linux – How to forward IPv6 port 80/443 to a podman container

containersipv6linuxnat;podman

I recently containerized my personal webserver. However, I've now noticed that it's no longer accessible over IPv6. Port mapping (-p 80:80 -p 443:443) only works for IPv4: https://github.com/containers/podman/issues/4323.

So far I've managed to get the pod its own IPv6 ULA address by adding

          [
            {
              "subnet": "fc01::/48",
              "gateway": "fc01::1"
            }
          ]

to /etc/cni/net.d/87-podman-bridge.conflist. So now I can curl 'http://[fc01::1]' from the host itself. But I can't figure out the ip6tables magic to forward requests on the public IP to the container. Based on https://www.tldp.org/HOWTO/Linux+IPv6-HOWTO/ch18s04.html, I've tried

# ip6tables -t nat -A POSTROUTING -o eth0 -s fc01::1/48 -j MASQUERADE
# ip6tables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to-destination '[fc01::1]:80'
# ip6tables -A FORWARD -i eth0 -o cni-podman0 -p tcp --dport 80 -j ACCEPT

and various subsets of those commands, but I get either timeouts or "No route to host".

My addresses look like this:

$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether f2:3c:91:c8:5b:d9 brd ff:ff:ff:ff:ff:ff
    inet <PUBLIC IPv4>/24 brd <BROADCAST> scope global eth0
       valid_lft forever preferred_lft forever
    inet6 <PUBLIC IPv6>/64 scope global dynamic mngtmpaddr noprefixroute 
       valid_lft 2591999sec preferred_lft 604799sec
    inet6 fe80::f03c:91ff:fec8:5bd9/64 scope link 
       valid_lft forever preferred_lft forever
3: cni-podman0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether b6:58:df:4b:b9:71 brd ff:ff:ff:ff:ff:ff
    inet 10.88.0.1/16 brd 10.88.255.255 scope global cni-podman0
       valid_lft forever preferred_lft forever
    inet6 fc01::1/48 scope global 
       valid_lft forever preferred_lft forever
    inet6 fe80::b458:dfff:fe4b:b971/64 scope link 
       valid_lft forever preferred_lft forever
4: vethb4059020@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master cni-podman0 state UP group default 
    link/ether d6:5d:37:f2:0c:48 brd ff:ff:ff:ff:ff:ff link-netns cni-26c430c8-c816-8962-b2f2-b3bbb5274f93
    inet6 fe80::d45d:37ff:fef2:c48/64 scope link 
       valid_lft forever preferred_lft forever

Best Answer

No, you do not need port forwarding. Container gets a unique IP address; the destination is not the host.

Say for example:

  • Your randomly generated ULA network was fdab:9bac:936f::/48
  • Gave fdab:9bac:936f:0ca2::/64 to a host for containers
  • Your route tables forward the container subnet to the proper host.
  • Assigned fdab:9bac:936f:0ca2::443 to this web server container (vanity IP via static addressing)
  • The host happens to have an IP of fdab:9bac:936f:1292::359 (different subnet)

Then access the web server container at fdab:9bac:936f:0ca2::443. If the only thing running in the container is a web server, those are the only open ports (80 and 443).


Only recently has container networking enabled sane IPv6 configurations that skip NAT. My reading of issue podman and IPv6 is that CNI plugins have the features to define IP address assignment, and push routes. If you choose to do container networking in that way.


ULA is not ideal. It will not route via the internet. Address selection policies put at at a lower priority than IPv4.

Internet routable is better. Unfortunately, you obfuscated your IP address.