Learn how to create your own VPN server which will hide your IP and allow you to access websites from any country in the world, for example for testing purposes.

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).

OpenVPN server on Ubuntu

First of all install OpenVPN:

sudo apt install openvpn

Now we need to configure openvpn server.

The OpenVPN server configuration

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?
# UDP - much faster, still reliable because TCP over UDP is still TCP
# TCP - slower but providers who might block VPN don't expect somone uses TCP
;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).
# 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"
# 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 120 second time period.
keepalive 10 120
# 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              1300

If you prefer run tunnel over TCP instead of UDP change proto udp to proto tcp . But generally UDP is preferable because of double TCP overhead in case of running tunnel itself in TCP too.

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 instals 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 paramteres (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 ./easyrsa gen-crl
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 server

Start and enable in systemd

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:

Ip route get default interface

Now edit the UFW before config:

sudo nano /etc/ufw/before.rules

In A POSTROUTING line change ens0 to your adapter.

# 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~
If your before.rules file is empty then add content "AS IS", otherwise, like on AWS EC2 instances oftenly, just add it to the bottom. *nat is section name, COMMIT is end of section. If you already have such section, you need to merge it
⚠️ Don't forget to replace ens0 in code above with your adapter e.g. ens2

Also, add a MASQUERADE rule for ipv6 routing:

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 

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
dev                 tun_$CLIENT_NAME
proto               udp
client
remote              office.devforth.io 888
cipher BF-CBC
auth SHA256
resolv-retry        infinite
persist-key
persist-tun
#ns-cert-type       server
comp-lzo
keepalive           9 30
verb                3
nobind
tun-mtu             1500
mssfix 1300
mute                20
redirect-gateway autolocal
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:

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 operation 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/