IPv6 on a VPS without the usual surprises
Configure a static IPv6 address and default route, firewall it properly, publish AAAA records, and test the complete path from outside.

IPv6 is not IPv4 with longer addresses. Hosts often receive globally routable addresses directly, neighbour discovery replaces ARP, and blocking ICMPv6 indiscriminately can break the network.
Confirm the assigned network
Collect four values from the VPS provider: your address, prefix length, gateway, and whether the gateway is on-link. Do not invent a gateway from the subnet.
Inspect the current state:
ip -6 address show
ip -6 route show
ping -6 -c 3 2606:4700:4700::1111
If an address and default route already exist, persist the provider's configuration rather than adding a competing route.
Configure Netplan on Ubuntu
An example /etc/netplan/60-vps.yaml:
network:
version: 2
ethernets:
ens3:
addresses:
- 203.0.113.20/24
- 2001:db8:100::20/64
routes:
- to: default
via: 203.0.113.1
- to: default
via: 2001:db8:100::1
on-link: true
nameservers:
addresses: [1.1.1.1, 2606:4700:4700::1111]
Interface names and routing requirements vary. Use sudo netplan try from a console-capable session so configuration rolls back if connectivity is lost.
Firewall both protocol families
Check /etc/default/ufw contains IPV6=yes, then apply the same service policy:
sudo ufw default deny incoming
sudo ufw allow OpenSSH
sudo ufw allow 80,443/tcp
sudo ufw enable
sudo ufw status verbose
Do not add a blanket rule blocking ICMPv6. Packet Too Big, neighbour discovery, and router messages are part of normal IPv6 operation.
Check application listeners
ss -lntp
0.0.0.0:443 covers IPv4. [::]:443 covers IPv6 and may also accept IPv4 depending on system settings. Configure the web server explicitly and test both families.
Publish and test AAAA
Add the AAAA record only after the service works by address:
curl -6 --resolve app.example.com:443:[2001:db8:100::20] https://app.example.com/
Then publish DNS and test from a different network:
dig AAAA app.example.com +short
curl -4I https://app.example.com
curl -6I https://app.example.com
Monitor IPv4 and IPv6 separately. A single “site is up” check can hide a failed family because clients fall back to the other one.
Check neighbour discovery and path MTU
If the address is configured but connections hang, inspect the route and neighbour table:
ip -6 route get 2606:4700:4700::1111
ip -6 neigh show
tracepath6 app.example.com
Do not “fix” a path-MTU problem by blocking ICMPv6. Check provider filtering, firewall counters, and the tunnel or reverse proxy in the path. A service that works for small headers but fails on larger responses often points to MTU rather than DNS.
Use stable names and rollback safely
Keep the IPv6 address in the provider inventory and use a stable interface configuration. Apply Netplan with netplan try from the provider console, open a second SSH session, and only then make the change permanent. If the application is not ready for IPv6, omit the AAAA record; partial IPv6 deployment is worse than an explicit IPv4-only service.
Once enabled, add an IPv6 synthetic check, review firewall logs, and confirm reverse DNS if the server sends mail or participates in network services. Treat IPv6 as a first-class path in incident runbooks.
Confirm application-generated URLs
After enabling AAAA, test redirects, callbacks, asset URLs, and webhook allowlists over IPv6. A site can serve its HTML over IPv6 while an API callback, database allowlist, or monitoring probe still rejects the address. Check access logs for the client's address family and make sure rate limits and trusted-proxy settings understand IPv6 notation.
Record the prefix and provider routing details with the server inventory. If you later move the VPS, do not assume the same IPv6 address or prefix can be retained; plan the DNS change and certificate renewal as part of the migration.
Continue reading