OpenVPN

Install OpenVPN

sudo aptitude install openvpn
# open port 1194 (as shown here for the ufw firewall interface):
sudo ufw allow 1194

Become an Certificate Authority

Alternative to this way: Use TinyCA (there are Ubuntu packages available).

sudo mkdir /etc/openvpn/easy-rsa/
sudo cp -R /usr/share/doc/openvpn/examples/easy-rsa/2.0/* /etc/openvpn/easy-rsa/
sudo chown -R $USER /etc/openvpn/easy-rsa/
cat << EOF | sudo tee -a /etc/openvpn/easy-rsa/vars >/dev/null
export KEY_COUNTRY="DE"
export KEY_PROVINCE="Hesse"
export KEY_CITY="Frankfurt"
export KEY_ORG="Your Organization"
export KEY_EMAIL="contact@example.org"
EOF

create the server certificates:

cd /etc/openvpn/easy-rsa/
source vars
./clean-all
./build-dh
./pkitool --initca
./pkitool --server server
cd keys
openvpn --genkey --secret ta.key
sudo cp server.crt server.key ca.crt dh1024.pem ta.key /etc/openvpn/

After making changes to the configuration restart the server:

sudo /etc/init.d/openvpn restart

For each client: Create a client certificate

Replace hostname with the actual hostname of the machine connecting to the VPN:

cd /etc/openvpn/easy-rsa/
source vars
./pkitool hostname

And copy the following files to the client:

  • /etc/openvpn/ca.crt
  • /etc/openvpn/ta.key
  • /etc/openvpn/easy-rsa/keys/hostname.crt
  • /etc/openvpn/easy-rsa/keys/hostname.key

For an easier transfer you can bundle the 4 files into a .tar.bz2 file like this:

sudo -i # or just su (on Debian)
HOSTNAME="hostname"
cd /etc/openvpn/easy-rsa/keys
tar cjf bundle.tar.bz2 ../../ca.crt ../../ta.key $HOSTNAME.crt $HOSTNAME.key

All of this can be automated and made comfortable with the following helper bash script: https://gist.github.com/952469#file_create_keys_for_client.sh.

Revoke a client certificate

http://people.mandriva.com/~ybourhis/openvpn/index.html
http://openvpn.net/howto.html#revoke

Since an OpenVPN server’s only means of authentication is to check whether the certificate presented by a client is signed by the "right" CA, the only way to revoke VPN access is to revoke the certificate. This is also done on the CA system by calling

/etc/openvpn/easy-rsa/revoke-full <client-name>
ln /etc/openvpn/easy-rsa/keys/crl.pem /etc/openvpn/

This creates a crl.pem file which contains a list of all revoked certificates and a hardlink in /etc/openvpn. Then add the directive crl-verify crl.pem to your server.conf.

Set up a bridged VPN

Set up a bridged VPN using the tap0 device (as described in the Ubuntu Server Guide on OpenVPN).

Set up The Bridge

Install the package bridge-utils (containing mainly the binary brctl):

sudo apt-get install bridge-utils

(When doing this on a virtual server you might need to install udev too: # apt-get install udev)

And now make your /etc/network/interfaces look like this:

auto lo
iface lo inet loopback

auto br0
iface br0 inet static
        address ww.xx.yy.zz
        network ww.xx.yy.0
        netmask 255.255.255.0
        broadcast ww.xx.yy.255
        gateway ww.xx.yy.1
        bridge_ports eth0
        bridge_fd 9
        bridge_hello 2
        bridge_maxage 12
        bridge_stp off

Restart networking to enable the bridge interface:

sudo /etc/init.d/networking restart

server configuration

sudo cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz /etc/openvpn/
sudo gzip -d /etc/openvpn/server.conf.gz

Now you have a server configuration file /etc/openvpn/server.conf (from the example file). Adjust it to:

local 192.168.1.2
dev tap0
up "/etc/openvpn/up.sh br0"
down "/etc/openvpn/down.sh br0"
;server 10.8.0.0 255.255.255.0
; the server's IP and subnet and the range of IP addresses the server may assign to connecting clients:
server-bridge ww.xx.yy.zz 255.255.255.0 ww.xx.yy.zz+1 ww.xx.yy.255-1
push "route ww.xx.yy.1 255.255.255.0"
push "dhcp-option DNS 208.67.222.222"
push "dhcp-option DOMAIN example.com"
tls-auth ta.key 0 # This file is secret
user nobody
group nogroup

Now set up the tap0 helper files.

First the interface up script: sudo vim /etc/openvpn/up.sh

#!/bin/sh

BR=$1
DEV=$2
MTU=$3
/sbin/ifconfig $DEV mtu $MTU promisc up
/usr/sbin/brctl addif $BR $DEV

And now the interface down script: sudo vim /etc/openvpn/down.sh

#!/bin/sh

BR=$1
DEV=$2

/usr/sbin/brctl delif $BR $DEV
/sbin/ifconfig $DEV down

Make them executable for root:

sudo chmod 755 /etc/openvpn/down.sh
sudo chmod 755 /etc/openvpn/up.sh

using tun device as described in ubuntuusers.de Wiki

permalink: http://wiki.ubuntuusers.de/OpenVPN?rev=182021

server configuration

port 1194
proto udp
dev tun
ca ca.crt
cert server.crt
key server.key  # This file should be kept secret
dh dh1024.pem
server 10.8.0.0 255.255.255.0
ifconfig-pool-persist ipp.txt
;push "redirect-gateway def1 bypass-dhcp"
;push "dhcp-option DNS 208.67.222.222"
;push "dhcp-option DNS 208.67.220.220"
;client-to-client
keepalive 10 120
tls-auth ta.key 0 # This file is secret
comp-lzo
persist-key
persist-tun
status openvpn.status
verb 3
nice tweak: redirect all traffic through the VPN tunnel

diff for /etc/openvpn/server.conf:

--- a/openvpn/server.conf
+++ b/openvpn/server.conf
 ;push "redirect-gateway def1 bypass-dhcp"
+push "redirect-gateway def1"
+push "route-gateway 10.8.0.1"

restart openvpn:

sudo /etc/init.d/openvpn restart

Allow NAT when using ufw as firewall (as described on http://www.nowhere.dk/articles/tip_nat_with_ubuntus_ufw_firewall):

In the file /etc/default/ufw set the parameter DEFAULT_FORWARD_POLICY to ACCEPT

DEFAULT_FORWARD_POLICY="ACCEPT"

In /etc/ufw/sysctl.conf uncomment

net.ipv4.ip_forward=1

Right at the beginning of /etc/ufw/before.rules (after the introductory comments) add this whole code block:

# nat Table rules
*nat
:POSTROUTING ACCEPT [0:0]

# Forward traffic through ppp0 - Change to match you out-interface
-A POSTROUTING -s 10.8.0.0/24 -o eth2 -j MASQUERADE

# don't delete the 'COMMIT' line or these nat table rules won't be processed
COMMIT

where 10.8.0.0/24 is the IP block from your VPN and eth2 is the network interface you want NAT to redirect requests to.

Restart the firewall:

sudo ufw disable && sudo ufw enable

On the clients you need to set the DNS server (to 208.67.222.222 for example). This can be done using scripts or using the setup of network-manager-openvpn.

If you suspect the NAT might not work, watch out for error messages on the server using

tailf /var/log/messages

client configuration

client
dev tun

;proto tcp
proto udp

remote your.openvpn.server.com 1194
;remote my-server-2 1194
;remote-random

resolv-retry infinite

nobind

;user nobody
;group nogroup

persist-key
persist-tun

;http-proxy-retry # retry on connection failures
;http-proxy [proxy server] [proxy port #]

;mute-replay-warnings

ca ca.crt
cert penryn.crt
key penryn.key

ns-cert-type server

tls-auth ta.key 1

;cipher x

comp-lzo

verb 3

;mute 20
set up the client using network-manager-openvpn

install network-manager-openvpn

Set up a new VPN configuration: OpenVPN. Set up the gateway to your OpenVPN server, The user certificate, ca certificate and private key have to be given (user.crt, ca.crt and user.key) and then change advanced params: LZO-compression, TCP; TLS-AUTH: ta.key and direction 1.

On the IPv4 settings set up the DNS Server to 208.67.222.222. Done.

Test the configuration

Try to connect and if it connected successfully, you can test the configuration like this:

ping 10.8.0.1

or if you run a webserver on the remote server you can check http://10.8.0.1 . If you run a network logger like wireshark, then listen on your physical connection and you will only see scrambled data in the packages.

speed

using netcat speedtest: speed over vpn connection: (4 754 432 bytes) / (16.64500 seconds) = 2.18 Mbps uncencrypted direct connection: (146 632 704 bytes) / (25.77 seconds) = 43.4 Mbps

using iperf speedtest:

iperf -s -p 2222
------------------------------------------------------------
Server listening on TCP port 2222
TCP window size: 85.3 KByte (default)
------------------------------------------------------------
[  4] local 10.8.0.1 port 2222 connected with 10.8.0.6 port 50052
[ ID] Interval       Transfer     Bandwidth
[  4]  0.0- 6.1 sec  1.70 MBytes  2.33 Mbits/sec
[  5] local 192.168.1.20 port 2222 connected with 192.168.1.22 port 50055
[  5]  0.0- 5.1 sec  32.4 MBytes  53.4 Mbits/sec

⚡ there is a problem here!

when I change the VPN to proto tcp on both sides then the result looks different: uncencrypted direct connection: (46 382 080 bytes) / (8.11 seconds) = 43.6 Mbps speed over vpn connection: (152 698 880 bytes) / (8.76100 seconds) = 132.975688 Mbps

philipp@lion:~$ iperf -s -p 2222
------------------------------------------------------------
Server listening on TCP port 2222
TCP window size: 85.3 KByte (default)
------------------------------------------------------------
[  4] local 10.8.0.1 port 2222 connected with 10.8.0.6 port 50080
[ ID] Interval       Transfer     Bandwidth
[  4]  0.0-10.0 sec    179 MBytes    151 Mbits/sec
[  5] local 192.168.1.20 port 2222 connected with 192.168.1.22 port 50079
[  5]  0.0-10.0 sec  62.9 MBytes  52.7 Mbits/sec

now the vpn based connection (10.8.0.1) looks much faster!

It is even faster than the physical network connection. This can only be due to the zlib compression...

newer configuration

server

status openvpn.status
port 1194
proto tcp
dev tun
ca ca.crt
cert server.crt
key server.key  # This file should be kept secret
dh dh1024.pem
server 10.8.0.0 255.255.255.0
ifconfig-pool-persist ipp.txt
push "redirect-gateway def1"
push "dhcp-option DNS 208.67.222.222"
client-to-client
keepalive 10 120
tls-auth ta.key 0 # This file is secret
comp-lzo
persist-key
persist-tun
verb 3

client

client
dev tun
auth-nocache
proto tcp-client
remote your.openvpn.server.com 1194
resolv-retry infinite
nobind
persist-key
persist-tun
ca ca.crt
cert philipp-ubuntu-virt.crt
key philipp-ubuntu-virt.key
ns-cert-type server
tls-auth ta.key 1
comp-lzo
verb 3
; now also set the dns entry:
script-security 2
up ./up.sh

where ./up.sh is

#!/bin/sh
# <http://openvpn.net/archive/openvpn-users/2006-10/msg00217.html>
# script to automatically set DNS information on connection

mv /etc/resolv.conf /etc/resolv.conf.hold # back up old file

for OPTION in "${foreign_option_1}" "${foreign_option_2}" "${foreign_option_3}" "${foreign_option_4}" "${foreign_option_5}" "${foreign_option_6}"
do
    if [ -z "${OPTION}" ]; then
        break
    fi
    if [ -n "$(echo ${OPTION} | grep DOMAIN)" ] || [ -n "$(echo ${OPTION} | grep DNS)" ]; then
        echo ${OPTION} |sed -e 's/dhcp-option DOMAIN/search/g' -e 's/dhcp-option DNS/nameserver/g' >> /etc/resolv.conf
    fi
done

if [ ! -f /etc/resolv.conf ]; then # openvpn did not set any DNS information
    mv /etc/resolv.conf.hold /etc/resolv.conf
fi

and ./down.sh

#!/bin/sh

mv /etc/resolv.conf.hold /etc/resolv.conf

A more elaborate updown script (using resolvconf) can be found on https://gist.github.com/5084036e9a4b4206e074.

Statistics

Add a line to your /etc/openvpn/server.conf:

status openvpn.status

and use the python script from http://code.geek.sh/2009/07/simple-openvpn-server-statistics/

Resources

Comments