Last Updated: 01 Apr 2018


Author: dordal

Setting up OpenVPN Server on CentOS 7 using EasyRSA 3

If you travel frequently, it can be handy to use a VPN service with an endpoint back home, particularly if you don't want somebody spying on you in an Internet cafe or airport. Properly setup, a VPN will encrypt all traffic originating from your machine, send it out over the Internet to the VPN server, and then it will go from there to the wider Internet.

There are a number of commercially available VPN services, but if you're technically inclined, you might want to setup your own. This document tells you how, using CentOS 7, OpenVPN, EasyRSA 3, and Viscosity, an excellent VPN client for Mac & Windows.

First, big thanks to Digital Ocean's VPN setup guide, as well as the guide and config files provided by Tyler Duzan.

Basic CentOS Setup

First, you'll need a CentOS 7 server. You can use one from almost anywhere – a machine with Digital Ocean, AWS or Azure, or one in your friend's apartment. Assuming you're starting from scratch, you'll need to get the software updated and the EPEL repo installed.

# sudo yum update -y
# sudo yum install epel-release -y
# sudo yum update -y

Then you'll want to install openvpn, easyrsa, iptables and (recommended) a few network troubleshooting tools.

# sudo yum install -y openvpn easy-rsa iptables iptables-services wget yum-cron net-tools bind-utils nc mtr

Setting up OpenVPN

Now, you'll want to configure the OpenVPN server. To do this, copy the following file to /etc/openvpn/server.conf. Thanks to the hardened config from Tristor, which I used as a starting point.

# Secure OpenVPN Server Config

# Basic Connection Config
dev tun
proto udp
port 1194
keepalive 10 120
max-clients 5

# Certs
ca ca.crt
cert server.crt
key server.key
dh dh.pem
tls-auth ta.key 0

# Ciphers and Hardening
reneg-sec 0
remote-cert-tls client
crl-verify crl.pem
tls-version-min 1.2
cipher AES-256-CBC
auth SHA512

# Drop Privs
user nobody
group nobody

# IP pool
topology subnet
ifconfig-pool-persist ipp.txt
client-config-dir ccd

# Misc

# DHCP Push options force all traffic through VPN and sets DNS servers
push "redirect-gateway def1 bypass-dhcp"
push "dhcp-option DNS"
push "dhcp-option DNS"

# Logging
log-append /var/log/openvpn.log
verb 3

Make the Client Config Directory

This directory can hold client-specific configs, if desired:

# mkdir /etc/openvpn/ccd

Generating the Keys and Certificates

OpenVPN provides a tool called EasyRSA, which lets you generate the keys you need. You installed it above, so time to get going:

First, Init PKI:

# cd ~
# /usr/share/easy-rsa/3/easyrsa init-pki

Now, build the certificate authority. You'll be asked for a common name; I use 'VPN'. If you want to be extra secure, you can set this to be the FQDN of your host, and then turn on an option to make sure that the CN of the certificate matches the FQDN of the server, but I prefer not to do this, so my certificates are portable:

# /usr/share/easy-rsa/3/easyrsa build-ca nopass

Generate the Diffie-Helllman parameters:

# /usr/share/easy-rsa/3/easyrsa gen-dh

Generate the server keys (vpn-server should be the name of your server):

# /usr/share/easy-rsa/3/easyrsa build-server-full vpn-server nopass

Generate one or more client keys (vpn-client-01 should be the name of your client machine):

# /usr/share/easy-rsa/3/easyrsa build-client-full vpn-client-01 nopass

Generate the certificate revocation list:

# /usr/share/easy-rsa/3/easyrsa gen-crl

Generate a pre-shared key. This helps harden your VPN; for details see the details about –tls-auth on the OpenVPN Hardening page.

# openvpn --genkey --secret pki/ta.key

Copying the Keys

Now you need to copy your keys to the OpenVPN config directory. Everything should be in ~/pki:

# sudo cp pki/ca.crt /etc/openvpn/ca.crt
# sudo cp pki/dh.pem /etc/openvpn/dh.pem
# sudo cp pki/issued/vpn-server.crt /etc/openvpn/server.crt
# sudo cp pki/private/vpn-server.key /etc/openvpn/server.key
# sudo cp pki/ta.key /etc/openvpn/ta.key
# sudo cp pki/crl.pem /etc/openvpn/crl.pem

Setup OpenVPN to Start Automatically

Next up, you'll want to startup OpenVPN. To do so:

# sudo systemctl -f enable openvpn@server.service
# sudo systemctl start openvpn@server.service

If it doesn't start, check the log for clues:

# sudo tail -f /var/log/openvpn.log

Optionally, you may want to skip ahead to Setting up the Client, so you can test things out. At this point you should be able to connect to your VPN server, and ping it from your client ( if you've followed the steps above ). You won't be able to pass live traffic through the VPN until you complete the routing steps below, but this can be a good point to make sure that everything is working.

Setting up Routing w/ iptables

Since your server will be a VPN server, you probably want to block most inbound connections, except over SSH and the OpenVPN port. You'll also want to allow packet forwarding from VPN clients to the wider internet, or else your client could only talk to your VPN server itself. We do that with iptables.

Enable IPv4 Forwarding

First, edit /etc/sysctl.conf and add the following lines:

# Packet forwarding
net.ipv4.ip_forward = 1

Save the file, and then run sysctl -p to load the changes. You can verify forwarding is enabled by doing more /proc/sys/net/ipv4/ip_forward which should return 1 if its enabled.

Configure IPTables

Now, we run a series of commands to configure iptables. Thanks again to Tristor for his work here, which forms the basis of this. Note that you MUST do this as part of a bash script which gets run all at once, if you type these commands line by line you'll cut yourself off from SSH access before you can enter the commands to open it up. Also, if you're not using for your VPN subnet, you'll need to change that below.


# REMEMBER: Run this as a single bash script or you'll lock yourself out of your machine.

# Flushing all rules
iptables -F FORWARD
iptables -F INPUT
iptables -F OUTPUT
iptables -X
# Setting default filter policy
iptables -P INPUT DROP
iptables -P OUTPUT DROP
iptables -P FORWARD DROP
# Allow unlimited traffic on loopback
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
# Accept outbound on the primary interface
iptables -I OUTPUT -o eth0 -d -j ACCEPT
# Accept inbound TCP packets
iptables -I INPUT -i eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT
# Allow incoming SSH
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -s -j ACCEPT
# Allow incoming OpenVPN
iptables -A INPUT -p udp --dport 1194 -m state --state NEW -s -j ACCEPT
# Enable NAT for the VPN
iptables -t nat -A POSTROUTING -s -o eth0 -j MASQUERADE
# Allow TUN interface connections to OpenVPN server
iptables -A INPUT -i tun0 -j ACCEPT
# Allow TUN interface connections to be forwarded through other interfaces
iptables -A FORWARD -i tun0 -j ACCEPT
iptables -A OUTPUT -o tun0 -j ACCEPT
iptables -A FORWARD -i tun0 -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -i eth0 -o tun+ -m state --state RELATED,ESTABLISHED -j ACCEPT
# Allow outbound access to all networks on the Internet from the VPN
iptables -A FORWARD -i tun0 -s -d -j ACCEPT
# Block client-to-client routing on the VPN
iptables -A FORWARD -i tun0 -s -d -j DROP

Finally, enable that config as a service.

sudo systemctl enable iptables
sudo systemctl start iptables
sudo service iptables save

Setting up the Client

Getting the VPN server running is only half the battle. Actually, it's about 90% of the battle, but you still have to do the client side work. Assuming you're using Mac or Windows, you pretty much want to use Viscosity. It's an excellent third party VPN client, and my favorite. It's $9, but pay it. It's worth it.

First, on the server, make a directory and copy the client config and client certificates into it:

# cd ~
# mkdir vpn-client-01-config
# cp pki/ca.crt vpn-client-01-config/ca.crt
# cp pki/issued/vpn-client-01.crt vpn-client-01-config/client.crt
# cp pki/private/vpn-client-01.key vpn-client-01-config/client.key
# cp pki/ta.key vpn-client-01-config/ta.key

Now, create the config file, at vpn-client-01-config/client.ovpn. Be sure to change the remote line to point to your vpn server!

# Secure OpenVPN Client Config

#viscosity dns full
#viscosity usepeerdns true
#viscosity dhcp true
dev tun
proto udp
remote 1194
redirect-gateway def1
verb 3
ca ca.crt
cert client.crt
key client.key
tls-auth ta.key 1
remote-cert-tls server
ns-cert-type server
key-direction 1
cipher AES-256-CBC
tls-version-min 1.2
auth SHA512

Now tar up the config, and download it to your Mac or Windows machine:

# tar cvfz vpn-client-01-config.tgz vpn-client-01-config

Then, simply import the client.opvn into Viscosity, and you'll be all set.


test94.140.116.53, Apr 27, 2018 07:04 AM

Thank you! very helpfull tutorial! One note only - on client.ovpn file need to remove line
“ns-cert-type server”

test136.60.227.178, Oct 18, 2018 10:38 PM

This tutorial has been my holy bible while learning how to set up my home server and get OpenVPN up and running. I tried several other tutorials that were either outdated or not well written but this one has been a rock. I really appreciate all the work you put into it, i've learned a lot about the topics you discussed because it was easy to research them from your descriptions.


test186.156.23.194, Dec 20, 2018 02:19 AM

I love you, you are the best dude.

test178.121.82.236, Jan 16, 2019 07:18 PM

Thank you for the tutorial.
But I'm stuck on the “Configure IPTables” step, Created the sh file, trying to run and the result is:

iptables: Too many links.

what can be wrong here?

dordal, Jan 16, 2019 10:11 PM

I'm not sure what would be wrong there. Short of Googling and trying to figure it out, you also might try stoping and starting the service, so that you clear out any old config and load it fresh.

test98.28.53.206, Feb 11, 2019 06:03 AM

You can try an iptables flush first manually. Make sure your interface names match as well!

Enter your comment. Wiki syntax is allowed: