For this setup I’ll assume that you have two networks, A and B, in different locations, both connected to the Internet with broadband. At each location you will need a Linux system acting as a router/firewall to serve as the VPN end point. I’m using two Asus WL-500G Deluxe routers running OpenWRT RC5 — a Linux distribution for embedded routers — but you’re free to use the hardware and distribution of your choice. You can use one of the BSDs, Mac OS X, or even Windows; check the documentation on OpenVPN’s homepage for a list of supported operating systems. If your use OpenBSD, have a look at the article Creating secure wireless access points with OpenBSD and OpenVPN.
The networks on both locations must use the same subnet — for instace, 192.168.0.0/24 — and in order to avoid conflicts, each computer at any location should have its own private IP address. A good practice is to use, for example, IP addresses 192.168.0.1 through 192.168.0.100 for computers on network A and 192.168.0.101 through 192.168.0.200 for network B. Reserve the range 192.168.0.201 through 192.168.0.254 for the routers and other network devices. In this example, the router on network A (routerA) will have the IP address 192.168.0.253 and will be the server for the VPN, while the router on network B (routerB) will have the IP address 192.168.0.254 and will be the client.
This setup runs OpenVPN in bridging mode, so you need to bridge the local network interface with the virtual interface tap0 used by OpenVPN on both routers. Issue
openvpn --mktun --dev tap0 to create the tap0 interface, then run
brctl addbr br0 to create the bridge and
brctl addif br0 eth0; brctl addif br0 tap0; ifconfig tap0 0.0.0.0 promisc up to add the local network interface eth0 (replace with your interface) and tap0 to the bridge and bring tap0 up. Each distribution has its own way of configuring network bridges; see the article Create a secure Linux-based wireless access point for bridging on Debian.
Now you need to create SSL certificates. It’s good security practice to use a separate computer for this purpose, and preferably one not connected to the Internet. OpenVPN provides scripts (called easy-rsa) to facilitate the procedure, so it’s just a matter of answering a few simple questions. The creation of certificates is described in the PKI part of OpenVPN’s How-To, so I’ll just provide a list of the steps necessary for creating the required certificates:
cd /usr/share/doc/openvpn/easy-rsa (might be different on your distribution) . ./vars ./clean-all ./build-ca ./build-key-server routerA ./build-key routerB ./build-dh openvpn --genkey --secret keys/ta.key
On routerA, create the directory /etc/openvpn/keys by issuing
mkdir -p /etc/openvpn/keys and copy the files ca.crt, dh1024.pem, routerA.crt, routerA.key, and ta.key that you created earlier to that directory. Do the same thing on routerB, copying instead the files ca.crt, routerB.crt, routerB.key, and ta.key. Also create the directories /etc/openvpn/chroot/ccd on routerA and /etc/openvpn/chroot on routerB. Paste the following lines into the file /etc/openvpn/server.conf on routerA:
mode server proto udp port 1194 dev tap0 keepalive 10 120 daemon writepid /var/run/openvpn.pid comp-lzo max-clients 10 user nobody group nogroup persist-key persist-tun verb 3 mute 20 client-to-client duplicate-cn cd /etc/openvpn tls-server tls-auth keys/ta.key 0 cipher BF-CBC ca keys/ca.crt cert keys/routerA.crt key keys/routerA.key dh keys/dh1024.pem chroot chroot client-config-dir ccd
Paste the following lines into /etc/openvpn/client.conf on routerB, replacing 184.108.40.206 with routerA’s public IP address. If you don’t use an Internet connection with static IP addresses, you can use a dynamic DNS service, such as DynDNS, instead.
client proto udp dev tap0 remote 220.127.116.11 1194 resolv-retry infinite nobind persist-key persist-tun ns-cert-type server comp-lzo daemon writepid /var/run/openvpn.pid verb 3 mute 20 user nobody group nogroup cd /etc/openvpn ca keys/ca.crt cert keys/routerB.crt key keys/routerB.key tls-auth keys/ta.key 1 chroot chroot
OpenVPN will drop its privileges to user nobody and group nogroup and will chroot to the directory /etc/openvpn/chroot as soon as it initializes, for better security. Since the VPN will run over the Internet, it’s a good idea to use LZO compression to save some bandwidth, so unless you have really fast Internet connections you should leave the
comp-lzo parameter as it is. You can find explanations about the other options used in the configuration files on the openvpn man page.
Make sure that routerA accepts UDP connections from the Internet on port 1194; if you use iptables, run
iptables -A INPUT -i WAN -p udp --dport 1194 -j ACCEPT, replacing WAN with your router’s interface that’s connected to the Internet. Start the OpenVPN daemon on routerA with
openvpn --config /etc/openvpn/server.conf and on routerB with
openvpn --config /etc/openvpn/client.conf. Now you should be able to connect to hosts on network B from hosts on network A and vice versa. If you have any problems, set the verbosity level, verb, to 9 in your configuration files and check the system logs.
To have OpenVPN start automatically on boot you can use your distribution’s init scripts or just add the commands you issued before to initialize the bridge and run the openvpn daemon to your rc.local file. If you use OpenWRT, create /etc/init.d/S70openvpn on both routers and paste the following into the file:
#!/bin/sh case "$1" in stop) kill `cat /var/run/openvpn.pid` ;; *) if ! brctl show | grep -q tap0; then openvpn --mktun --dev tap0 brctl addif br0 tap0 ifconfig tap0 0.0.0.0 promisc up fi openvpn --config /etc/openvpn/server.conf (replace with client.conf in routerB) ;; esac
Make that file executable, with
chmod 755 /etc/init.d/S70openvpn.
Recently I installed a system like this for a small company that wanted to connect its branch office to its headquarters. The company’s owner is more than happy with OpenVPN’s performance and security, but he’s happier because he could upgrade their IT infrastructure to meet their needs without spending a fortune on proprietary VPN systems.