Setup OpenVPN server on Ubuntu 22.04
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).
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:
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 replaceens0
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 | |
log/tun_$CLIENT_NAME.status | status /var/|
<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 | |
$CLIENT_NAME.tar.gz $CLIENT_NAME | tar zcvf tun_|
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/ |