IPv6 stopped being a future topic. A large share of North American mobile traffic is native IPv6, several major mail providers treat properly configured IPv6 senders better, and a service reachable over both families depends less on translation layers. On our VPS plans, every VM gets four IPv6 addresses alongside its IPv4.
This guide covers static configuration on Ubuntu 24.04 with Netplan, DNS publication, reverse DNS, and filtering.
1. Assess what you have
ip -6 addr show
ip -6 route show
ping6 -c3 2620:fe::fe
Three cases. If a global address (starting with 2 or 3)
is present and the ping answers, you are already set. If you only see an
fe80:: address, only link-local exists. If the address is there but
the ping fails, the default route is missing.
2. Configure the address with Netplan
Ubuntu Server uses Netplan. Files live in /etc/netplan/; the YAML is
indentation-sensitive and must use spaces.
sudo tee /etc/netplan/60-ipv6.yaml <<'EOF'
network:
version: 2
ethernets:
ens3:
dhcp4: true
accept-ra: false
addresses:
- "2602:xxxx:xxxx:1::10/64"
routes:
- to: "::/0"
via: "2602:xxxx:xxxx:1::1"
on-link: true
nameservers:
addresses: [2620:fe::fe, 2606:4700:4700::1111, 9.9.9.9]
EOF
sudo chmod 600 /etc/netplan/60-ipv6.yaml
sudo netplan try
netplan try applies the configuration and rolls it back
automatically after 120 seconds unless you confirm. On a remote machine
that is the safety net that saves you from losing access over a typo. Confirm with
Enter, then sudo netplan apply.
Static addressing or autoconfiguration? If your provider
announces the prefix through Router Advertisements, leave
accept-ra: true and drop the addresses block: the VM
configures itself. Mixing both, RA enabled and a static address, produces competing default routes and intermittent losses that are painful to
diagnose.
3. Verify connectivity
ip -6 addr show ens3
ip -6 route get 2620:fe::fe
ping6 -c3 2606:4700:4700::1111
traceroute6 -n ipv6.google.com
curl -6 -s https://ifconfig.co
curl -6 must return exactly the address you configured. A different
address means a temporary IPv6 generated by privacy extensions, fine on a laptop,
a problem on a server whose reverse DNS has to match.
# pin the outgoing source address
sudo tee /etc/sysctl.d/99-ipv6-server.conf <<'EOF'
net.ipv6.conf.all.use_tempaddr = 0
net.ipv6.conf.default.use_tempaddr = 0
EOF
sudo sysctl --system
4. Publish the AAAA record
One AAAA record is enough to make the service reachable over IPv6. Keep the same TTL as the A record to avoid asymmetric behaviour during a migration.
example.com. 300 IN A 198.51.100.42
example.com. 300 IN AAAA 2602:xxxx:xxxx:1::10
Only publish the AAAA once the service actually answers over
IPv6. A dual-stack client prefers IPv6: if the port only listens on
IPv4, the user waits for a timeout before falling back. For a web server, check
for listen [::]:443 ssl; in Nginx; for any service,
sudo ss -tulpen | grep ':::'.
5. Set up reverse DNS (PTR)
The PTR record maps an IP address back to a name. It is not managed at your registrar but by whoever holds the prefix, your hosting provider, through its console. At FFxF, reverse DNS is configurable on every address assigned to the VM.
It is essential for sending mail: most large recipients reject or spam-file a message coming from an IPv6 address with no PTR, or whose PTR does not resolve back.
dig -x 2602:xxxx:xxxx:1::10 +short
# should return: mail.example.com.
dig +short mail.example.com AAAA
# should return: 2602:xxxx:xxxx:1::10
The two lookups must agree with each other. A PTR pointing at a name with no matching AAAA is treated as no PTR at all.
6. Filter IPv6
The classic mistake: a well-tuned IPv4 firewall and nothing on IPv6. Server IPv6 addresses get scanned like any other, prefixes are public and active ranges are inferred from DNS.
grep IPV6 /etc/default/ufw # should print IPV6=yes
sudo ufw status verbose # rules should appear as (v6)
If it says IPV6=no, fix the file then run
sudo ufw disable && sudo ufw enable. Rules written afterwards
cover both families automatically.
Do not block all ICMPv6. Unlike IPv4, the protocol depends on it to function: neighbour discovery, path MTU discovery. Filtering ICMPv6 indiscriminately produces connections that establish and then stall on large transfers. UFW allows what is needed by default; leave it alone.
7. Make services listen
A configured address is useless if the daemons only listen on IPv4.
sudo ss -tulpen | grep -E ':::|\[::\]'
- Nginx: add
listen [::]:80;andlisten [::]:443 ssl;. - OpenSSH: listens on both families by default, unless
ListenAddressnarrows it. - Postfix:
inet_protocols = all. - Docker: needs
"ipv6": trueand a dedicated prefix indaemon.jsonto give containers IPv6.
Checklist
- Global address and default route present (
ip -6 route). ping6andcurl -6go out with the expected address.- AAAA published only after confirming the service listens.
- PTR configured and consistent with the AAAA.
- Firewall active on v6, ICMPv6 preserved.
- Final check on test-ipv6.com from a client, and from the server.