Configure IPv6 on Linux VPS — Complete Setup Guide
The global IPv4 address pool is exhausted. Most VPS providers now allocate an IPv6 subnet alongside your server, but Linux doesn't always enable or configure it automatically. This guide walks you through the complete process of setting up IPv6 on a Linux VPS — covering both SLAAC and static assignment, firewall rules, DNS AAAA records, and connectivity testing.
Why Enable IPv6?
IPv4 provides only 4.3 billion addresses — already exhausted. IPv6 provides 3.4 × 10³⁸ addresses. Additional benefits include:
- No NAT — every host gets a real public address
- Faster routing due to simplified headers
- Built-in IPsec support
- Stateless autoconfiguration (SLAAC) — no DHCP server needed
- Better CDN and crawler coverage for dual-stack origins
Check Your Provider's IPv6 Allocation
Before configuring, verify your VPS has been assigned an IPv6 address — check your provider's control panel or run:
# Show all network interfaces
ip addr show
# Show only IPv6
ip -6 addr show
# Show IPv6 routing table
ip -6 route show
If you see an address starting with 2xxx: or 3xxx:, your interface already has a global IPv6 address. If you only see fe80:: (link-local), no global IPv6 has been assigned.
Method 1 — SLAAC (Stateless Address Autoconfiguration)
SLAAC is the simplest approach — ideal when your provider sends Router Advertisements. The OS generates an IPv6 address automatically from the advertised prefix.
Ubuntu / Debian — Netplan
# Find your interface name
ip link show
# Edit Netplan config
nano /etc/netplan/00-installer-config.yaml
network:
version: 2
ethernets:
eth0:
dhcp4: true
dhcp6: true # enable SLAAC / DHCPv6
accept-ra: true # accept Router Advertisements
# Apply configuration
netplan apply
# Verify
ip -6 addr show eth0
CentOS / Rocky / AlmaLinux — NetworkManager
nmcli con show
nmcli con mod eth0 ipv6.method auto
nmcli con up eth0
# Verify
nmcli -p con show eth0 | grep IPv6
Method 2 — Static IPv6 Address
Use static assignment for servers that need a stable IP — mail servers, DNS servers, or any host you add AAAA records for.
Ubuntu / Debian — Netplan (static)
nano /etc/netplan/00-installer-config.yaml
network:
version: 2
ethernets:
eth0:
dhcp4: true
addresses:
- 2a01:4f8:c2c:1234::1/64 # replace with your provider's IPv6
routes:
- to: ::/0
via: 2a01:4f8:c2c:1234::1 # your IPv6 gateway
nameservers:
addresses:
- 2606:4700:4700::1111 # Cloudflare IPv6 DNS
- 2001:4860:4860::8888 # Google IPv6 DNS
netplan apply
CentOS / Rocky — nmcli (static)
nmcli con mod eth0 \
ipv6.method manual \
ipv6.addresses "2a01:4f8:c2c:1234::1/64" \
ipv6.gateway "fe80::1" \
ipv6.dns "2606:4700:4700::1111,2001:4860:4860::8888"
nmcli con up eth0
Kernel Configuration — Enable IPv6 if Disabled
Some providers disable IPv6 at the kernel level. Check and enable it:
# Check if IPv6 is disabled
sysctl net.ipv6.conf.all.disable_ipv6
# 1 = disabled
# Enable IPv6 for all interfaces
sysctl -w net.ipv6.conf.all.disable_ipv6=0
sysctl -w net.ipv6.conf.default.disable_ipv6=0
# Make persistent across reboots
echo "net.ipv6.conf.all.disable_ipv6 = 0" >> /etc/sysctl.d/99-ipv6.conf
echo "net.ipv6.conf.default.disable_ipv6 = 0" >> /etc/sysctl.d/99-ipv6.conf
sysctl --system
net.ipv6.conf.all.forwarding = 1 only if your VPS acts as an IPv6 router or gateway for containers.Firewall Rules for IPv6
iptables only handles IPv4. IPv6 traffic is controlled by ip6tables — they must be configured separately.
UFW (recommended for Ubuntu/Debian)
# Ensure UFW has IPv6 enabled
grep "IPV6" /etc/default/ufw
# Should show: IPV6=yes
# Allow common ports (applies to both IPv4 and IPv6)
ufw allow 22/tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable
# View IPv6 rules
ufw status verbose
ip6tables (manual)
# Flush existing rules
ip6tables -F
ip6tables -X
# Allow loopback and established connections
ip6tables -A INPUT -i lo -j ACCEPT
ip6tables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# Allow ICMPv6 (required for neighbor discovery)
ip6tables -A INPUT -p ipv6-icmp -j ACCEPT
# Allow SSH, HTTP, HTTPS
ip6tables -A INPUT -p tcp --dport 22 -j ACCEPT
ip6tables -A INPUT -p tcp --dport 80 -j ACCEPT
ip6tables -A INPUT -p tcp --dport 443 -j ACCEPT
# Drop everything else
ip6tables -A INPUT -j DROP
# Save rules
apt install iptables-persistent -y
netfilter-persistent save
Configure DNS AAAA Records
Once your VPS has IPv6, add AAAA records in your domain's DNS:
| Record Type | Name | Value |
|---|---|---|
| AAAA | @ | 2a01:4f8:c2c:1234::1 |
| AAAA | www | 2a01:4f8:c2c:1234::1 |
| AAAA | 2a01:4f8:c2c:1234::1 |
For reverse DNS (PTR records), configure rDNS through your provider's control panel — point your IPv6 address to your server's hostname.
Configure Nginx to Listen on IPv6
server {
# Accept both IPv4 and IPv6
listen 80;
listen [::]:80;
listen 443 ssl;
listen [::]:443 ssl;
server_name example.com www.example.com;
# ...
}
With the default Linux setting net.ipv6.bindv6only = 0, a dual-stack [::]:80 socket also accepts IPv4 connections — no need for a separate listen 80 directive.
Verify IPv6 is Working Correctly
# Ping Google's IPv6 DNS
ping6 2001:4860:4860::8888 -c 4
# Test HTTP request over IPv6
curl -6 -I https://ipv6.google.com
# Show active global IPv6 addresses
ip -6 addr show scope global
# Check routing table
ip -6 route show
tracepath6 2001:4860:4860::8888
# Test DNS resolution over IPv6
dig AAAA google.com @2606:4700:4700::1111
Troubleshooting Common Issues
Error: "Network is unreachable" when running ping6
This means the interface has no global IPv6 address or the default IPv6 route is missing.
# Check for a default route
ip -6 route show | grep default
# Add a temporary default route (replace with your actual gateway)
ip -6 route add default via 2a01:4f8:c2c:1234::1 dev eth0
# If your provider uses a link-local gateway
ip -6 route add default via fe80::1 dev eth0
Error: "connect: Cannot assign requested address" with curl -6
IPv6 is disabled at the kernel level. Check and enable it:
cat /proc/sys/net/ipv6/conf/all/disable_ipv6
# If 1, run:
sysctl -w net.ipv6.conf.all.disable_ipv6=0
Error: "Address already in use" when Nginx won't start after adding [::]:443
Occurs when net.ipv6.bindv6only=1 and the port is already held by an IPv4 socket.
# Check current value
sysctl net.ipv6.bindv6only
# Set to 0 to allow dual-stack sockets
sysctl -w net.ipv6.bindv6only=0
echo "net.ipv6.bindv6only = 0" >> /etc/sysctl.d/99-ipv6.conf
Error: ICMPv6 "Destination Unreachable" — neighbor solicitation not answered
Firewall is blocking all ICMPv6. Open the Neighbor Discovery message types:
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type 133 -j ACCEPT
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type 134 -j ACCEPT
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type 135 -j ACCEPT
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type 136 -j ACCEPT
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type 137 -j ACCEPT
IPv6 address disappears after reboot
The address was set temporarily, not persisted in a config file.
# Ubuntu/Debian — verify Netplan config
cat /etc/netplan/00-installer-config.yaml
# CentOS/Rocky — verify NetworkManager connection
cat /etc/NetworkManager/system-connections/eth0.nmconnection | grep ipv6
Frequently Asked Questions
Does my VPS have IPv6?
Check your provider's control panel — most providers show the allocated IPv6 subnet there. Alternatively, run ip -6 addr show and look for an address starting with 2 or 3 (global unicast). If you only see fe80:: (link-local), IPv6 hasn't been provisioned on your server yet.
Do I need IPv6 if my website only uses IPv4?
It's recommended even for IPv4-only sites. Googlebot supports IPv6 and may crawl your site over it. Some ISPs provide IPv6-only connectivity to end users. Cloudflare also favors dual-stack origins when routing traffic. Enabling IPv6 has no downside and improves reach and future-proofing.
What's the difference between SLAAC and DHCPv6?
SLAAC (Stateless Address Autoconfiguration) lets the host generate its own address from a router-advertised prefix — no DHCP server needed. DHCPv6 works like IPv4 DHCP — a server explicitly assigns an address. Most VPS providers use SLAAC or static assignment; check your provider's documentation to see which applies to your plan.