Docker with IPv6

Docker with IPv6

Due to a limit with my Internet provider the IPv4 CGNAT gateway is very unstable. Therefore I disabled IPv4 via CGNAT and running on IPv6 only. For my self hosted services the problem occurred that many DNS names are not resolvable via IPv6 or the application is unable to open the ports for IPv6 connections.

For my home environment I needed a solution and began using AdGuardHome with Public NAT64 services to be able to reach services like Github which are currently not providing IPv6 addresses.

# Resolve IPv4 addresses
dig github.com A

; <<>> DiG 9.18.18-0ubuntu0.22.04.1-Ubuntu <<>> github.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 33874
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;github.com.			IN	A

;; ANSWER SECTION:
github.com.		19	IN	A	140.82.121.3

;; Query time: 4 msec
;; SERVER: 127.0.0.53#53(127.0.0.53) (UDP)
;; WHEN: Fri Dec 22 11:21:42 UTC 2023
;; MSG SIZE  rcvd: 55

# Resolve IPv6 addresses
dig github.com AAAA

; <<>> DiG 9.18.18-0ubuntu0.22.04.1-Ubuntu <<>> github.com AAAA
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 22684
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;github.com.			IN	AAAA

;; AUTHORITY SECTION:
github.com.		851	IN	SOA	ns-1707.awsdns-21.co.uk. awsdns-hostmaster.amazon.com. 1 7200 900 1209600 86400

;; Query time: 0 msec
;; SERVER: 127.0.0.53#53(127.0.0.53) (UDP)
;; WHEN: Fri Dec 22 11:21:45 UTC 2023
;; MSG SIZE  rcvd: 123

After installing AdGuardHome as VM in Proxmox and adding NAT64 resolver the DNS resolution is working for IPv6

# Resolve IPv6 addresses for github.com
dig github.com AAAA

; <<>> DiG 9.10.6 <<>> github.com AAAA
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 34174
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;github.com.			IN	AAAA

;; ANSWER SECTION:
github.com.		14	IN	AAAA	2a00:1098:2c::5:8c52:7903
github.com.		14	IN	AAAA	2a00:1098:2b::1:8c52:7903
github.com.		14	IN	AAAA	2a01:4f9:c010:3f02:64:0:8c52:7903

;; Query time: 36 msec
;; SERVER: fd00::e4b3:e3ff:fe1f:dae7#53(fd00::e4b3:e3ff:fe1f:dae7)
;; WHEN: Fri Dec 22 12:25:49 CET 2023
;; MSG SIZE  rcvd: 123

Enabling Docker to use IPv6

In my setup I am using services like

  • Traefik
  • Vikunja
  • Matrix
  • HomeAssistant
  • Umami
  • etc

First of all Traefik needs to be able to work with IPv6. In the past I was using HAProxy to proxy incoming traffic back to IPv4 which works the most time.

To enable Docker with IPv6 support an easy adjustment to the daemon.json needs to be done

# Create or update current daemon.json
nano /etc/docker/daemon.json
{
  "ipv6": true,
  "fixed-cidr-v6": "fd01::/64",
  "experimental": true,
  "ip6tables": true
}

fixed-cidr-v6 can also be a public routable IPv6 subnet which is delegated via router advertising. In this case every container is getting a public IP. This should only be done if you are sure what you are doing.

After changing the settings a restart of the docker service is necessary. With this configuration Docker is only aware to use IPv6 but will not do it by default.

Create Docker v6 networks

To enable IPv6 support on certain container a new network needs to be created which also contains a separate ULA address. These addresses can be chosen freely.

# Create IPv6 network fd02::/64
docker network create --ipv6 --subnet fd02::/64 traefik-public6

# show network
docker network inspect traefik-public6

    {
        "Name": "traefik-public6",
        "Id": "d142aad4c2f4767dfa8b50c94ebba5ce633f2a58edc3707148c6b36d57e438aa",
        "Created": "2023-11-17T15:12:11.183781286Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": true,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.24.0.0/16",
                    "Gateway": "172.24.0.1"
                },
                {
                    "Subnet": "fd02::/64",
                    "Gateway": "fd02::1"
                }
            ]
        }
        ...

Use IPv6 in docker-compose files

After creating a new network for our service we need to add this to the compose file itself

version: '3.3'
services:
  traefik:
    image: traefik
    command:
     - --api.dashboard=true
     - --accesslog=true
     - --log.level=debug
     - --providers.docker.endpoint=unix:///var/run/docker.sock
     - --providers.docker.swarmMode=false
     - --providers.docker.exposedbydefault=false
     - --providers.docker.network=traefik-public
     - --entrypoints.web.address=:80
     - --entrypoints.websecure.address=:443
     - --entrypoints.matrixfederation.address=:8448
     ...
    environment:
      CF_API_EMAIL: me@example.com
      CF_API_KEY: somecloudflareapikeyhere
    networks:
      - traefik-public6
    ports:
      - 80:80
      - 443:443
      - 8448:8448
    volumes:
     - traefik-certificates:/letsencrypt
     - traefik_data:/var/traefik_data
     - /var/run/docker.sock:/var/run/docker.sock
    labels:
      ...

networks:
  traefik-public6:
    external:
      name: traefik-public6

volumes:
  ...