IPv6 on a VPS: A Checklist That Gets You Online on the First Try

Your provider handed you an IPv6 address the day you ordered the VPS, and you probably ignored it. Then the first time you actually need it — an IPv6-only client, a second IP for mail, or a route around a broken IPv4 peering — you spend an afternoon fighting Network is unreachable. This is the checklist that gets IPv6 working on a Linux VPS on the first try, plus the three failure modes that break most setups.

Step 1: Write down what your provider actually assigned

Open your provider’s control panel and note the exact IPv6 address, the prefix length, and the gateway. The three common patterns on cloud VPSes are:

  • A single /64 routed to you — the gateway is your provider’s router, usually a link-local address like fe80::1 on the same interface.
  • A static address + gateway pair — the gateway is a global address in the same /64 or a nearby prefix.
  • SLAAC/DHCPv6 — more common on dedicated servers than on cloud VPSes; check whether your image supports it.

Some providers don’t enable IPv6 by default at all. If the panel shows no address, check the docs — it may be one toggle in the network settings, and it usually requires a reboot or a reconfig to appear on the interface.

Step 2: Make sure the guest hasn’t disabled IPv6

A surprising number of cloud images ship with IPv6 disabled in sysctl, often via a file in /etc/sysctl.d/. Check before you configure anything:

sysctl net.ipv6.conf.all.disable_ipv6 net.ipv6.conf.default.disable_ipv6
# expected: net.ipv6.conf.all.disable_ipv6 = 0
#           net.ipv6.conf.default.disable_ipv6 = 0

If either prints 1, find the offending file (usually /etc/sysctl.d/99-disable-ipv6.conf), delete or edit it, then apply:

sudo sysctl -p
ip -6 addr show

Step 3: Configure the interface

On Ubuntu (netplan), a typical static IPv6 block looks like this:

network:
  version: 2
  ethernets:
    eth0:
      dhcp4: true
      addresses:
        - 2001:db8:1000::2/64
      routes:
        - to: default
          via: fe80::1
          scope: link

Then apply and verify:

sudo netplan apply
ip -6 addr show eth0
ip -6 route show default

On Debian-style systems using /etc/network/interfaces, the equivalent is:

iface eth0 inet6 static
    address 2001:db8:1000::2/64
    gateway fe80::1

The gateway being link-local (fe80::1) is the most common source of confusion — on most clouds the IPv6 default route goes through a link-local next hop, and netplan needs scope: link for that to work.

Step 4: Test from the box

ping -6 2001:4860:4860::8888        # Google DNS over IPv6
curl -6 -s https://ifconfig.co       # shows your IPv6 address if the route works

If ping works but curl fails, the problem is DNS (no AAAA record yet) or outbound traffic filtering. If even ping fails, go to the failure table below.

The three failure modes that break 80% of setups

FailureSymptomFix
No default routeNetwork is unreachable on any ping -6Add the route via the link-local gateway as in Step 3
Firewall drops ICMPv6Address assigned but nothing responds; neighbors never resolveAllow the ICMPv6 types below in ufw/nftables
Services bound to IPv4 onlycurl -6 works but port 80/22 don’t answerSet ListenAddress :: in sshd, listen [::]:80 in nginx

The firewall one is the sneakiest: IPv6 neighbor discovery relies on ICMPv6, and a drop-all firewall without ICMPv6 exceptions will silently break IPv6 even though the address looks configured. An nftables rule set that accepts the required types:

table inet filter {
  chain input {
    type filter hook input priority filter; policy drop;
    icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, echo-request, nd-neighbor-solicit, nd-neighbor-advert, nd-router-solicit, nd-router-advert } accept
  }
}

With ufw, sudo ufw allow to ::/0 proto icmpv6 covers the same ground, and recent ufw versions already include sane ICMPv6 defaults. For sshd, make sure it listens on IPv6 too:

# /etc/ssh/sshd_config
ListenAddress ::

Step 5: Add the AAAA record

IPv6 on the server is only half the job. Add an AAAA record for your hostname pointing at the new address, then verify resolution from outside:

dig AAAA +short example.com @1.1.1.1
# should print your IPv6 address once DNS has propagated

A free external check like test-ipv6.com will confirm both the server and the DNS side in one pass.

When it still doesn’t work

If the address is configured, the route is up, and the firewall is open but nothing responds, the problem is upstream: some providers don’t route the prefix they assign until you open a ticket, and a few charge extra for usable IPv6. Before you buy anything, check what the provider actually includes — native IPv6 support is one of the details we track in our VPS comparison table.

Enable IPv6 once, keep it on, and verify it quarterly. Even if your users are all IPv4 today, mail deliverability, API clients, and an increasing share of mobile networks already prefer the v6 path — and having it working costs you nothing.

Leave a Reply