Setup OpenVPN server on Ubuntu
First of all you need to rent any cheap VPS server from Data Center located in desired country. It could be any VPS, for example we tested it on AWS EC2 in us-east-1 Data Center (USA).
This guide is compatible with providing IPv6 protocol via tunnel out of the box: on each client it creates routes for both IPv4 and IPv6 addresses, however to use IPv6 you have to make sure your server has IPv6 address too.
On new host, install openvpn:
sudo apt install openvpn
Open file in editor:
sudo nano /etc/openvpn/server.conf
Paste/replace content with next:
port 888
# transmit encapsulated tunnel traffic over TCP or UDP?
;proto tcp
proto udp
dev tun
# SSL/TLS root certificate (ca), certificate (cert), and private key (key).
# Each client and the server must have their own cert and key file.
# The server and all clients will use the same ca file.
# See the "easy-rsa" directory for a series of scripts for generating RSA certificates
# and private keys. Remember to use a unique Common Name for the server
# and each of the client certificates.
ca keys/ca.crt
cert keys/server.crt
# This file should be kept secret
key keys/server.key
# Diffie hellman parameters. we don't use it because use EC instead
dh none
# Network topology. Should be subnet (addressing via IP)
# unless Windows clients v2.0.9 and lower have to be supported
# (then net30, i.e. a /30 per client). Defaults to net30 (not recommended)
topology subnet
# Configure server mode and supply a VPN subnet for OpenVPN to draw client addresses
# from. The server will take 10.8.0.1 for itself, the rest will be made available
# to clients. Each client will be able to reach the server on 10.8.0.1.
# Comment this line out if you are ethernet bridging. See the man page for more info.
server 10.8.0.0 255.255.255.0
# IPv6 subnet
server-ipv6 2001:db8:0:123::/64
crl-verify keys/crl.pem
# Push routes to the client to allow it to reach other private subnets behind
# the server. Remember that these private subnets will also need to know to route
# the OpenVPN client address pool (10.8.0.0/255.255.255.0) back to the OpenVPN server.
;push "route 192.168.10.0 255.255.255.0"
;push "route 192.168.20.0 255.255.255.0"
# To assign specific IP addresses to specific clients or if a connecting client
# has a private subnet behind it that should also have VPN access, use subdirectory
# "ccd" for client-specific configuration files (see man page for more info).
# Uncomment this directive if multiple clients
# might connect with the same certificate/key
# files or common names. This is recommended
# only for testing purposes. For production use,
# each client should have its own certificate/key
# pair.
#
# IF YOU HAVE NOT GENERATED INDIVIDUAL
# CERTIFICATE/KEY PAIRS FOR EACH CLIENT,
# EACH HAVING ITS OWN UNIQUE "COMMON NAME",
# UNCOMMENT THIS LINE OUT.
duplicate-cn
# If enabled, this directive will configure
# all clients to redirect their default
# network gateway through the VPN, causing
# all IP traffic such as web browsing and
# and DNS lookups to go through the VPN
# (The OpenVPN server machine may need to NAT
# or bridge the TUN/TAP interface to the internet
# in order for this to work properly).
push "redirect-gateway ipv6 def1 bypass-dhcp"
# The addresses below refer to the public DNS servers
push "dhcp-option DNS 8.8.8.8"
push "dhcp-option DNS 8.8.4.4"push "dhcp-option DNS 2001:4860:4860:0:0:0:0:8888"
push "dhcp-option DNS 2001:4860:4860:0:0:0:0:8844"
# The keepalive directive causes ping-like messages to be sent back and forth over
# the link so that each side knows when the other side has gone down.
# Ping every 10 seconds, assume that remote peer is down if no ping received during
# a 40 second time period.
keepalive 10 40
# For extra security beyond that provided by SSL/TLS, create an "HMAC firewall"
# to help block DoS attacks and UDP port flooding. Generate with:
# openvpn --genkey --secret ta.key
#
# The server and each client must have a copy of this key.
# The second parameter should be '0' on the server and '1' on the clients.
;tls-auth ta.key 0 # This file is secret
tls-crypt keys/ta.key
# Select a cryptographic cipher. This config item must be same in client config
cipher BF-CBC # Blowfish (default)
;cipher DES-EDE3-CBC # Triple-DES
;cipher AES-256-GCM # AES 256 - for openvpn version 2.4+
auth SHA256
# Enable compression on the VPN link. If you enable it here, you must also
# enable it in the client config file.
comp-lzo
# It's a good idea to reduce the OpenVPN daemon's privileges after initialization.
# You can comment this out on Windows systems.
user nobody
group nogroup
# The persist options will try to avoid accessing certain resources on restart
# that may no longer be accessible because of the privilege downgrade.
persist-key
persist-tun
# Output a short status file showing current connections, truncated
# and rewritten every minute.
status /tmp/openvpn-status.log 3
# Set the appropriate level of log file verbosity.
#
# 0 is silent, except for fatal errors
# 4 is reasonable for general usage
# 5 and 6 can help to debug connection problems
# 9 is extremely verbose
verb 3
tun-mtu 1500
mssfix
If you prefer run tunnel over TCP instead of UDP change proto udp
to proto tcp
. But generally UDP is preferable because:
- In case of using TCP for tunnel, all TCP traffic on system will be wrapped in TCP twice causing overhead (slowing down all)
- When UDP is used for tunnel, system TCP reliability is still same: TCP retries work on top of underlinable protocol
- One reason you might want TCP is when provider in your country tries to recognize a VPN traffic. Even if you using custom port then still might catch it. However much less providers expect to see Openvpn over TCP 😉
Read carefully line by line config to understand which keys/certificates to create and how.
🔑 Adding EasyRSA and generating server key
Install easy RSA:
sudo apt install easy-rsa
Easy RSA installs to /usr/share, and we need to copy it to openvpn dir:
cd /etc/openvpn/
sudo cp -r /usr/share/easy-rsa/ .
Now let's start keys generation:
cd /etc/openvpn/easy-rsa
sudo cp vars.example vars
sudo nano vars
Find set_vars section which starts with:
set_var EASYRSA_REQ_COUNTRY
And change to your parameters (Company country, name, email address, for big companies it will help openvpn users find you as administrator). Also found ALGO and DIGEST vars and change them to:
set_var EASYRSA_ALGO "ec"
set_var EASYRSA_DIGEST "sha512"
EC means much faster Elliptic Curve algorithms used when establishing connection (Standard is Diffie-Hellman's classic RSA).
sudo ./easyrsa init-pki
⚠️ Init PKI removes pki folder and everything that was created there before
Generate pki/ca.crt:
sudo ./easyrsa build-ca nopass
🧠 nopass disables ca.crt file encryption: Certificate Authority (ca.crt) is used to sign other certificates and make them Authoritative. In theory CA could be generated on absolutely different host then your VPN server (and in different PKI environment as a consequence), but then, later, you should supply .req files to CA host, run special command to import them "./easyrsa import-req copied_server.req server" and sign certs there. However after this you will still have to pass ca.crt back to openvpn server so openvpn will be able to verify that they signed by CA provided. In this case we recommend remove nopass in build-ca command
Generate pki/server.key + reqs/server.req:
sudo ./easyrsa gen-req server nopass
Press enter every time when it asks for confirmation.
Sign the server certificate:
sudo ./easyrsa sign-req server server
Now copy signed server key and CA to new keys directory:
sudo mkdir /etc/openvpn/keys
sudo cp pki/private/server.key /etc/openvpn/keys/
sudo cp pki/issued/server.crt /etc/openvpn/keys/
sudo cp pki/ca.crt /etc/openvpn/keys/
Also generate TA:
sudo openvpn --genkey secret /etc/openvpn/keys/ta.key
Also generate cr.pem :
EASYRSA_CRL_DAYS=3650 sudo ./easyrsa gen-crl
And copy it to keys:
sudo cp pki/crl.pem /etc/openvpn/keys/
CRL file used to hold list of revoked certificates. What does revoke mean: since you issued certificate it will be valid until it's expiration time (10 years default). So this works like blacklist: your crl.pem will hold list of restricted certificates, but not generate it manually, check for "Revoke client" at bottom of this hint
Starting OpenVPN server
Start and enable service:
sudo systemctl start openvpn@server
sudo systemctl enable openvpn@server
Edit sysctl.conf
:
sudo nano /etc/sysctl.conf
Find net.ipv4.ip_forward
and net.ipv6.conf.all.forwarding = 1
and set both to 1. Add or edit these line (most likely they might be just commented):
net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding = 1
Apply instantly:
sudo sysctl -p
Now we need to find your primary adapter which is used in your current default route (network interface). So now all connections to the internet done via this adapter. Run:
ip route | grep default
Most often it called enpX
or ethX
or ensX
like in my case:
Now edit the UFW before config:
sudo nano /etc/ufw/before.rules
If your before.rules
If the file is empty then add next content "AS IS", otherwise (like on AWS EC2 instances often happens), just add it to the bottom.
*nat
is section name,COMMIT
is the end of the section.
If you already have such a section, you need to merge it by changing ens0 in a POSTROUTING
to your adapter name.
# START OPENVPN RULES
# # NAT table rules
*nat
:POSTROUTING ACCEPT [0:0]
# Allow traffic from OpenVPN client to ADAPTER (change to the interface you discovered!)
-A POSTROUTING -s 10.8.0.0/8 -o ens0 -j MASQUERADE
COMMIT
# # END OPENVPN RULES1~
⚠️ Don't forget to replaceens0
in code above with your adapter e.g.ens2
Also, add a MASQUERADE
rule for ipv6 routing:
sudo nano /etc/ufw/before6.rules
Add next:
*nat
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -s 2001:db8:0:123::/64 -o ens5 -j MASQUERADE
# don't delete the 'COMMIT' line or these rules won't be processed
COMMIT
Also edit:
sudo nano /etc/default/ufw
Find and change DEFAULT_FORWARD_POLICY
to accept:
DEFAULT_FORWARD_POLICY="ACCEPT"
Now apply UFW rules:
(if you configured drive tunnel in a config above over TCP then change 888/udp
to 888/tcp
)
sudo ufw allow 888/udp
sudo ufw allow OpenSSH
sudo ufw disable
sudo ufw enable
sudo ufw reload
Generating client's config and keys
To generate certificates for clients create this file:
sudo nano /etc/openvpn/build-client-key.sh
Change <YOUR_VPN_HOST_OR_IP>
to your host or IP address. For example it could be 1.2.3.4
or vpn.host.com
Content:
#!/bin/bash
function build_client_key {
CLIENT_NAME=$1
pushd easy-rsa
export KEY_NAME=$CLIENT_NAME
echo -ne '\n' | ./easyrsa gen-req $CLIENT_NAME nopass
echo -ne 'yes' | ./easyrsa sign-req client $CLIENT_NAME
popd
mkdir -p clients/$CLIENT_NAME/tun_$CLIENT_NAME
mv easy-rsa/pki/issued/$CLIENT_NAME.crt clients/$CLIENT_NAME/tun_$CLIENT_NAME/
mv easy-rsa/pki/private/$CLIENT_NAME.key clients/$CLIENT_NAME/tun_$CLIENT_NAME/
cp keys/ca.crt clients/$CLIENT_NAME/tun_$CLIENT_NAME/
cp keys/ta.key clients/$CLIENT_NAME/tun_$CLIENT_NAME/
GREP_BEGIN_END='(?P<dashes>-+)\s?BEGIN\s(?P<name>.+)(?P=dashes)\s(.+\s)+?(?P=dashes)\s?END\s(?P=name)(?P=dashes)'
cat << EOF > clients/$CLIENT_NAME/tun_$CLIENT_NAME.ovpn
client
dev tun_$CLIENT_NAME
proto udp
remote <YOUR_VPN_HOST_OR_IP> 888 # Your IP or host here
cipher BF-CBC
resolv-retry infinite
nobind
persist-key
persist-tun
comp-lzo
mute-replay-warnings
verb 3
reneg-sec 900
mute 20
key-direction 1
#status /var/log/tun_$CLIENT_NAME.status
<ca>
`cat clients/$CLIENT_NAME/tun_$CLIENT_NAME/ca.crt`
</ca>
<cert>
`cat clients/$CLIENT_NAME/tun_$CLIENT_NAME/$CLIENT_NAME.crt`
</cert>
<key>
`cat clients/$CLIENT_NAME/tun_$CLIENT_NAME/$CLIENT_NAME.key`
</key>
<tls-crypt>
`cat clients/$CLIENT_NAME/tun_$CLIENT_NAME/ta.key`
</tls-crypt>
EOF
pushd clients
# tar zcvf tun_$CLIENT_NAME.tar.gz $CLIENT_NAME
popd
}
export -f build_client_key
bash -c "build_client_key $@"
Make file executable:
sudo chmod +x /etc/openvpn/build-client-key.sh
To create a client:
cd /etc/openvpn/
/etc/openvpn/build-client-key.sh johndoe
Where johndoe is your or your colleague which need to work through VPN server. Then find file .ovpn
in clients folder:
ls clinets/johndoe
And transfer it from server to user via scp/ftp
or in any other way you can to John.
This file already has all certificates built-in so it will be super-easy to transfer this simple text file, especially assuming the fact that in most operations systems .ovpn
files could be easily imported in internal network managers.
Revoke client
Once johndoe lefts your organisation you will definitely want to revoke his certificate to restrict his access.
cd /etc/openvpn/easy-rsa/
sudo ./easyrsa revoke johndoe
sudo ./easyrsa gen-crl
sudo cp pki/crl.pem /etc/openvpn/keys/