Tutorial

How To Configure and Connect to a Private OpenVPN Server on FreeBSD 10.1

How To Configure and Connect to a Private OpenVPN Server on FreeBSD 10.1

Introduction

OpenVPN is an open-source virtual private network (VPN) server/client application which allows you to join a virtual network (similar to a LAN) securely.

This tutorial will explain how to install and configure an OpenVPN server on a FreeBSD 10.1 machine with IPv4 NAT and routing. It includes short explanations of various configuration options.

By the end of this tutorial you’ll be running your own OpenVPN server, and have a client configuration file ready to download to connect to this network.

Note: As of July 1, 2022, DigitalOcean no longer supports the creation of new FreeBSD Droplets through the Control Panel or API. However, you can still spin up FreeBSD Droplets using a custom image. Learn how to import a custom image to DigitalOcean by following our product documentation.

Prerequisites

  • A FreeBSD 10.1 server. Server size depends on how many clients you intend to connect to the VPN; 519 MB is fine for a few clients
  • Root access

This tutorial requires root access. In this tutorial, the server we use refers to a default freebsd user, then access to the root shell:

sudo tcsh

Step 1 — Installing OpenVPN

Installing OpenVPN with the pkg system is quite simple. Simply run these commands to update the package lists and install the VPN software:

pkg update
pkg install openvpn

This should also install the easy-rsa package, which will be used to generate the SSL key pairs.

Step 2 — Configuring the OpenVPN Server

For this tutorial we will base our configuration file on the sample one provided by OpenVPN. We’ll create a configuration folder for OpenVPN:

mkdir /usr/local/etc/openvpn

Copy the example server.conf file to the new directory.

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

Install nano or your favorite text editor:

pkg install nano

Open the config file for editing:

nano /usr/local/etc/openvpn/server.conf

Note: The OpenVPN configuration file format prefixes comments with semicolons (;) or hashes (#). In the example, semicolons are used to comment (disable) configuration options, and hashes are used for comments.

If you know what configuration options you want to modify you may do so at this point.

  • Optional port: The default port is 1194, but you can change this to anything you like
  • Optional proto: Choose either tcp or udp; the default is fine
  • user and group: Set these to nobody by uncommenting the lines. This will make OpenVPN run with fewer privileges, for security
user nobody
group nobody

Note: Each configuration can run only one port and protocol at once.

Finally, be sure to save your changes.

Step 3 — Generating Server Certificates and Keys

easy-rsa makes generating certs and keys simple.

First, copy the program to your configuration directory, since you will be modifying values.

cp -r /usr/local/share/easy-rsa /usr/local/etc/openvpn/easy-rsa

Open the vars file for editing:

nano /usr/local/etc/openvpn/easy-rsa/vars

Change the key size by modifying this line:

export KEY_SIZE=2048

These days the standard is 2048-bit keys, although you can also use 4096-bit, which is more secure but slows down negotiation.

If you like you can also set the default certificate and key values in this file so you don’t have to enter them later.

Since the shell we’re using is tcsh, the export lines need to be replaced with setenv. This is done with sed before the source. Move to our easy-rsa directory (required).

cd /usr/local/etc/openvpn/easy-rsa/

Replace the lines:

cat ./vars | sed -e 's/export /setenv /g' -e 's/=/ /g' | source /dev/stdin

Still from our /usr/local/etc/openvpn/easy-rsa/ directory, first clean the directory, then build the certificate authority (CA).

./clean-all
./build-ca

You will be prompted to set the CA options. Fill these in with your details:

Country Name (2 letter code) [US]:GB
State or Province Name (full name) [CA]:Somerset
Locality Name (eg, city) [SanFrancisco]:Bath
Organization Name (eg, company) [Fort-Funston]:Callum
Organizational Unit Name (eg, section) [changeme]:VPN
Common Name (eg, your name or your server's hostname) [changeme]:vpn.example.com
Name [changeme]:Callum's VPN CA
Email Address [mail@host.domain]:callum@example.com

Now build the server key:

./build-key-server server

Again, set the options. You do not need a password or an optional company name.

Enter y to sign and commit the key:

Country Name (2 letter code) [US]:GB
State or Province Name (full name) [CA]:Somerset
Locality Name (eg, city) [SanFrancisco]:Bath
Organization Name (eg, company) [Fort-Funston]:Callum
Organizational Unit Name (eg, section) [changeme]:VPN
Common Name (eg, your name or your server's hostname) [server]:vpn.example.com
Name [changeme]:Callum's VPN Server
Email Address [mail@host.domain]:callum@example.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []: ENTER
An optional company name []: ENTER

Certificate is to be certified until Feb  5 14:40:15 2025 GMT (3650 days)
Sign the certificate? [y/n]: y

1 out of 1 certificate requests certified, commit? [y/n] y
Write out database with 1 new entries
Data Base Updated

Finally the Diffie-Hellman key must be generated. This can take some time depending on key size:

./build-dh

Now that all the server keys and certs are generated, they should be copied to our OpenVPN configuration directory.

cd /usr/local/etc/openvpn/easy-rsa/keys/
cp dh*.pem ca.crt server.crt server.key /usr/local/etc/openvpn/

You’re done with the server certificates! Now on to the client certificate.

Step 4 — Generating Client Certificates

Each client will also each need a certificate and key in order to authenticate and connect to the VPN. Make sure you’re in the /usr/local/etc/openvpn/easy-rsa/ directory.

cd /usr/local/etc/openvpn/easy-rsa/

Run the following command, where clientName is the name you want to use for this particular client certificate.

./build-key clientName

You will be prompted to enter the country name, city name, etc. again. The process is the same as for the server key generation. This is intended to be the information of the client but none of it really matters.

You don’t need a passphrase or company name. Enter y to sign and commit the certificate.

Note: It is a good practice to use a different certificate for each client, and this is enforced by OpenVPN by default. However, if required, this can be disabled in the OpenVPN configuration (explained later).

If you used a key size different from 2048 you will need to modify the OpenVPN configuration to match the file name of the key size you used. If you don’t remember, you can view the correct file name of the dh file with this command:

ls /usr/local/etc/openvpn/easy-rsa/keys/dh*.pem

Edit the server.conf:

nano /usr/local/etc/openvpn/server.conf

Replace the line dh dh2048.pem with:

dh dhSIZE.pem

If you followed our recommendation for the 2048-bit key earlier, you don’t have to make any changes.

Repeat this section for each separate client certificate you want to create.

Step 5 — Configuring IPv4 NAT Routing

FreeBSD includes natd as part of the ipfw firewall which allows for NAT routing and can be used for OpenVPN. In order to use this, edit /etc/rc.conf:

nano /etc/rc.conf

Add these contents at the bottom:

firewall_enable="YES"
firewall_type="open"

gateway_enable="YES"
natd_enable="YES"
natd_interface="vtnet0"
natd_flags="-dynamic -m"
  • firewall_enable enables the ipfw firewall which is needed for natd
  • firewall_type="open" makes the firewall allow traffic as default
  • gateway_enable sets net.inet.ip.forwarding to 1 which allows IPv4 routing on the system
  • natd_enable enables the actual NAT router
  • natd_interface is the external interface towards the Internet;
  • natd_flags makes the NAT dynamic and -m preserves port numbers

Now reboot your server to load ipfw and natd:

reboot

Log in again. After the reboot, remember to run sudo tcsh again to become root if you aren’t already.

Step 6 - Configuring OpenVPN Routing Config and DNS

By default OpenVPN isn’t configured to tell the client to route Internet traffic through the VPN. We’ll make sure it does route traffic through OpenVPN by uncommenting some lines in /usr/local/etc/openvpn/server.conf:

nano /usr/local/etc/openvpn/server.conf

Locate and uncomment these three lines:

push "redirect-gateway def1 bypass-dhcp"

push "dhcp-option DNS 208.67.222.222"
push "dhcp-option DNS 208.67.220.220"

The preset DNS servers are for OpenDNS but you can set them to whatever DNS you like (such as Google DNS with 8.8.8.8 and 8.8.4.4).

Optional settings:

You may also allow clients to directly communicate with each other’s IPs by uncommenting:

client-to-client

If, as mentioned earlier, you want to use the same keys and certificates for multiple clients (which is slightly less secure) uncomment this line:

duplicate-cn

Compression can be enabled and disabled with this line:

comp-lzo

Your cipher can be set manually by uncommenting one of these lines:

cipher BF-CBC        # Blowfish (default)
cipher AES-128-CBC   # AES
cipher DES-EDE3-CBC  # Triple-DES

Note: Whichever cipher you use must also be defined in the client config file which we will create later.

Additional ciphers are also available, such as aes-256-cbc.

Step 7 — Starting OpenVPN

Enable OpenVPN to load on boot and load with the service command by adding the following line to /etc/rc.conf:

nano /etc/rc.conf

Add these lines at the bottom of the file:

openvpn_enable="YES"
openvpn_configfile="/usr/local/etc/openvpn/server.conf"

The OpenVPN server is now fully configured and will load on boot.

Start the server manually with:

service openvpn start

Expected output:

add net 10.8.0.0: gateway 10.8.0.2

Your OpenVPN server is now running.

Step 8 — Configuring Client File

On the server we’ll create the configuration file for each client.

First, create a folder to work in:

mkdir -p /usr/local/etc/openvpn/clients/clientName

Make clientName the client name we set earlier while generating certificates. (It doesn’t matter precisely how you set this since it is only a working directory.)

Move to the new directory:

cd /usr/local/etc/openvpn/clients/clientName/

Copy in the client key and certificate we generated with easy-rsa, and the sample client.conf file. Make sure you replace the clientName with the name you used earlier for the .key and .crt files:

cp /usr/local/etc/openvpn/easy-rsa/keys/clientName.crt /usr/local/etc/openvpn/easy-rsa/keys/clientName.key ./
cp /usr/local/share/examples/openvpn/sample-config-files/client.conf ./client.conf
cp /usr/local/etc/openvpn/ca.crt ./

Again, clientName was what we used earlier.

Edit the client.conf file:

nano ./client.conf

Update the remote line to include your server’s IP address (which can be obtained with ifconfig) and the port number; 1194 is the default:

remote your_server_ip 1194

Note: If you modified the server’s cipher or comp-lzo settings, then this must be reflected in the client.conf file. Use the same settings you did previously; for example:

cipher aes-256-cbc
;comp-lzo

This setting uses the aes-256-cbc cipher and disables compression.

If you changed the proto line in the server configuration, then this also needs to be reflected in the client.

Make sure these lines match what you set earlier; if you didn’t change anything on the server side, don’t change them here.

Now a bit of housekeeping; we will be embedding the certificates and key in the single configuration file. This makes it easier to transfer to individual clients. Alternately, you can download the configuration file and the key and two certificate files to the client separately.

In the same client.conf file, comment out the certificate and key file names:

;ca ca.crt
;cert client.crt
;key client.key

Save your changes.

Finally, we need to embed the ca.crt, clientName.crt and clientName.key files in the configuration file. You can copy and paste the contents in using cat or nano or whatever you’re most comfortable with, and the appropriate variables for OpenVPN, or you can use the one-line script shown below.

Run this script and enter your clientName when prompted. The script appends your certificate and key files to the client.conf file, with appropriate variable names and newlines that OpenVPN is expecting:

echo "Enter clientName:" && set CLIENTNAME = $< && printf "\n<ca>\n" >> ./client.conf && cat ./ca.crt >> ./client.conf && printf "</ca>\n" >> ./client.conf && printf "\n<cert>" >> ./client.conf && grep -v '^ ' ./$CLIENTNAME.crt | grep -v 'Certificate' >> ./client.conf && printf "</cert>\n" >> ./client.conf && printf "\n<key>\n" >> ./client.conf && cat ./$CLIENTNAME.key >> ./client.conf && printf "</key>\n" >> ./client.conf

Make sure you scroll all the way to the right, since this is a long command.

Take a look at the finished client.conf file with nano or cat. You should see the key and certificates added to the file at the bottom.

You’re done! All that needs to be done now is to distribute the client.conf file to your client. Most clients prefer the extension .ovpn to .conf, so you will want to rename the file locally to my_vpn.ovpn or something similar.

Repeat this section for each client. Use separate certificates by default, or use the same client certificate on each client if you prefer.

Conclusion and Client Setup

You should now have a working OpenVPN server!

Download the client configuration file you created in the last step (/usr/local/etc/openvpn/clients/clientName/client.conf) to your local machine. Use a secure method to download the file, such as SCP or SFTP.

Also on your local machine, install an OpenVPN client. Tunnelblick works well on Mac OS X, and OpenVPN has a Windows client.

Make sure your client configuration file is named as expected; this is usually a name like my_vpn.ovpn.

Double-click the file or move it to your client’s expected directory.

Start your client and connect to the appropriate OpenVPN server.

To ensure your VPN is working, use an IP address checker such as http://www.whatismyip.com/. Your IP shown should match your OpenVPN server’s IP.

Congratulations! You’ve connected to your new OpenVPN server.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the author(s)

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
10 Comments
Leave a comment...

This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Great guide @calluma! Is there any way to tighten up the firewall a bit so it’s not wide open?

I successfully set up an OpenVPN server on FreeBSD with this guide and my Windows and Mac clients have no trouble connecting to it. But for some reason the network bandwidth is terrible on both systems once the VPN tunnel has been established. My local ISP provides me with 100 Mbit/s downstream, the FreeBSD droplet has a downstream/upstream of +300 Mbit/s (according to speedtest-cli) but over the VPN tunnel I can’t get more than 20-30 Kbit/s downstream. The droplet itself has no heavy CPU or RAM load. OpenVPN is the only service I was going to use it for. Switching from my home ISP to my university’s network does not affect this low bandwidth issue. What else can I do now? Are there any other settings that could cause this behavior?

That happens to me as well.

The firewall_type=“open” seems to be the issue, but I have been unable to get OpenVPN to work otherwise on FreeBSD.

This comment has been deleted

    Please see my comment below, I resolved this issue by disabling large receive offload.

    Hi

    Thank you ! Everything works fine. I have changed only one detail on creating the client keys: ./build-key-pass clientName instead of ./build-key clientName

    just to give a prompt on the client side before connecting

    Regards

    At first I’ve been doing all of this via ssh, but after setting up the firewall in Step 5 I could not connect. So I’ve had to login via console to finish everything. Maybe this will be helpful for somebody.

    If you experience poor performance (the order of 10-100s of kb/s downloads) you need to disable large receive offload. The vtnet driver and lro don’t seem to play nice, you can first confirm this is the issue via:

    % sudo ifconfig vtnet0 -lro
    

    if that fixes your problem then you can add " -lro" to the end of the line in the vtnet interface configuration in /etc/rc.digitalocean.d/droplet.conf

    Also, I would consider not following this tutorial because it uses the outdated natd. The freebsd digital ocean kernel has support for ifpw_nat, so I would just enable that instead.

    To accomplish that just remove the natd lines from /etc/rc.conf and instead do:

    firewall_nat_enable="YES"
    firewall_nat_interface="vtnet0"
    

    Next, make sure the ipfw_nat module is loading by adding the following line to /boot/loader.conf:

    ipfw_nat_load=YES
    libalias_load=YES
    

    And that should resolve all performance related problems some people are seeing. Cheers.

    This comment has been deleted

      I was really hoping you were right, but unfortunately things are not that simple…

      As as side note the above firewall config can also be implemented using pf.

      I still have speed issues, regardless which firewall config I use…

      The speed I get is 0.1 Mbps Download and 35.4 Mbps Upload. I have tried ifconfig vtnet0 -tso -lro and also ifconfig vtnet0 -lro and ifconfig vtnet0 -tso Nothing helps… the download speed will remain at 0.1 Mbps while the Upload speed will be about 35 Mbps

      Hi!

      I’m following this tutorial and got stuck in step 3. I opened nano /usr/local/etc/openvpn/easy-rsa/vars but can’t find export KEY_SIZE=2048 Is there new formatting introduced since this article has been written? I do have #set_var EASYRSA_KEY_SIZE 2048 But even when uncomenting this line, running next command (that I honestly don’t understand), returns this error:

      root@beasty:/usr/local/etc/openvpn/easy-rsa # cat ./vars | sed -e 's/export /setenv /g' -e 's/=/ /g' | source /dev/stdin
      EASYRSA_CALLER: Undefined variable.
      

      Any help would be appreciated

      Just to let you know, you’re not the only one. These instructions appear to be for some earlier version of easy-rsa. I’ve been trying things with the current version and sort-of have it figured out. When I get the whole thing up and running I’ll post instructions here.

      Yeah, all Step 3 seems obsolete.

      Hi ,HenryV, Did you finish the test for “EASYRSA_CALLER: Undefined variable.” OS: FreeBSD 10.3 EASY-RSA: 3.0.1_1 OPENVPN: 2.3.11 I am waiting for you.

      Try using ports for easy-rsa (v2.2) if you haven’t updated them yet (worked for me).

      cd /usr/ports/security/easy-rsa/ make deinstall clean make install clean

      I cannot issue these commands on my installation:

      /usr/local/etc/openvpn/easy-rsa/

      ./clean-all ./build-ca

      Please help

      Do I have problem using freebsd 10.3 with this tutorial?

      I’ve tried this on FreeBSD 10.3 on a LON1 512 droplet and I get terrible throughput. Nothing I’ve done has changed it. I’m beginning to think that digitalocean have a rate-limiting issue or something as this is a default configuration.

      I notice that on the FreeBSD droplet networking is setup using avahi. Could this have anything to do with it?

      I sent a support ticket to DigitalOcean who confirmed to me that the normal FreeBSD 10.3 (non-zfs) droplet does indeed have known networking issues. They suggest moving to the ZFS version in which they have solved these problems.

      I’ll be moving mine soon and let you know how it goes. I might even write a new tutorial as it uses EasyRSA 3 which has different commands.

      So I just created this on their new FreeBSD 10.3 ZFS droplet and I run into the same exact problems. I’ve sent an email back to them saying it’s still not working, but in the meantime I went back to Ubuntu 16.04.1 droplet and used this script to auto setup openvpn and it worked instantly.

      It’s a shame as freebsd is great, but Im going to stick with ubuntu for now.

      Sorry to bump an old thread, but did we ever solve the slow VPN speeds in the latest droplet? Is anyone else still having this trouble?

      I can confirm that the problem still exists today with: FreeBSD - 12.0 RELEASE and OpenVPN 2.4.7

      I’ve tried running this command as a fix, to no avail: ifconfig vtnet0 -tso -lro

      After working with this a lot, I was able to get very acceptable speeds by executing the following command: ifconfig vtnet0 -tso -lro -rxcsum

      In my /usr/local/etc/rc.d/digitalocean file, I modified this line (48 for me) to the following and now everything is working well: ifconfig_vtnet0=“inet ${ip4_addr} netmask ${ip4_mask} -tso -lro -rxcsum”

      Join the Tech Talk
      Success! Thank you! Please check your email for further details.

      Please complete your information!

      Become a contributor for community

      Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

      DigitalOcean Documentation

      Full documentation for every DigitalOcean product.

      Resources for startups and SMBs

      The Wave has everything you need to know about building a business, from raising funding to marketing your product.

      Get our newsletter

      Stay up to date by signing up for DigitalOcean’s Infrastructure as a Newsletter.

      New accounts only. By submitting your email you agree to our Privacy Policy

      The developer cloud

      Scale up as you grow — whether you're running one virtual machine or ten thousand.

      Get started for free

      Sign up and get $200 in credit for your first 60 days with DigitalOcean.*

      *This promotional offer applies to new accounts only.