Skip to content

OpenVPN server on FreeBSD with pf firewall

by Finn Espen Gundersen on November 3rd, 2014

FreeBSD 10, with the new and improved packet filter/firewall pf, and OpenVPN are all great products. But I had a not so great time making them play together – especially with a Windows 8 client. As with everything, it is easy when you know how.

Most OpenVPN examples seem to be using the tap interface and ethernet bridging. To keep things simple, I wanted to go with the default ip-routed tun interface. Apart from being default, thus requiring less config fiddling, it fits nicely with pf and requires one less kernel module.

After making it all play together, I also wanted the connecting clients to access the internet through the VPN connection, necessitating some routing. The last step is not necessary if all the resources the VPN clients will need are on the server itself. A similar step will be required if the clients should access other servers close to the VPN entry-point.

The steps outlined here should also work on FreeBSD 9.

Preparing certificates

Installing is as easy as

pkg install openvpn

But before we can go ahead and start it, we need keys and certificates. Decide on somewhere to keep the server’s private keys and other crucial files, I opted for

mkdir /root/sslCA
chmod 700 /root/sslCA

This needs to be put in /etc/ssl/openssl.cnf as

dir            = /root/sslCA    # Where everything is kept

OpenSSL also requires some folders and a serial number

cd /root/sslCA
mkdir certs private newcerts
echo 1024 > serial
touch index.txt

Then, let’s generate the 10 year Certificate Authority which will be used to sign the certificates

openssl req -new -x509 -days 3650 -extensions v3_ca -keyout private/cakey.pem -out cacert.pem -config /etc/ssl/openssl.cnf

OK, that authority can now sign the server certificate. This is a two-step process where we first generate a request for a certificate, then the actual certificate. Note that while you can put almost anything in the fields when asked, you will need at least a common name for each, and the organization must be the same for both certificates.

openssl req -new -nodes -out server.req -keyout private/server.key -config /etc/ssl/openssl.cnf
openssl ca -out server.crt -infiles server.req -config /etc/ssl/openssl.cnf

Answer yes [y] where asked.

If you want to use password-based authentication for the clients, these are all the certificates you need. But if you want certificate based authentication, then each client will also need a certificate. Just create another request and certificate in the same manner, but with “server” replaced by “client”. You will need to copy those files (and the CA cert) to the client later.

The last piece of the plumbing puzzle is the random Diffie-Hellman parameters.

openssl dhparam -out dh1024.pem 1024


Configure OpenVPN

We will base our config on the sample file, so copy it first.

cp /usr/local/share/examples/openvpn/sample-config.files/server.conf /usr/local/etc/openvpn/openvpn.conf

Most settings are defaults. In particular we avoid some work with tap and bridges since we are using a tunneled ip routed interface. But we need to tell OpenVPN where we put everything. Look for the lines in openvpn.conf starting with ca, cert, key and dh.

ca   /root/sslCA/cacert.pem
cert /root/sslCA/server.crt
key  /root/sslCA/private/server.key
dh   /root/sslCA/dh1024.pem

If you want the client to use the VPN as the default gateway, i.e. not only to access server resources, but perhaps also to surf the web, you will need to put these two lines either in the server or client config. You will also need some routing, see below.

push "redirect-gateway def1 bypass.dhcp"
push "dhcp-option DNS"

If you want the clients to be able to see each other, uncomment the line


Now, prepare to run by adding to /etc/rc.conf:


And then, ignition:

/usr/local/etc/rc.d/openvpn start



If all you want is for the clients to access the server, no routing is necessary. If you don’t already have pf (or another firewall) enabled, consider yourself done with the server setup. However, if you have a firewall and/or want the clients to access the internet, or other servers in your LAN, you are in for  some pf magic.

The packet filter pf just recently got SMP support in FreeBSD. It perfectly illustrates how the FreeBSD community values performance, now having a faster port than the native OpenBSD version. If only we could port the “match” functionality as well.

Type ifconfig and identify the name of your network interfaces.

create a file /etc/pf.conf containing

# default openvpn settings for the client network
vpnclients = ""
#put your wan interface here (it will almost certainly be different)
wanint = "vtnet0"
# put your tunnel interface here, it is usually tun0
vpnint = "tun0"
# OpenVPN by default runs on udp port 1194
udpopen = "{1194}"
icmptypes = "{echoreq, unreach}"

set skip on lo
# the essential line
nat on $wanint inet from $vpnclients to any -> $wanint

block in
pass in on $wanint proto udp from any to $wanint port $udpopen 
# the following two lines could be made stricter if you don't trust the clients
pass out quick 
pass in on $vpnint from any to any
pass in inet proto icmp all icmp-type $icmptypes

Note that all incoming TCP from the WAN is blocked with this setup, add a line resembling the “pass in for proto udp” one to open specific TCP ports.

Rule 1 of firewall design is “Never blindly copy-paste rules”. While the above has been designed to not expose copy-pasters to too much danger, it is certainly better to extract the essentials and adapt the pass rules to your own needs. If you want IPv6 you have to.

Since pf is included by default, all we need is some rc.conf settings


And then, enable packet forwarding, enable pf as our firewall, and start it

sysctl net.inet.ip.forwarding=1
pfctl -ef /etc/pf.conf

Nevermind any messages about missing ALTQ, we don’t need QoS (yet).


Configuring Clients

Thanks to using the tun interface and keeping to the defaults, the client configuration can be kept close to the defaults. Just search online for tutorials for your operating system. If your client is Windows 8, read on.

The Windows client includes an OpenVPN GUI program. I could not get that to show any GUI. If you can’t either, don’t despair. We will go old school and edit the settings file instead. If you don’t want to install the OpenVPN GUI, you don’t need it. You do, however, need the TAP adapter (selected by default) even though we have configured the server for TUN.

After installing the Windows OpenVPN client, copy the client.ovpn file from c:\Program Files\OpenVPN\sample-config to ..\config. It will need the CA certificate, client key and client certificate from the server to accompany it.

Edit the client.ovpn file slightly (it needs to be done as administrator). Look for the following lines and edit accordingly.

remote # put your server IP or name here
# the certificate files from the server (separate client certificate, not server)
ca   ca.crt
cert client.crt
key client.key
# remember to keep these lines commented out if they appear
;ns-cert-type server
;remote-cert-tls server

At the end add

#this line sets the VPN as default gateway
redirect-gateway def1
#these lines stroke Windows 8 the right way
route-method exe
route-delay 5
route-metric 550

To start the connection we need to run (as administrator) from the config directory

"c:\program files\openvpn\bin\openvpn.exe" --config client.ovpn

The default OpenVPN network is with the server at Try pinging it.


From → FreeBSD

  1. jawrat permalink

    this is a great tutorial/howto, except you didn’t point out how to generate the client cert/key pairs! can you help?

  2. jawrat permalink

    never mind, figured it out. reading comprehension is hard when you are running on less than usual sleep 🙂

  3. Kostiantyn permalink

    after allying of your vatiant of – /etc/pf.conf, I fully lost SSH access to the server. What can you suggest to recover?

    & tnx for the perfect text!

Leave a Reply

Note: XHTML is allowed. Your email address will never be published.

Subscribe to this comment feed via RSS