Getting OpenVPN to work with OpenVZ

This is a short howto which shows how OpenVPN can be persuaded to work within an OpenVZ instance. The problem with the default configuration file supplied by IPredator is that the route setup of OpenVPN and thus the connection will fail.

Dependencies

Basics are not covered here. You need to have the following dependencies already installed or prepared:

System setup

  • CentOS or Debian as a host system with the tun kernel module loaded
  • OpenVZ host installation
  • An OpenVZ template — Debian is used in this howto

Configuration files

Preparations

We start with the assumption that you have a host running on which the tun module is loaded into the kernel. There also is a container prepared in which you want to establish an OpenVPN connection. The container in the howto uses CID 101.

First make sure that the container is shutdown. Then execute the first batch of commands make sure to adjust the CID to your setup. Grant container 101 access to the tun device and adjust the capability settings accordingly.

# vzctl stop 101
# vzctl set 101 --devnodes net/tun:rw --save
# vzctl set 101 --devices c:10:200:rw --save
# vzctl set 101 --capability net_admin:on --save

Start the container again. Then create the required devices inside the container so that OpenVPN has a something to work with. Make sure to adjust the permissions properly.

# vzctl start 101
# vzctl exec 101 mkdir -p /dev/net
# vzctl exec 101 chmod 600 /dev/net/tun

Now OpenVPN can be installed inside the container along with resolvconf which is needed to run the DNS update script that was provided by Debian.

# apt-get install openvpn resolvconf

Installation

Place the configuration file and the shell scripts into /etc/openvpn. Open the configuration in your favorite editor and append the following lines:

/etc/openvpn/IPredator-CLI-Password.conf

# additions for OpenVZ
script-security 2
route-noexec
route-up /etc/openvpn/openvz-route-up.sh
up /etc/openvpn/update-resolv-conf
down /etc/openvpn/openvz-down.sh

Those additions change the configuration as follows:

  • The line starting with script-security allows OpenVPN to execute external scripts.
  • To work around the issue that OpenVPN quits because it cannot deal with the default route that an OpenVZ container has set, OpenVPN is instructed to ignore any routes pushed to the client with route-noexec.
  • Since routing gets set up manually, appropriate script handlers need to be registered and some glue scripts are provided. All routes are installed on the route-up event. To make sure that the initial routing table gets restored when OpenVPN goes down with the openvz-down script.

Add your username and password to the IPredator.auth file. Finally place the shell scripts into the /etc/openvpn and make them executable with chmod 750.

# chmod 750 /etc/openvpn/openvz-route-up.sh
# chmod 750 /etc/openvpn/openvz-down.sh

To get the DNS setup working properly a few tweaks to the system need to be made:

  • First a backup of the local default DNS config is created as /etc/resolv.conf.local.
  • Then we need to add a safeguard to /etc/rc.local to ensure that if the OpenVZ container is not shutdown properly it will boot with a usable resolv.conf again.

The openvz-down.sh script relies on the /etc/resolv.conf.local to make sure that the next time it tries to start the OpenVPN instance the system has a properly configured DNS.

# cp /etc/resolv.conf /etc/resolv.conf.local
# vim /etc/rc.local
...
add "cp /etc/resolv.conf.local /etc/resolv.conf" before the line exit 0
...

/etc/openvpn/openvz-route-up.sh

#!/bin/sh -x
#
# NOTES:
#   - script assumes that we have venet0
#   - and that there is only one route which is default via venet0
#   - The script silently accepts any faults ... eg if you have a different
#     set of routes so make sure all is fine by running OpenVPN in the
#     foreground and enable DEBUG=1

DEBUG=0

debug() { 
  if [ $DEBUG != 0 ]; then 
    echo "DEBUG: $1" 
  fi 
} 

debug "local device: $dev" 
debug "VPN server IP: $trusted_ip" 
debug "route_vpn_gateway $route_vpn_gateway" 

ip route delete default
ip route add $trusted_ip dev venet0
ip route add default via $route_vpn_gateway dev $dev

/etc/openvpn/openvz-down.sh

#!/bin/sh

# Clear all routes
ip route flush all

# Restore defaults
ip route add default dev venet0

# Restore our local copy ... resolvconf cannot be trusted to restore it properly
# without fiddling around with its config
cp /etc/resolv.conf.local /etc/resolv.conf

Test run

Now its time to test the connection. To do that please run:

# openvpn --config /etc/openvpn/IPredator-CLI-Password.conf

If everything works to your satisfaction restart the container to make sure OpenVPN comes up properly. Also make sure that once the OpenVPN is running that you have a proper DNS config in /etc/resolv.conf, which should then contain the IPredator DNS servers.