This guide provides a practical, step-by-step walkthrough to build an IPv6-only WireGuard VPN environment that supports both native IPv6 connectivity and access to IPv4-only services using NAT64/DNS64 translation. It targets system administrators, developers, and businesses seeking to modernize their VPN deployments for IPv6-first networks while preserving reachability to legacy IPv4 endpoints.
Why IPv6-Only with WireGuard?
IPv6 adoption removes many constraints of IPv4, but complete transition is gradual. Running an IPv6-only VPN reduces address management overhead, simplifies routing, and aligns with cloud provider networks that favor IPv6. However, many resources remain IPv4-only. Combining WireGuard with a NAT64/DNS64 gateway provides seamless access to those resources while keeping the tunnel IPv6-native end-to-end.
High-level Architecture
- WireGuard server with an IPv6 public address (or prefix delegation).
- Clients configured to use IPv6-only for the WireGuard interface.
- A NAT64 engine (e.g., Jool or Tayga) on the server to translate IPv6-to-IPv4 for IPv4-only destinations.
- DNS64 server (e.g., BIND, Unbound or systemd-resolved with DNS64 support) to synthesize AAAA records for IPv4-only hosts.
- Firewall and kernel tweaks for forwarding, MTU, and connection tracking.
Prerequisites
- Linux server with a public IPv6 address (Ubuntu/Debian/CentOS recommended).
- Root or sudo access.
- WireGuard installed (kernel module and tools).
- NAT64 software (Jool preferred for performance) and DNS64-capable resolver.
Step 1 — Install WireGuard
On Debian/Ubuntu:
sudo apt update && sudo apt install wireguard wireguard-tools
On RHEL/CentOS:
sudo yum install epel-release && sudo yum install kmod-wireguard wireguard-tools
Confirm the kernel module is present:
sudo modprobe wireguard
Step 2 — Choose an IPv6 Prefix and Plan Addresses
Decide on an internal ULA or public subnet. For example, if your server has a /64 from the ISP (e.g., 2001:db8:1:1::/64), reserve a prefix for WireGuard clients such as:
- Server WG address:
2001:db8:1:1::1/64 - Client pool:
2001:db8:1:1::100-200
Using a single /64 per WireGuard interface is typical. Clients will receive unique IPv6 addresses from that subnet.
Step 3 — Generate Keys and Configure the Server
Generate server keys:
wg genkey | tee server_private.key | wg pubkey > server_public.key
Create /etc/wireguard/wg0.conf (IPv6-only addressing):
[Interface]Address = 2001:db8:1:1::1/64
ListenPort = 51820
PrivateKey = <contents of server_private.key>
SaveConfig = true
Important: do not include any IPv4 Address= lines if you want strictly IPv6-only.
Step 4 — Configure Clients
For each client, generate keys and create a peer config. Example client config:
[Interface]PrivateKey = <client-private>
Address = 2001:db8:1:1::101/64
DNS = 2001:db8:1:1::2
Peer section pointing to server (server public IPv6):
[Peer]PublicKey = <server-public>
Endpoint = [2001:db8:fe::10]:51820
AllowedIPs = ::/0
PersistentKeepalive = 25
Note: AllowedIPs = ::/0 forces IPv6 default route via the tunnel. If you want split-tunnel, replace with specific prefixes.
Step 5 — Add Peers on the Server
On server, add each client’s public key and allowed IPs:
sudo wg set wg0 peer <client-public> allowed-ips 2001:db8:1:1::101/128
Or append to /etc/wireguard/wg0.conf:
[Peer]PublicKey = <client-public>
AllowedIPs = 2001:db8:1:1::101/128
Step 6 — Enable IPv6 Forwarding and Kernel Tweaks
Persist sysctl settings in /etc/sysctl.d/99-wg-ipv6.conf:
net.ipv6.conf.all.forwarding = 1
net.ipv6.conf.default.forwarding = 1
net.ipv6.conf.all.accept_ra = 0
net.ipv6.conf.default.accept_ra = 0
Apply immediately:
sudo sysctl --system
Setting accept_ra=0 prevents RA-based route overrides on server interfaces.
Step 7 — Set MTU and MSS Considerations
WireGuard uses the kernel TUN device. For IPv6-only with NAT64 to IPv4, be mindful of MTU. Typical WireGuard MTU is 1420 for IPv4 transport; with IPv6 transport possibly a bit lower. Set MTU on the interface or client configs:
MTU = 1420
Additionally, if you NAT to IPv4 and traverse path MTU issues, add MSS clamping in firewall rules to avoid fragmentation:
sudo ip6tables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
Step 8 — Configure Firewall / Filtering
Using nftables (recommended) or ip6tables, allow WireGuard port and enable forwarding between wg0 and upstream interface (e.g., eth0). Example nftables snippet:
table inet filter {
chain input { type filter hook input priority 0; iifname "wg0" accept; tcp dport 51820 udp dport 51820 accept; }
chain forward { type filter hook forward priority 0; iifname "wg0" oifname "eth0" accept; iifname "eth0" oifname "wg0" accept; }
}
Ensure ICMPv6 necessary types are permitted (ND, PMTU).
Step 9 — Install and Configure NAT64 (Jool)
To reach IPv4-only services, use a NAT64 engine. Jool (kernel-module) is performant. On Debian:
sudo apt install jool-dkms jool-tools
Enable the standard Well-Known Prefix (WKP) or a dedicated prefix, e.g., 64:ff9b::/96. Configure Jool:
sudo jool instance add --netfilter --pool6 64:ff9b::/96
Then add an IPv4 pool (the IPv4 addresses you will translate to):
sudo jool --instance "netfilter" pool4 add 198.51.100.0/24
Configure forwarding so that packets to IPv4-mapped addresses are sent through Jool. You will need routes so that traffic for 64:ff9b::/96 is processed locally (it is on the server by default if the client points to DNS64 synthesized AAAA).
Step 10 — Configure DNS64
DNS64 synthesizes AAAA records for IPv4-only names so clients resolve to synthetic IPv6 addresses that map to IPv4 via NAT64. Unbound is lightweight and supports DNS64. Example unbound config snippet:
server:
interface: 2001:db8:1:1::2
access-control: 0.0.0.0/0 allow
access-control: ::/0 allow
do-not-query-localhost: no
dns64_prefix: 64:ff9b::/96
Start Unbound and point client WireGuard DNS setting to the Unbound IPv6 address (e.g., 2001:db8:1:1::2).
Step 11 — Testing
- From client, verify IPv6 connectivity:
ping6 2001:4860:4860::8888(Google DNS v6). - Test IPv4-only reachability via DNS64+NAT64: resolve an IPv4-only host (e.g., example.com) and verify it returns a synthesized AAAA within the chosen prefix:
dig AAAA example.com. - Confirm that pinging the synthesized IPv6 address results in translation to IPv4 on server (check Jool stats):
sudo jool --instance "netfilter" counters.
Step 12 — Observability and Logging
Monitor WireGuard with:
sudo wg show
Monitor Jool and Unbound logs for translation and DNS synthesis issues. Use tcpdump on server to trace packet flows:
sudo tcpdump -i wg0 ip6 and host 64:ff9b::
Edge Cases and Advanced Considerations
- IPv6 Prefix Delegation: For multi-site or client PD, integrate DHCPv6-PD to hand out subprefixes to remote gateways.
- Split DNS: For internal names, ensure your DNS64 server does not synthesize AAAA for names that already have IPv6 records (Unbound handles that naturally).
- CGNAT and Shared IPv4 Pools: If your NAT64 pool uses shared IPv4 addresses, be cautious with port exhaustion; consider allocating a dedicated IPv4 range for high-volume clients.
- Performance: Jool in kernel mode provides high throughput; Tayga (userland) is simpler but may be CPU-bound on busy servers.
- Security: Use WireGuard peer keys, enforce minimal AllowedIPs, rotate keys periodically, and keep NAT64/DNS64 services restricted to VPN clients only.
Rollback and Troubleshooting
- If clients cannot resolve names: verify DNS64 is listening on the configured IPv6 address and that clients use that address as DNS.
- If IPv4-only endpoints fail: confirm Jool/Tayga is running and the NAT64 prefix matches the DNS64 prefix.
- For MTU issues: lower MTU on client and server WireGuard interfaces and enable MSS clamping.
- Check sysctl
net.ipv6.conf.*.forwardingand ensure forwarding is enabled.
Deploying an IPv6-only WireGuard setup with NAT64/DNS64 combines the benefits of modern IPv6 networking with continued access to legacy IPv4-only services. The architecture described here is production-ready with careful attention to firewalling, MTU tuning, and DNS/NAT64 coordination.
For further resources, operational tips, and custom deployment assistance, visit Dedicated-IP-VPN at https://dedicated-ip-vpn.com/.