Every server we deploy, VPS or dedicated, in all six sites, gets an IPv4 address and a routed /64 of IPv6. The /64 is not a checkbox feature: about 45% of the traffic reaching our customers' web servers arrives over IPv6, and a server without it is slower to reach for nearly half the internet. This post explains how the block is delivered, why “routed” matters, and how to actually use eighteen quintillion addresses.
Routed, not on-link
There are two ways a host can hand you IPv6. The lazy way puts your addresses on the same link as everyone else's and relies on neighbour discovery to find them; it works for one address and breaks the moment you want a container or a VM to have its own. The routed way gives the server a small point-to-point link and routes the entire /64 to it. Anything inside the server, a container, a VM, a WireGuard peer, can take an address from the block and be reachable without any proxying or NDP tricks.
Our images configure the point-to-point address and the default route at first boot. The block is yours from the first second; nothing in the panel needs enabling.
ip -6 addr show dev eth0 # the first address of your /64 is configured
ip -6 route show default # via the site's gateway, on eth0
cat /etc/netplan/*.yaml # Ubuntu: the block and gateway are here
One address per service
The habit worth forming is the opposite of the IPv4 one. Instead of one address and a port per service, give each service its own address on port 443. Add addresses to the interface, freely:
ip -6 addr add 2001:db8:1:411::443:1/64 dev eth0 # web
ip -6 addr add 2001:db8:1:411::25:1/64 dev eth0 # mail
ip -6 addr add 2001:db8:1:411::5432:1/64 dev eth0 # database, firewalled to one client
Make them permanent in netplan (addresses: list) and bind each daemon to its own address. Reverse DNS for any address in your block can be set from the panel under the server's Network tab, which matters for mail and for anything that logs hostnames.
Containers and VMs
Docker's IPv6 support is off by default. Turn it on with a subnet carved from your block; a /80 gives every container its own global address and no NAT:
cat > /etc/docker/daemon.json <<'EOF'
{ "ipv6": true, "fixed-cidr-v6": "2001:db8:1:411:d0c::/80", "ip6tables": true }
EOF
systemctl restart docker
docker run --rm alpine ping6 -c1 ipv6.google.com
Because the /64 is routed to the server, packets for the /80 arrive at the host and are forwarded to the container by the kernel; there is nothing else to configure. The same applies to LXC, libvirt guests or a WireGuard tunnel network: take a slice of the block, enable forwarding, done.
Firewall it like IPv4
Every address in the block is globally reachable, which is the feature and also the reason to keep the firewall symmetric. With ufw, rules apply to both families by default (IPV6=yes in /etc/default/ufw); check with ufw status that each rule has a (v6) twin. With nftables, use an inet table so one rule set covers both. The classic mistake is a database bound to :: with a firewall that only knows about IPv4.
DNS and the 45%
Add an AAAA record alongside the A record for every hostname. Modern clients try IPv6 first (with a fallback race of about 250 ms if it fails), and mobile networks in particular are IPv6-native with IPv4 behind carrier NAT. A site with an AAAA record is reached directly by those clients; one without goes through the carrier's translator, adding latency and occasionally breaking long connections. The 45% figure is what our customers' nginx logs show across the fleet; for mobile-heavy sites it is higher.
Test from outside
A green check in the panel says the address is configured, not that it is reachable. Test from a machine on another network:
ping6 2001:db8:1:411::443:1
curl -6 -sI https://example.com | head -1
dig AAAA example.com +short
Or use the looking glass at /network/looking-glass, which pings and traceroutes over both families from each of our sites. For a public check, the usual online IPv6 test sites tell you whether the AAAA record, the reachability and the TLS certificate all agree.
More than a /64
A /64 is the smallest block that works with every IPv6 feature (SLAAC needs exactly 64 bits of host part), and it is enough for a fleet of containers. If you run a hypervisor or a VPN concentrator that wants to hand out its own /64s, a /56 is available on request for dedicated servers; open a ticket with the use case and it is routed within a day. We do not charge for address space; IPv6 was designed to be plentiful, and pricing it defeats the purpose.
