IPv6 Access to Published Ports
Articles » Docker Networking for Container-Based Services » IPv6 Access to Published Ports
The previous section described the role of userland docker-proxy supporting containers connecting to published ports, or local processes connecting to loopback interface. We’ve also seen that when a published port is not bound to a specific IPv4 address, the proxy process listens on an IPv6 socket, enabling IPv6 access to services offered in IPv4-only containers.
It’s easy to check whether the expected IPv6 functionality works: connect to a published port on ::1 from a local process:
$ docker run --rm -d --name web_1 -p 8080:80 webapp
3398eae2649a55d2b9aa11c4979a50e025c035e34227537f4f4bd91c3ba44c9f
$ curl http://[::1]:8080/
<b>Hostname:</b> 3398eae2649a<br/>
<b>Remote IP:</b> 172.17.0.1
As expected, the remote IP address seen by the web server running in a Docker container (our Flask application) is the source IPv4 address of the outgoing docker-proxy session.
If you want to see IPv6 and IPv4 TCP sessions going through the docker-proxy process, use telnet to connect to a published port and netstat to display the established sessions:
$ netstat -nt
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 172.17.0.1:52880 172.17.0.2:80 ESTABLISHED
tcp6 0 0 ::1:8080 ::1:41534 ESTABLISHED
tcp6 0 0 ::1:41534 ::1:8080 ESTABLISHED
IPv6 access to published ports is obviously not limited to the local processes; IPv6 clients can reach a container-based service as soon as you have an IPv6 address configured on an external interface.
$ ip addr show dev eth1
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc...
link/ether 08:00:27:9b:8a:66 brd ff:ff:ff:ff:ff:ff
inet 192.168.33.2/24 brd 192.168.33.255 scope global eth1
valid_lft forever preferred_lft forever
inet6 2001:db8::2/64 scope global
valid_lft forever preferred_lft forever
inet6 fe80::a00:27ff:fe9b:8a66/64 scope link
valid_lft forever preferred_lft forever
worker-1$ curl http://[2001:db8::2]:8080/
<b>Hostname:</b> 3398eae2649a<br/>
<b>Remote IP:</b> 172.17.0.1
Limitations
While the Docker proxy enables convenient IPv6 connectivity to published container ports, it does not provide the true client identity information - it’s a simple TCP proxy and thus does not add HTTP headers or any other indication what the actual client IPv6 address might be.
You can easily check that claim with our Flask application, which returns original HTTP headers when invoked with the /headers
path. You’ll see the headers generated by the web client, but no extra headers like X-Forwarded-For
a typical web proxy might insert.
$ curl http://[2001:db8::2]:8080/headers
User-Agent: curl/7.58.0
Host: [2001:db8::2]:8080
Accept: */*
Next: Conclusions
More Information
- If you’re new to Docker, start with Introduction to Docker webinar; if you’d like to learn more about Docker networking, explore the Docker Networking Deep Dive webinar. Both webinars are part of ipSpace.net subscription.
- The source code for all the examples used in this article is available on Github.
- All printouts in this article were created on a Ubuntu host running Docker engine version 19.03.12.