Networks B12
How to Set Up an OpenVPN Server on Azure (Updated)
Part of OpenVPN on Azure · Part 2
This is an updated version of my previous article How to Set Up an OpenVPN Server on Azure to support configuring OpenVPN on Ubuntu 22.04, since many changes have happened in Easy-RSA.
Prerequisites
- An Ubuntu 22.04 VM deployed in Azure with at least one NIC that has a public IP address enabled.
- A user with sudo privileges on the Ubuntu 22.04 VM.
- The VM private IP address does not overlap with subnet 172.16.0.0/24.
- An NSG rule is added to the VM to allow UDP destination port 32768.
Install OpenVPN & Easy-RSA
# install openvpn & easy-rsa
sudo apt update
sudo apt install openvpn easy-rsa net-tools
# configure easy-rsa
make-cadir ~/openvpn-ca
Configure the vars file to include the required settings.
cd ~/openvpn-ca
vi vars
set_var EASYRSA_REQ_COUNTRY “SG”
set_var EASYRSA_REQ_PROVINCE “Singapore”
set_var EASYRSA_REQ_CITY “Singapore”
set_var EASYRSA_REQ_ORG “Your Org”
set_var EASYRSA_REQ_EMAIL “admin@example.com”
set_var EASYRSA_REQ_OU “Your OU”
set_var EASYRSA_KEY_SIZE 2048
set_var EASYRSA_CA_EXPIRE 36500
set_var EASYRSA_CERT_EXPIRE 3650
set_var EASYRSA_REQ_CN “OpenVPN-CA”
set_var EASYRSA_BATCH “1”
Set Up CA & Configure OpenVPN
Set up the CA.
export EASYRSA_BATCH=1
./easyrsa init-pki
./easyrsa build-ca nopass
When bash asks for “Common Name”, enter “OpenVPN-CA”, then execute the following commands to generate the server certificate:
./easyrsa gen-req ovpn nopass
./easyrsa sign-req server ovpn
./easyrsa gen-dh
openvpn --genkey secret pki/ta.key
Move certificates and keys to the OpenVPN /etc directory and create a user that represents OpenVPN.
sudo cp pki/ca.crt pki/ta.key pki/dh.pem pki/issued/ovpn.crt pki/private/ovpn.key /etc/openvpn/server
sudo adduser --system --shell /usr/sbin/nologin --no-create-home openvpn
Configure OpenVPN
sudo vi /etc/openvpn/server/server.conf
# OpenVPN listening address
local 10.0.0.4
# OpenVPN listening port
port 32768
# tcp/udp
proto udp
dev tun
ca ca.crt
cert ovpn.crt
key ovpn.key
dh dh.pem
# OpenVPN network
server 172.16.0.0 255.255.255.0
ifconfig-pool-persist ipp.txt
# Redirect all traffic to OpenVPN
push "redirect-gateway def1 bypass-dhcp"
push "dhcp-option DNS 8.8.8.8"
push "dhcp-option DNS 8.8.8.4"
keepalive 10 120
# This file is secret
tls-auth ta.key 0
# Cipher settings
cipher AES-256-GCM
auth SHA512
tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-256-CBC-SHA:TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA:TLS-DHE-RSA-WITH-AES-128-CBC-SHA:TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA
comp-lzo
user openvpn
group nogroup
persist-key
persist-tun
log /var/log/openvpn/server.log
log-append server.log
verb 4
Add iptables rules to NAT OpenVPN traffic.
# iptables configuration for openvpn
sudo iptables -A INPUT -i eth0 -p udp -m state --state NEW -m udp --dport 32768 -j ACCEPT
sudo iptables -A INPUT -i tun+ -j ACCEPT
sudo iptables -A FORWARD -i tun+ -j ACCEPT
sudo iptables -A OUTPUT -o tun+ -j ACCEPT
sudo iptables -A FORWARD -i tun+ -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo iptables -A FORWARD -i eth0 -o tun+ -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo iptables -t nat -A POSTROUTING -s 172.16.0.0/24 -o eth0 -j MASQUERADE
sudo bash -c "echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.conf"
sudo sysctl -p
Use iptables-persistent to save iptables rules.
sudo apt install iptables-persistent
Start and enable the OpenVPN server service.
sudo systemctl start openvpn-server@server
sudo systemctl status openvpn-server@server
sudo systemctl enable openvpn-server@server
Generate Client Profile and Connect to OpenVPN Service
Create a shell script to generate the client profile.
cd ~
vi genprofile.sh
Add the following lines to genprofile.sh.
#!/bin/bash
export EASYRSA_BATCH=1
cd ~/openvpn-ca
./easyrsa gen-req $1 nopass
./easyrsa sign-req client $1
cd ~/client-configs
./make_config.sh $1
Press “ESC”, type “:wq” to save the file
chmod +x genprofile.sh
Create a new directory called “client-configs”
mkdir client-configs
mkdir client-configs/files
cd client-configs
Create a base client configuration file “base.conf”
vi base.conf
Add following lines
client
dev tun
proto udp
remote <YOUR_OPENVPN_PUBLIC_IP_OR_DNS_NAME> 32768
resolv-retry infinite
nobind
user nobody
group nogroup
persist-key
persist-tun
remote-cert-tls server
key-direction 1
cipher AES-256-GCM
auth SHA512
comp-lzo
verb 3
ESC, type “:wq” to save the file. Now create a script file called make_config.sh
vi make_config.sh
Add following content into the file
#!/bin/bash
# First argument: Client identifier
KEY_DIR=~/openvpn-ca/pki
OUTPUT_DIR=~/client-configs/files
BASE_CONFIG=~/client-configs/base.conf
cat ${BASE_CONFIG} \
<(echo -e '<ca>') \
${KEY_DIR}/ca.crt \
<(echo -e '</ca>\n<cert>') \
${KEY_DIR}/issued/${1}.crt \
<(echo -e '</cert>\n<key>') \
${KEY_DIR}/private/${1}.key \
<(echo -e '</key>\n<tls-auth>') \
${KEY_DIR}/ta.key \
<(echo -e '</tls-auth>') \
> ${OUTPUT_DIR}/${1}.ovpn
ESC, type “:wq” to save the file
chmod +x make_config.sh
Connect to OpenVPN server from client side
From OpenVPN server, run
./genprofile.sh <profile name>
The command above will generate a client profile and save it into ~/client-configs/files. Copy/download this profile to the client side, then import this profile from OpenVPN and connect.
The client should have an OpenVPN connection established, and it should redirect all traffic to OpenVPN now.
Use Cloud Provider’s Network to Accelerate OpenVPN Connection
If you happen to use a cloud provider and your OpenVPN client is close to one of cloud provider’s regions, you could use your cloud provider’s network to bridge VPN connection between OpenVPN client and OpenVPN server, the benefits are
- Reliable VPN connectivity, cloud provider usually provides dedicated internet link cross border
- Leverage the cloud provider’s global network to accelerate VPN connectivity. Some cloud providers provide hot potato routing by default, such as Azure or GCP. That means VPN traffic usually takes optimal paths.
- Even you are using sovereign cloud, internet quality between your sovereign cloud provider and VPN server, is still better than your home network
Here is a simple solution that uses iptables to bounce traffic from your local cloud data center to the remote VPN server.
- In order to bounce traffic, you should have a Linux VM instance running from your cloud provider’s local data center, for example a Ubuntu server distribution with 1 CPU and 1GB memory should be enough
- Mapping a UDP port from your Linux VM instance to remote OpenVPN server’s port, open NSG to allow that UDP port from your Linux instance. For example, OpenVPN server’s UDP port is 1194, you can map a random UDP port say 11940 from your Linux VM instance to 1194 and open NSG to allow 11940 UDP traffic to pass to your Linux VM instance
- Add two iptables rules from your Linux VM instance
iptables -A PREROUTING -p udp -m udp --dport <Mapped UDP Port> -j DNAT --to-destination <Remote OpenVPN IP>:<Remote OpenVPN Port>
iptables -A POSTROUTING -d <Remote OpenVPN IP>/32 -p udp -m udp --dport <Remote OpenVPN Port> -j SNAT --to-source <Linux VM's IP, usually from eth0> More in OpenVPN on Azure