VPS IPv6 Configuration Guide: Enable, Configure, and Troubleshoot IPv6 on Ubuntu
IPv6 adoption crossed 40% of global internet traffic in 2024, and the share continues growing as IPv4 address space exhaustion worsens. Most VPS providers assign IPv6 addresses to every instance — but the addresses are often unconfigured, Nginx only listens on IPv4, UFW rules block IPv6 traffic, and applications bind to IPv4-only. This guide fully configures IPv6 so your VPS is reachable via both protocols.
Step 1: Verify IPv6 Assignment
# Check if your VPS has an IPv6 address
ip addr show | grep inet6 | grep -v 'link\|host'
# Example output:
# inet6 2001:db8:1234:5678::2/64 scope global dynamic
# Get just the IPv6 address
ip -6 addr show eth0 | grep 'inet6.*scope global' | awk '{print $2}'
# Test IPv6 internet connectivity
curl -6 https://ifconfig.co
ping6 google.com -c 3
If no global IPv6 address appears, check your VPS control panel — some providers require enabling IPv6 per-instance. Contact support if it’s not available.
Step 2: Configure Static IPv6 (Netplan)
# View current Netplan configuration
cat /etc/netplan/00-installer-config.yaml
# Ubuntu 22.04/24.04 uses Netplan by default
sudo nano /etc/netplan/00-installer-config.yaml
# Typical configuration with both IPv4 and IPv6:
network:
version: 2
ethernets:
eth0:
dhcp4: true # Keep IPv4 DHCP
dhcp6: false # Disable DHCPv6 if using static IPv6
addresses:
- 2001:db8:1234:5678::2/64 # Your assigned IPv6 address
routes:
- to: ::/0
via: 2001:db8:1234:5678::1 # IPv6 gateway (from your provider)
nameservers:
addresses:
- 1.1.1.1
- 2606:4700:4700::1111 # Cloudflare's IPv6 DNS
# Apply configuration
sudo netplan apply
# Verify
ip -6 route show
Step 3: Configure UFW for IPv6
# Enable IPv6 support in UFW
sudo nano /etc/default/ufw
IPV6=yes
# Reload UFW to apply IPv6 rules
sudo ufw disable
sudo ufw enable
# UFW rules now apply to both IPv4 and IPv6 automatically
sudo ufw status verbose
# Should show rules for both v4 and v6
Step 4: Configure Nginx for Dual-Stack
By default, Nginx on Ubuntu listens on IPv4 only. Add IPv6 listeners to every server block:
sudo nano /etc/nginx/sites-available/yourdomain
server {
# IPv4
listen 80;
# IPv6
listen [::]:80;
server_name yourdomain.com www.yourdomain.com;
return 301 https://$host$request_uri;
}
server {
# IPv4
listen 443 ssl http2;
# IPv6
listen [::]:443 ssl http2;
server_name yourdomain.com www.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
# ... rest of config
}
sudo nginx -t && sudo systemctl reload nginx
# Verify Nginx is listening on IPv6
sudo ss -tlnp | grep nginx
# Should show:
# *:80 (IPv4)
# [::]:80 (IPv6)
Step 5: Add DNS AAAA Records
Add AAAA records at your DNS provider to make your domain reachable via IPv6:
# Your VPS IPv6 address
ip -6 addr show eth0 | grep 'scope global' | awk '{print $2}' | cut -d'/' -f1
# Add at your DNS provider:
yourdomain.com. 3600 IN A 203.0.113.47 # IPv4
yourdomain.com. 3600 IN AAAA 2001:db8::2 # IPv6
www.yourdomain.com. 3600 IN A 203.0.113.47
www.yourdomain.com. 3600 IN AAAA 2001:db8::2
# Verify DNS propagation
dig yourdomain.com AAAA +short # Should return your IPv6 address
dig +short AAAA www.yourdomain.com
Step 6: Let’s Encrypt for IPv6 Domains
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
# Certbot verifies domain ownership — works with both IPv4 and IPv6
# If your domain has an AAAA record, Certbot may choose IPv6 for verification
Step 7: Test Full IPv6 Connectivity
# Test from your VPS — can it reach IPv6 services?
curl -6 https://google.com -I -s | head -3
# Test from external — is your site reachable via IPv6?
# Use: https://ipv6-test.com/validate.php?url=yourdomain.com
# Or use curl on a machine with IPv6:
curl -6 https://yourdomain.com -I
# Check if Nginx received IPv6 connections
sudo grep '\[' /var/log/nginx/access.log | head -5
# IPv6 connections appear with brackets: [2001:db8::1] - ...
Troubleshooting Common IPv6 Issues
Services Fail When IPv6 is Enabled
# Some services bind to 0.0.0.0 (IPv4) but not [::] (IPv6)
# Check what's listening:
sudo ss -tlnp6
# For Node.js apps — listen on both:
// app.js
app.listen(3000, '::', () => console.log('Listening on IPv4 and IPv6'));
MySQL/MariaDB — Bind to IPv6
# /etc/mysql/mariadb.conf.d/50-server.cnf
bind-address = :: # Listens on both IPv4 and IPv6 localhost
SSH on IPv6
# Test SSH connection via IPv6
ssh -6 deploy@2001:db8::2
# If SSH doesn't accept IPv6 connections:
sudo nano /etc/ssh/sshd_config
# Ensure: ListenAddress 0.0.0.0 and ListenAddress ::
sudo systemctl reload ssh
Prefer IPv4 for Outbound Connections (Troubleshooting)
# If your app has issues with IPv6 outbound, temporarily prefer IPv4:
sudo nano /etc/gai.conf
# Uncomment: precedence ::ffff:0:0/96 100
# This makes IPv4-mapped IPv6 addresses preferred
IPv6 Security Considerations
# UFW applies rules to IPv6 automatically when IPV6=yes
# Verify your deny-by-default applies to IPv6 too
sudo ufw status | grep v6
# Block ICMPv6 echo requests (optional — may break IPv6 path MTU discovery)
# Generally NOT recommended — leave ICMPv6 open for proper IPv6 operation
# sudo ip6tables -A INPUT -p icmpv6 --icmpv6-type echo-request -j DROP
# Check Fail2ban is monitoring IPv6 auth attempts
sudo fail2ban-client status sshd
# Should show both IPv4 and IPv6 in banned IPs
Getting Started
All Ubuntu VPS plans at VPS.DO support IPv6. Check the control panel for your assigned IPv6 address block — configure it in Netplan, add AAAA records at your DNS provider, and update Nginx to listen on [::]:443. IPv6 reachability improves global accessibility and future-proofs your infrastructure as IPv4 exhaustion continues.
Conclusion
Full IPv6 configuration on a VPS requires four steps: verify the IPv6 address assignment, add [::]:80 and [::]:443 listeners in Nginx, ensure UFW has IPV6=yes, and add AAAA records at your DNS provider. After these changes, your server is reachable via both IPv4 and IPv6 — serving the growing share of internet users who prefer or require IPv6 connectivity.