5

My server is running on both IPv4 and IPv6. Docker is running on (local) IPv4 addresses (ie 192.168.100.1/24). I did not enable IPv6 inside daemon.json as I understand that to be rather buggy and requires me to have a full IPv6 /64 range available.

For example, a reverse-proxy nginx docker container is running at superuser.one -- that IP is accessible both over IPv4 and IPv6.

# dig superuser.one +short a
85.17.140.73
# dig superuser.one +short aaaa
2001:1af8:4200:a003:1:aaaa:0:123

And IPv6 is working:

# ping6 superuser.one -c 1
PING superuser.one(2001:1af8:4200:a003:1:aaaa:0:123 (2001:1af8:4200:a003:1:aaaa:0:123)) 56 data bytes
64 bytes from 2001:1af8:4200:a003:1:aaaa:0:123 (2001:1af8:4200:a003:1:aaaa:0:123): icmp_seq=1 ttl=57 time=19.5 ms

--- superuser.one ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 19.526/19.526/19.526/0.000 ms

However, when accessing the webserver (or other services running behind Docker), IPv6 doesn't work:

# curl https://superuser.one -6 -I
curl: (7) Failed to connect to superuser.one port 443: Connection refused

While IPv4 works fine:

# curl https://superuser.one -4 -I
HTTP/2 200
server: nginx
date: Mon, 22 Feb 2021 15:10:37 GMT
[...]

How can I get Docker to listen to the server's IPv6 address and forward the request to the right container (using the regular bridge or host network already set up)?

Edit 1:

ip -6 addr: https://pastebin.com/zKkZW6CE

# docker network ls
NETWORK ID     NAME            DRIVER    SCOPE
4ea1dddd3d64   0x04            bridge    local
c6ad6c596ec5   bridge          bridge    local
5d5ea78ff91f   host            host      local
7a03e7ecb430   matrix          bridge    local
20cb1fbc5dfe   matrix-coturn   bridge    local
684af653d87a   none            null      local

docker network inspect 0x04: https://pastebin.com/tWYNyM3Y

Edit 2:

I cleared my daemon.json file as I had the following content:

"ipv6": true,
"fixed-cidr-v6": "fd00::/80"

This means I can now correctly run IPv4 and IPv6 connections on my bridge network:

ipv4 and ipv6 working

However, this doesn't seem to work with --network option. Most my containers are running in their own network.

Tuinslak
  • 1,465
  • 8
  • 32
  • 56
  • Can you edit your question with some network information? `ip -6 addr` on the host, `docker network ls` and `docker network inspect `? Also, does the application inside the container bind on ipv6 too? – Halfgaar Feb 24 '21 at 17:08
  • Done :) No, internal apps don't bind on IPv6 – Tuinslak Feb 25 '21 at 05:59

1 Answers1

1

You can just declare a normal port forward during container creation, using

-p [2001:dead:beef::1]:22:22

That creates an IPv6 socket on the host that is forwarded to an IPv4 socket inside the container.

To listen to any IPv6 address, use [::] as the listen address.

Simon Richter
  • 3,317
  • 19
  • 19
  • So something like this: `docker run -d -P -p [::]:80:80 -p [::]:443:443 -p 80:80 -p 443:443 -e TZ=Asia/Singapore -v /etc/letsencrypt:/etc/letsencrypt --restart always --network 0x04 --name ocean-nginx ocean-nginx` ? – Tuinslak Feb 25 '21 at 06:06
  • @Tuinslak, yes, with the caveat that IPv6 sockets bound to `[::]` can also accept v4 connections, depending on the `bindv6only` setting (which has a distro-specific default). If `/proc/sys/net/ipv6/bindv6only` is zero, you can omit the `-p 80:80 -p 443:443`, as that is covered already by the others and would generate a conflict. – Simon Richter Feb 25 '21 at 12:43
  • Interesting, amd64 debian and one RPi return `0`, but another RPi return `cat: /proc/sys/net/ipv6/bindv6only: Cannot allocate memory`. On the amd64 debian that returns 0, when removing `-p 80:80` it makes IPv4 not work (`docker run -d -P -p [::]:80:80 -p [::]:443:443 -e TZ=Asia/Singapore -v /etc/letsencrypt:/etc/letsencrypt --restart always --network 0x04 --name ocean-nginx ocean-nginx`). Adding both IPv6 and IPv4 (as mentioned in the first comment) it makes IPv4 work but not IPv6 still – Tuinslak Feb 25 '21 at 14:09
  • Is it because I am using `--network`? – Tuinslak Feb 25 '21 at 14:09
  • @Tuinslak, [this](https://www.ipspace.net/kb/DockerSvc/40-userland-proxy.html) suggests that Docker explicitly turns off IPV6_V6ONLY, but that contradicts what you are seeing. Quick testing with `docker run --rm -it -p [::]:2222:22 debian` allows me to connect with both v4 and v6. – Simon Richter Feb 25 '21 at 14:54
  • @Tuinslak, after the container starts, there should be a `docker-proxy` process for every port mapping, with an explicit `-host-ip` parameter. The `-P` parameter would probably also create a bunch of (random) mappings, but that should be in addition to the ones you specify. – Simon Richter Feb 25 '21 at 15:01
  • So running `docker run --rm -it -p [::]:2222:22 debian` and installing/running sshd -D for me doesn't work `ssh localhost -p 2323`, `ssh: connect to host localhost port 2323: Connection refused` but running. Running `docker run --rm -it -p 2222:22 debian`: `ssh localhost -p 2323` `The authenticity of host '[localhost]:2323 ([127.0.0.1]:2323)' can't be established.` – Tuinslak Feb 26 '21 at 13:46
  • I did have `"ipv6": true, "fixed-cidr-v6": "fd00::/80" in my daemon.json, but removing that did not change anything. `docker-proxy` shows me one result: https://static.yeri.be/2021/02/2323.png -- is that what it should be? – Tuinslak Feb 26 '21 at 13:59
  • Let us [continue this discussion in chat](https://chat.stackexchange.com/rooms/120197/discussion-between-tuinslak-and-simon-richter). – Tuinslak Feb 26 '21 at 14:01
  • "that is forwarded to an IPv4 socket inside the container" I don't think that is true, I have assigned IPv6 addresses to my containers and the port forwarding seems to forward to the container's IPv6 address, not its IPv4 address. – AndreKR Aug 12 '23 at 21:10