I wrote this article for people who want to have a VPN that supports IPv6, because IPv6 is cool, no?

All the outbound traffic will be redirected through the VPN thus faking true location: vpn.png When you visit a website, the source IP address will be the public address of the VPN for IPv4 or IPv6 prefix, not client one.

Here is my current configuration and address space:

  • OpenVPN server: Debian Jessie with openvpn 2.3.4-5.
  • TLS authentication (no user/password check).
  • OpenVPN clients: Android 5.1.1 with OpenVPN for Android 0.6.46 and Ubuntu 15.10 with openvpn 2.3.7.
  • One IPv4, all outbound traffic will be nat'ed.
  • A ::/64 IPv6 block.
  • sudo on the server.
  • Time and patience.

TLS and local certificate authority

I use SSL certificate issued from a local certificate authority. This article will not treat this part. However, for my needs, I use XCA, a graphical front-end for managing keys and certificates. At the end of this step, you must have:

  • A CA certificate generated from XCA (cacert.pem).
  • A key/cert pair for the OpenVPN server generated from XCA (vpn.key and vpn.crt).
  • A PKCS12 for the end user generated from XCA. This one is password protected.

Server installation

The server I use is a low-cost virtual private server (VPS) with 1vCPU and 768M of memory. This is enough for running a VPN server. On the server, the first step is to install openvpn package. On debian, this is done by executing the command:

sudo apt-get install openvpn

I could give you the OpenVPN server configuration, but this is not enough. To allow your VPN to pass IPv6 address to clients, you have to configure some sysctl entries. Look at /etc/sysctl.conf to modify or add those entries:


For the last one, you must change the interface name (here eth0) to the interface that holds the IPv6 address.

  • net.ipv4.ip_forward permits forwarding IPv4 packets from one interface to another. Your server will act as router.
  • net.ipv6.conf.all.forwarding permits forwarding IPv6 packets
  • net.ipv6.conf.eth0.proxy_ndp to proxify network discovery protocol to your client through VPN tunnel.

The last one will permit the transfer of NDP packets from eth0 to specified neighbor. Each neighbor must be added to the neighbor list with the command:

ip neigh add proxy _ipv6-address_ dev _tunnel-interface_

Do not be afraid, this is done later in a script!


So, here my current (working) configuration:

# /etc/openvpn/clients.conf
port 1194
proto udp
dev tun

ca /etc/pki/CA/cacert.pem
cert /etc/pki/CA/vpn.crt
key /etc/pki/CA/private/vpn.key
dh /etc/pki/CA/dh1024.pem
mode server

### IPv4
topology "subnet"
push "topology subnet"
push "route-gateway"
push "redirect-gateway def1 bypass-dhcp" # push all ipv4 traffic
push "dhcp-option DNS"

### IPv6
push tun-ipv6
ifconfig-ipv6 2001:9999:5000:8914::1 fe80::fc00:ff:fe0c:7299
ifconfig-ipv6-pool 2001:9999:5000:8914::2/112
push "route-ipv6 2001:9999:5000:8914::/64 2001:9999:5000:8914::1"
push "route-ipv6 2000::/3" # push all ipv6 traffic

keepalive 10 120
user vpn
group vpn
status /var/lib/openvpn/openvpn-status.log
verb 3

learn-address "/usr/bin/sudo -u root /etc/openvpn/learn-address"

IPv6 address and routing

Look at this part:

ifconfig-ipv6 2001:9999:5000:8914::1 fe80::fc00:ff:fe0c:7299
ifconfig-ipv6-pool 2001:9999:5000:8914::2/112
push "route-ipv6 2001:9999:5000:8914::/64 2001:9999:5000:8914::1"
push "route-ipv6 2000::/3" # push all ipv6 traffic

The first 3 entries must be modified according your IPv6 prefix.

  • 2001:9999:5000:8914::1 is the tunnel address on the server side, this will created once OpenVpn daemon will start, do not bother.
  • fe80::fc00:ff:fe0c:7299 is the default gateway seen from my server, you can get it with the command:
user@vps$ ip -6 route show default
default via fe80::fc00:ff:fe0c:7299 dev eth0  proto ra  metric 1024  expires 1409sec hoplimit 64
  • Your configuration must be changed with the address given by the last command.
  • ifconfig-ipv6-pool 2001:9999:5000:8914::2/112 is the range of addresses for your clients

Auto neighbor add

When a client connects to the VPN, a new neighbor is created. The VPN must be informed to proxify NDP to your client. This is done with the script under "learn-address" parameter:

learn-address "/usr/bin/sudo -u root /etc/openvpn/learn-address"

And here the script:

# /etc/openvpn/learn-address

echo $addr | grep -q ':'
if [ $? -ne 0 ]; then
  exit 0

case "$action" in
        ip neigh replace proxy "$addr" dev $ext_interface
        ip -6 route del "$addr" dev $tun_interface
        ip -6 route add "$addr" dev $tun_interface
        ip neigh del proxy "$addr" dev $ext_interface

This script will be executed by openvpn every time a client connects. As you can see, it uses sudo as root privilege is needed for this. Here the sudoers:

vpn ALL=NOPASSWD: /etc/openvpn/learn-address

Finally, openvpn is executed as vpn user, do not forger to create it as a system user:

useradd vpn

Client configuration

The clients needs a PKCS12, refer to XCA to export one. Here is the configuration:

# vpn.cfg
comp-lzo yes
remote your.vpn-address.com 1194 # change this parameter with the fqdn/address of your VPN
dev tun
proto udp
resolv-retry infinite
user nobody
group nogroup
pkcs12 pkcs12-file # you will have to set this accordingly
ns-cert-type server
verb 3
script-security 2
up /etc/openvpn/update-resolv-conf
down /etc/openvpn/update-resolv-conf

In this example, change:

  • remote: the address (ipv4) if your VPN Gateway, public address.
  • pkcs12: the filename containing the user's PKCS12

And to bring-up the VPN, here is the command:

sudo openvpn vpn.cfg

You will be asked for your user's password and then the PKCS12 password.