The FreeBSD Diary

The FreeBSD Diary (TM)

Providing practical examples since 1998

If you buy from Amazon USA, please support us by using this link.
OpenVPN - creating a routed VPN 29 November 2008
Need more help on this topic? Click here
This article has 1 comment
Show me similar articles

In this article, I will show you how I created a routed VPN using OpenVPN. In this network, multiple clients can attach to the server, each of which has access to the network attached to the server. Each client can also contact any other client, subject to firewall rules.

NOTE (added 20 December 2012): I've now been using OpenVPN for 4 years. It runs on all my servers and my laptop. It has been rock-solid and extremely stable. It comes with my highest recommendation.

In my case, I wanted a way for all my servers (on the internet, in data centers) to contact my CVS repository behind my firewall at home. Given that home has a dynamic IP address, it complicates matters. A VPN solves this issue and provides several benefits. I have outlined the problems in my other diary and I urge you to read that before proceeding. It will provide valuable background as to why I have chosen this particular solution.


Two people have been of great help while I struggled with OpenVPN. ecrist and krzee have both pointed me to examples and features. Others within the FreeNode OpenVPN channel also listened to my goals and provided suggestions. Thanks.

Here are a few good references:


This article relies upon previous articles on this website:

Most of this article will concentrate on the configuration and setup. It will not cover certificates or installation.

Server configuration

NOTE: since this was originally written, I have changed the configuration. The article used to show both ifconfig-pool-persist and client-config-dir settings. The latter can be used with ifconfig-push to guarantee static IP addresses. That is what I need. I have since changed the configuration shown below to reflect what I am using now.

This section shows you the setup of my OpenVPN server. The main configuration file is /usr/local/etc/openvpn/openvpn.conf. This is mine:

port 1194
proto udp
dev tun
ca /usr/local/etc/openvpn/keys/ca.crt
cert /usr/local/etc/openvpn/keys/
key /usr/local/etc/openvpn/keys/
dh /usr/local/etc/openvpn/keys/dh1024.pem
client-config-dir /usr/local/etc/openvpn/ccd
keepalive 10 120
user nobody
group nobody
tls-auth /usr/local/etc/openvpn/keys/ta.key 0
status openvpn-status.log
verb 4

push "route"

Some of the options from above are outlined below. For full details, please refer to the OpenVPN man page.

The ca, cert, key, and dh directives are straight from the basic setup given in the previous article.

client-config-dir specifies the directory for custom client config files. We use these files for assigning static IPs, but they have additional uses.

server indicates that our VPN server will use the subnet.

client-to-client allows each VPN client to see all other VPN clients.

tls-auth is a shared secret, same file in each client, that is optional but allows n additional layer of HMAC authentication on top of the TLS control channel to protect against DoS attacks.

push ensures that each client can access the network on the VPN server. This push adds an entry to the client's routing table.

Client configuration

The configuration file, /usr/local/etc/openvpn/openvpn.conf, contains this:

dev tun
proto udp
remote 1194
resolv-retry infinite
user nobody
group nobody
ns-cert-type server
tls-auth /usr/local/etc/openvpn/keys/ta.key 1
ca /usr/local/etc/openvpn/keys/ca.crt
cert /usr/local/etc/openvpn/keys/
key /usr/local/etc/openvpn/keys/
verb 4

As expected, I will outline some of these directives.

client designates this as a client configuration.

ns-cert-type server avoids a man-in-the-middle attack.

tls-auth is the same shared secret file as mentioned in the server section. I will show you how to generate it later. Notice that the direction is 1 on the client and 2 on the server. See the --secret option on the OpenVPN man page for more information.

ca, cert, key, and dh have been previously explained.

Client firewall rules

The following is a common problem:

TLS Error: TLS key negotiation failed to occur within 60 seconds (check your network connectivity)
TLS Error: TLS handshake failed

If you see this message on both the client and the server, it is most likely a firewall problem. That is, the messages which need to flow between the client and the server are not being allowed to flow. This is doubly true if you have other clients which are working well, and one which is not. In my case, I needed to add a rule to my client firewall. I use pf. The rule is:

pass out log on $PUBLIC inet proto udp from any to any port 1194 synproxy state

Where $PUBLIC is the name of my network interface (in this case, it is em0). In my case, I tested this situation by removing all firewall rules on the client. OpenVPN immediately connected, thereby confirming that it was a firewall issue.

Generating the tls-auth

You can generate a tls-auth file with this command:

openvpn --genkey --secret /usr/local/etc/openvpn/keys/ta.key

Copy the file contents to each client.

Getting it running

Start both the server and the client. You should see this on the server:

tun0: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1500
        inet6 fe80::204:acff:fea3:74af%tun0 prefixlen 64 scopeid 0x9
        inet --> netmask 0xffffffff
        Opened by PID 59658

Notice that this configuration uses tun0, not tap0.

On the client, you should see something like this:

tun0: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> metric 0 mtu 1500
        inet --> netmask 0xffffffff
        Opened by PID 39769

You will also see that the server is configured for IPv6 but the client is not (i.e. the inet6 line).

The client should be able to ping the server:

$ ping
PING ( 56 data bytes
64 bytes from icmp_seq=0 ttl=64 time=24.077 ms
64 bytes from icmp_seq=1 ttl=64 time=23.429 ms
64 bytes from icmp_seq=2 ttl=64 time=23.045 ms
64 bytes from icmp_seq=3 ttl=64 time=31.404 ms
--- ping statistics ---
4 packets transmitted, 4 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 23.045/25.489/31.404/3.435 ms

That's it. Now, on to static IP addresses

Static IP addresses

I want static IP addresses for my clients. This will make things easier when it comes to running jobs on them. These hosts already have public IP addresses and hostnames. I will add private hostnames for them. For example, if the host can be accessed publicly by the name, then I will add a new entry to my private DNS server (accessible only from my LAN at home) for

nyi-vpn             IN  A
After reloading the name server, I can resolve that hostname:
$ host nyi-vpn has address

To assign that IP address to that host, I create a file in the client-config-dir, namely: /usr/local/etc/openvpn/ccd

That file must have the same name as the client's X509 common name. In this case:

The file will contain:


You can provide an IP address instead of a hostname. Restart your client and you should see something similar to this in /var/log/messages on your server:

OPTIONS IMPORT: reading client specific options from: /usr/local/etc/openvpn/ccd/
MULTI: Learn: ->
MULTI: primary virtual IP for PUSH: Received control message: 'PUSH_REQUEST' SENT CONTROL []: 'PUSH_REPLY,route,route,ping 10,ping-restart 120,
        ifconfig' (status=1)

And on the client, you'll see messages similar to this:

TUN/TAP device /dev/tun0 opened
/sbin/ifconfig tun0 mtu 1500 netmask up
/sbin/route add -net
/sbin/route add -net

There, you should be running now. I think this VPN solution will be ideal to me. Time will tell. Let's see what happens when my first IP address change happens. For now, I'm about to alter my Nagios monitoring to check my remote clients over the VPN rather than the public networks. This little bit of work now will save me a great deal of time when my IP address changes.

Enjoy OpenVPN.

Need more help on this topic? Click here
This article has 1 comment
Show me similar articles