0

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
  • 2
    Use a global subnet that has been routed to your device. – Michael Hampton Aug 23 '20 at 17:54
  • Even if I give the container a routable IP, I'll need to do some kind of port forwarding. I can't point DNS at the container since only HTTP should hit the container. SSH etc. should hit the host – Tavian Barnes Aug 23 '20 at 18:42

1 Answers1

2

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.

John Mahowald
  • 32,050
  • 2
  • 19
  • 34
  • Is it possible to have port 22 go to the host, while ports 80/443 go to the container, without NAT? By the way, the host IP is routable (`2600:...`), not ULA. I just gave the containers ULA addresses because I don't really want them accessible from the internet. – Tavian Barnes Aug 24 '20 at 18:04
  • 1
    Use the host's (unique, not related to any container) IP address when you want to contact the host. Private IP ranges do not make you inaccessible from the internet, packet filters do. Deny connections you don't want at firewalls (from the internet, and possibly between internal subnets). – John Mahowald Aug 24 '20 at 18:48
  • Sure, I'll give the containers routable addresses. But I really would prefer `ssh example.com` and `curl example.com` to both work, even if I have to use IPv6 NAT to do it. – Tavian Barnes Aug 24 '20 at 20:07
  • IPv6 NAT is not really done, I don't have a good implementation of it to recommend offhand. Instead, have `example.com` resolve to a reverse proxy or something in front of whatever backends you want. In addition to adding all hosts to DNS, so a name like `host1.example.com` works to bypass the load balancer. – John Mahowald Aug 29 '20 at 21:21