While on Ubuntu servers, image pulls from Docker Hub kept failing with the following error:
Error response from daemon: Get "https://registry-1.docker.io/v2/": dial tcp
[2600:1f18:2148:bc00:c80c:3676:30dd:a616]:443: connect: cannot assign requested address
Running ip addr show confirmed the host has no IPv6 addresses on any interface. The server’s network does not route IPv6.
The culprit is Docker’s Go runtime. Unlike most system programs, Docker does not use the C library’s getaddrinfo() for DNS - it has its own pure Go resolver. When DNS returns both A and AAAA records for registry-1.docker.io, Go prefers the IPv6 address. The kernel immediately returns EADDRNOTAVAIL because there is no IPv6 source address to bind, and the connection fails before any packet reaches the network.
This is why the following do not work:
- Modifying
/etc/gai.confto prefer IPv4 - only affectsgetaddrinfo(), which Docker bypasses sysctl net.ipv6.conf.all.disable_ipv6=1- does not prevent IPv6 socket creationip6tables -A OUTPUT -p tcp -j REJECT- never reached, the error is a local kernel failure before packet creation
The fix is to prevent AAAA records from reaching Docker’s resolver entirely, using dnsmasq with filter-AAAA.
Install dnsmasq:
sudo apt install -y dnsmasq
Create /etc/dnsmasq.d/ipv4-only.conf:
filter-AAAA
server=8.8.8.8
server=1.1.1.1
listen-address=127.0.0.1
bind-interfaces
Disable systemd-resolved’s stub listener so dnsmasq can take port 53, then start dnsmasq:
sudo mkdir -p /etc/systemd/resolved.conf.d
sudo tee /etc/systemd/resolved.conf.d/no-stub.conf << 'EOF'
[Resolve]
DNSStubListener=no
EOF
sudo systemctl restart systemd-resolved
sudo systemctl enable dnsmasq
sudo systemctl restart dnsmasq
Replace /etc/resolv.conf with a static file pointing at dnsmasq:
sudo rm -f /etc/resolv.conf
echo "nameserver 127.0.0.1" | sudo tee /etc/resolv.conf
Confirm the fix by running nslookup registry-1.docker.io - the response should contain only IPv4 addresses. Docker pulls should now succeed consistently.