Hetzner's cheapest VPS plans come with IPv6-only connectivity. Docker doesn't handle this well out of the box — containers won't be able to reach the internet. Here's the full setup.
Docker defaults to IPv4 networking. On an IPv6-only host, containers can't resolve DNS or reach external services (package registries, APIs, OAuth providers, etc.). You'll see:
apt-get updatefailing inside containers- API calls timing out
- OAuth flows breaking
- Anything that needs external connectivity silently failing
/etc/docker/daemon.json:
{
"ipv6": true,
"fixed-cidr-v6": "2001:db8:1::/64"
}Then restart Docker:
sudo systemctl restart dockerThis enables IPv6 on the default bridge network.
The daemon setting only covers the default bridge. Each Docker Compose project creates its own network, and each one needs IPv6 explicitly enabled:
# In your docker-compose.yml
networks:
default:
enable_ipv6: true
ipam:
config:
- subnet: fd00::/80 # Use a unique subnet per projectUse unique subnets to avoid conflicts between projects:
- Project A:
fd00::/80 - Project B:
fd01::/80 - Project C:
fd02::/80
On an IPv6-only host, you probably want to bind to 127.0.0.1 and put a reverse proxy or tunnel in front:
services:
myapp:
ports:
- "127.0.0.1:8080:8080" # Only accessible locallyThen expose via Cloudflare Tunnel, nginx, or similar. Binding to 0.0.0.0 would expose the port but it's only reachable over IPv6 anyway (unless you have Tailscale or similar for IPv4).
Symptoms: the app starts fine but can't reach external APIs. Easy to miss because the container itself works — it just can't talk to the outside world.
If two compose projects use the same fd00::/80 subnet and both are running, the second one will fail to create its network. Keep a simple registry of which subnet each project uses.
Docker's embedded DNS should work over IPv6 once the daemon is configured. If you hit DNS issues, check that your host's /etc/resolv.conf has working IPv6 nameservers.
# Check Docker network IPv6 status
docker network ls --format "table {{.Name}}\t{{.Driver}}\t{{.IPv6}}"
# Test connectivity from inside a container
docker exec <container> curl -6 ifconfig.me
# Check daemon config
cat /etc/docker/daemon.jsonFor services that only support IPv4 endpoints, you have a few options:
- Tailscale with exit node: Route IPv4 traffic through a Tailscale exit node (e.g. Mullvad). Beware of the Docker localhost routing issue this creates.
- NAT64/DNS64: Some providers offer this at the network level.
- Cloudflare Tunnel: Handles IPv4 on Cloudflare's end, your server only needs IPv6 outbound to Cloudflare.