How to install and use OpenVPN
Note:
This documentation has moved to a new home! Please update your bookmarks to the new URL for the up-to-date version of this page.
OpenVPN is a flexible, reliable and secure Virtual Private Networking (VPN) solution. It belongs to the family of SSL/TLS VPN stacks (different from IPSec VPNs). This chapter will show how to install and configure OpenVPN to create a VPN.
Install the server
To install OpenVPN, run the following command in your terminal:
sudo apt install openvpn easy-rsa
Set up the Public Key Infrastructure (PKI)
If you need more than just pre-shared keys, OpenVPN allows you to set up a Public Key Infrastructure (PKI) to use SSL/TLS certificates for authentication and key exchange between the VPN server and clients.
OpenVPN can operate in either routed or bridged VPN mode and supports both UDP and TCP. While you can configure a different port, port 1194 is the default for all communication. VPN clients are available for most platforms, including Linux distributions, macOS, Windows, and OpenWRT-based routers.
To begin configuring OpenVPN, you need to establish a PKI, which involves:
- Generating a separate certificate (public key) and private key for the server and each client.
- Creating a primary Certificate Authority (CA) certificate and key to sign the server and client certificates.
OpenVPN supports bi-directional authentication, where the client authenticates the server certificate, and the server authenticates the client certificate, ensuring mutual trust.
Both the server and client authenticate each other by verifying that the certificate was signed by the primary CA and then by checking details in the authenticated certificate, such as the common name or certificate type.
Set Up the Certificate Authority
To set up your own CA and generate certificates and keys for an OpenVPN server with multiple clients, first, copy the easy-rsa directory to /etc/openvpn to preserve any changes made to the scripts during package updates. From your terminal, run:
sudo make-cadir /etc/openvpn/easy-rsa
Note:
You can alternatively edit /etc/openvpn/easy-rsa/vars directly, adjusting it to your needs.
As a root user, change to the newly created directory /etc/openvpn/easy-rsa and run:
./easyrsa init-pki
./easyrsa build-ca
The PEM passphrase set when creating the CA will be required each time you need to encrypt the output of a command (such as when dealing with a private key). This encryption helps protect sensitive information from being exposed in plain text.
Create Server Keys and Certificates
Next, you will generate a key pair for the server. Use the following commands:
./easyrsa gen-req myservername nopass
Diffie-Hellman parameters must be generated for the OpenVPN server to ensure secure key exchange. Use the following command to generate these parameters:
./easyrsa gen-dh
This command will create a dh.pem file in the pki directory, which is essential for the secure establishment of VPN connections.
And finally, create a certificate for the server:
./easyrsa sign-req server myservername
All certificates and keys have been generated in subdirectories. Common practice is to copy them to /etc/openvpn/:
cp pki/dh.pem pki/ca.crt pki/issued/myservername.crt pki/private/myservername.key /etc/openvpn/
Create client certificates:
The VPN client will also need a certificate to authenticate itself to the server. Typically, a different certificate is created for each client.
This can be done either on the server (as with the keys and certificates above) and then securely distributed to the client, or the client can generate and submit a request that is signed by the server.
To create the certificate, enter the following in a terminal as a root user:
./easyrsa gen-req myclient1 nopass
./easyrsa sign-req client myclient1
If the first command was executed on a remote system, you need to copy the .req file to the CA server. From there, you can import it using:
sudo ./easyrsa import-req /incoming/myclient1.req myclient17
Then, proceed with the signing command:
sudo ./easyrsa sign-req client myclient1
After this is done, in both cases you will need to copy the following files to the client using a secure method:
pki/ca.crt
pki/issued/myclient1.crt
Since the client certificates and keys are only required on the client machine, you can remove them from the server.
Simple server configuration
Included with your OpenVPN installation are these (and many more) sample configuration files:
root@server:/# ls -l /usr/share/doc/openvpn/examples/sample-config-files/
total 68
-rw-r–r– 1 root root 3427 2011-07-04 15:09 client.conf
-rw-r–r– 1 root root 4141 2011-07-04 15:09 server.conf.gz
Start by copying and unpacking server.conf.gz to /etc/openvpn/server.conf:
sudo cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz /etc/openvpn/myserver.conf.gz
sudo gzip -d /etc/openvpn/myserver.conf.gz
Edit /etc/openvpn/myserver.conf to ensure the following lines point to the certificates and keys you created earlier:
ca ca.crt
cert myservername.crt
key myservername.key
dh dh2048.pem
Complete this setup by adding a TLS Authentication (TA) key in /etc/openvpn for tls-auth as follows:
sudo openvpn –genkey –secret ta.key
Edit /etc/sysctl.conf and uncomment the following line to enable IP forwarding:
#net.ipv4.ip_forward=1
Then reload sysctl:
sudo sysctl -p /etc/sysctl.conf
This is the minimum configuration required to set up a functional OpenVPN server. You can use the default settings provided in the sample server.conf file. Now, you can start the server.
$ sudo systemctl start openvpn@myserver
Note: Keep in mind that the systemctl start openvpn command does not start the specific OpenVPN configuration you defined. OpenVPN uses templated systemd jobs, named openvpn@CONFIGFILENAME. For instance, if your configuration file is named myserver.conf, you should use the service called openvpn@myserver. You can manage these services with commands such as start, stop, enable, disable, and preset using the openvpn@ template.
You will find logging and error messages in the journal. For example, if you started a templated service openvpn@server you can filter for this particular message source with:
sudo journalctl -u openvpn@myserver -xe
The same templated approach applies to all of systemctl’s commands. For instance, to manage a specific OpenVPN configuration file named myserver.conf, you would use commands like:
$ sudo systemctl status openvpn@myserver
[email protected] – OpenVPN connection to myserver
Loaded: loaded (/lib/systemd/system/[email protected]; disabled; vendor preset: enabled)
Active: active (running) since Thu 2019-10-24 10:59:25 UTC; 10s ago
Docs: man:openvpn(8)
https://community.openvpn.net/openvpn/wiki/Openvpn24ManPage
https://community.openvpn.net/openvpn/wiki/HOWTO
Main PID: 4138 (openvpn)
Status: “Initialization Sequence Completed”
Tasks: 1 (limit: 533)
Memory: 1.0M
CGroup: /system.slice/system-openvpn.slice/[email protected]
└─4138 /usr/sbin/openvpn –daemon ovpn-myserver –status /run/openvpn/myserver.status 10 –cd /etc/openvpn –script-security 2 –config /etc/openvpn/myserver.conf –writepid /run/Oct 24 10:59:26 eoan-vpn-server ovpn-myserver[4138]: /sbin/ip addr add dev tun0 local 10.8.0.1 peer 10.8.0.2
Oct 24 10:59:26 eoan-vpn-server ovpn-myserver[4138]: /sbin/ip route add 10.8.0.0/24 via 10.8.0.2
Oct 24 10:59:26 eoan-vpn-server ovpn-myserver[4138]: Could not determine IPv4/IPv6 protocol. Using AF_INET
Oct 24 10:59:26 eoan-vpn-server ovpn-myserver[4138]: Socket Buffers: R=[212992->212992] S=[212992->212992]
Oct 24You can enable or disable various OpenVPN services on your system, and you can also let Ubuntu manage this for you. The configuration for AUTOSTART can be found in /etc/default/openvpn. The allowed values are:
all to start all VPNs.
none to disable all VPNs.
A space-separated list of VPN configuration file names if you want to selectively start specific VPNs.
If the AUTOSTART variable is empty, it defaults to all. The VPN name refers to the configuration file name without the .conf extension, so a file like /etc/openvpn/home.conf would use home as its name.
If you are using systemd, changes to this variable require running systemctl daemon-reload followed by restarting the OpenVPN service. If you removed any entries, you may need to stop those services manually.
After running systemctl daemon-reload, restarting the “generic” OpenVPN service will also restart all dependent services created by the systemd generator in /lib/systemd/system-generators/openvpn-generator.
Finally, check if OpenVPN has created a tun0 interface by running the appropriate command for your system.
10:59:26 eoan-vpn-server ovpn-myserver[4138]: UDPv4 link local (bound): [AF_INET][undef]:1194
Oct 24 10:59:26 eoan-vpn-server ovpn-myserver[4138]: UDPv4 link remote: [AF_UNSPEC]
Oct 24 10:59:26 eoan-vpn-server ovpn-myserver[4138]: MULTI: multi_init called, r=256 v=256
Oct 24 10:59:26 eoan-vpn-server ovpn-myserver[4138]: IFCONFIG POOL: base=10.8.0.4 size=62, ipv6=0
Oct 24 10:59:26 eoan-vpn-server ovpn-myserver[4138]: IFCONFIG POOL LIST
Oct 24 10:59:26 eoan-vpn-server ovpn-myserver[4138]: Initialization Sequence Completedroot@server:/etc/openvpn# ip addr show dev tun0
5: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 100
link/none
inet 10.8.0.1 peer 10.8.0.2/32 scope global tun0
valid_lft forever preferred_lft forever
inet6 fe80::b5ac:7829:f31e:32c5/64 scope link stable-privacy
valid_lft forever preferred_lft forever
Simple client configuration
There are several OpenVPN client implementations available, some with graphical user interfaces (GUIs) and others that are command-line based. For more information on different clients, you can refer to our page on OpenVPN Clients.
For now, we’ll use the command-line OpenVPN client for Ubuntu, which is included in the same package as the server. Therefore, you’ll need to install the openvpn package on the client machine as well.
sudo apt install openvpn
Copy the client.conf sample configuration file to /etc/openvpn/ on the client machine:
sudo cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf /etc/openvpn/
Copy the client keys and certificate files you created earlier to /etc/openvpn/, then edit /etc/openvpn/client.conf to ensure the following lines point to those files. If the files are in /etc/openvpn/, you can omit the path:
ca ca.crt
cert myclient1.crt
key myclient1.key
tls-auth ta.key 1
Make sure the file names and paths match those used on your system.
And you have to specify the OpenVPN server name or address. Make sure the keyword client is in the config file, since that’s what enables client mode.
client
remote vpnserver.example.com 1194
Start the OpenVPN client using the templated mechanism with the following command:
$ sudo systemctl start openvpn@client
To check the status of the OpenVPN client, use the following command:
$ sudo systemctl status openvpn@client
[email protected] – OpenVPN connection to client
Loaded: loaded (/lib/systemd/system/[email protected]; disabled; vendor preset: enabled)
Active: active (running) since Thu 2019-10-24 11:42:35 UTC; 6s ago
Docs: man:openvpn(8)
https://community.openvpn.net/openvpn/wiki/Openvpn24ManPage
https://community.openvpn.net/openvpn/wiki/HOWTO
Main PID: 3616 (openvpn)
Status: “Initialization Sequence Completed”
Tasks: 1 (limit: 533)
Memory: 1.3M
CGroup: /system.slice/system-openvpn.slice/[email protected]
└─3616 /usr/sbin/openvpn –daemon ovpn-client –status /run/openvpn/client.status 10 –cd /etc/openvpn –script-security 2 –config /etc/openvpn/client.conf –writepid /run/openvpOct 24 11:42:36 eoan-vpn-client ovpn-client[3616]: Outgoing Data Channel: Cipher ‘AES-256-GCM’ initialized with 256 bit key
Oct 24 11:42:36 eoan-vpn-client ovpn-client[3616]: Incoming Data Channel: Cipher ‘AES-256-GCM’ initialized with 256 bit key
Oct 24 11:42:36 eoan-vpn-client ovpn-client[3616]: ROUTE_GATEWAY 192.168.122.1/255.255.255.0 IFACE=ens3 HWADDR=52:54:00:3c:5a:88
Oct 24 11:42:36 eoan-vpn-client ovpn-client[3616]: TUN/TAP device tun0 opened
Oct 24 11:42:36 eoan-vpn-client ovpn-client[3616]: TUN/TAP TX queue length set to 100
Oct 24 11:42:36 eoan-vpn-client ovpn-client[3616]: /sbin/ip link set dev tun0 up mtu 1500
Oct 24 11:42:36 eoan-vpn-client ovpn-client[3616]: /sbin/ip addr add dev tun0 local 10.8.0.6 peer 10.8.0.5
Oct 24 11:42:36 eoan-vpn-client ovpn-client[3616]: /sbin/ip route add 10.8.0.1/32 via 10.8.0.5
Oct 24 11:42:36 eoan-vpn-client ovpn-client[3616]: WARNING: this configuration may cache passwords in memory — use the auth-nocache option to prevent this
Oct 24 11:42:36 eoan-vpn-client ovpn-client[3616]: Initialization Sequence Completed
On the server log, an incoming connection might look like this:
ovpn-myserver[4818]: 192.168.122.114:55738 TLS: Initial packet from [AF_INET]192.168.122.114:55738, sid=5e943ab8 40ab9fed
ovpn-myserver[4818]: 192.168.122.114:55738 VERIFY OK: depth=1, CN=Easy-RSA CA
ovpn-myserver[4818]: 192.168.122.114:55738 VERIFY OK: depth=0, CN=myclient1
ovpn-myserver[4818]: 192.168.122.114:55738 peer info: IV_VER=2.4.7
ovpn-myserver[4818]: 192.168.122.114:55738 peer info: IV_PLAT=linux
ovpn-myserver[4818]: 192.168.122.114:55738 peer info: IV_PROTO=2
ovpn-myserver[4818]: 192.168.122.114:55738 peer info: IV_NCP=2
ovpn-myserver[4818]: 192.168.122.114:55738 peer info: IV_LZ4=1
ovpn-myserver[4818]: 192.168.122.114:55738 peer info: IV_LZ4v2=1
ovpn-myserver[4818]: 192.168.122.114:55738 peer info: IV_LZO=1
ovpn-myserver[4818]: 192.168.122.114:55738 peer info: IV_COMP_STUB=1
ovpn-myserver[4818]: 192.168.122.114:55738 peer info: IV_COMP_STUBv2=1
ovpn-myserver[4818]: 192.168.122.114:55738 peer info: IV_TCPNL=1
ovpn-myserver[4818]: 192.168.122.114:55738 Control Channel: TLSv1.3, cipher TLSv1.3 TLS_AES_256_GCM_SHA384, 2048 bit RSA
ovpn-myserver[4818]: 192.168.122.114:55738 [myclient1] Peer Connection Initiated with [AF_INET]192.168.122.114:55738
ovpn-myserver[4818]: myclient1/192.168.122.114:55738 MULTI_sva: pool returned IPv4=10.8.0.6, IPv6=(Not enabled)
ovpn-myserver[4818]: myclient1/192.168.122.114:55738 MULTI: Learn: 10.8.0.6 -> myclient1/192.168.122.114:55738
ovpn-myserver[4818]: myclient1/192.168.122.114:55738 MULTI: primary virtual IP for myclient1/192.168.122.114:55738: 10.8.0.6
ovpn-myserver[4818]: myclient1/192.168.122.114:55738 PUSH: Received control message: ‘PUSH_REQUEST’
ovpn-myserver[4818]: myclient1/192.168.122.114:55738 SENT CONTROL [myclient1]: ‘PUSH_REPLY,route 10.8.0.1,topology net30,ping 10,ping-restart 120,ifconfig 10.8.0.6 10.8.0.5,peer-id 0,cipher AES-256-GCM’ (status=1)
ovpn-myserver[4818]: myclient1/192.168.122.114:55738 Data Channel: using negotiated cipher ‘AES-256-GCM’
ovpn-myserver[4818]: myclient1/192.168.122.114:55738 Outgoing Data Channel: Cipher ‘AES-256-GCM’ initialized with 256 bit key
ovpn-myserver[4818]: myclient1/192.168.122.114:55738 Incoming Data Channel: Cipher ‘AES-256-GCM’ initialized with 256 bit key
On the client, you can check if it created a tun0 interface with the following command:
$ ip addr show dev tun0
4: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 100
link/none
inet 10.8.0.6 peer 10.8.0.5/32 scope global tun0
valid_lft forever preferred_lft forever
inet6 fe80::5a94:ae12:8901:5a75/64 scope link stable-privacy
valid_lft forever preferred_lft forever
To check if you can ping the OpenVPN server from the client, use the following command:
root@client:/etc/openvpn# ping 10.8.0.1
PING 10.8.0.1 (10.8.0.1) 56(84) bytes of data.
64 bytes from 10.8.0.1: icmp_req=1 ttl=64 time=0.920 msNote: The OpenVPN server always uses the first available IP address in the client network, and only that IP address will respond to pings. For example, if you set up a /24 subnet for the client network, the .1 address will be utilized. The point-to-point address shown in the ip addr output typically does not respond to ping requests.
Review your routes:
$ ip route
default via 192.168.122.1 dev ens3 proto dhcp src 192.168.122.114 metric 100
10.8.0.1 via 10.8.0.5 dev tun0
10.8.0.5 dev tun0 proto kernel scope link src 10.8.0.6
192.168.122.0/24 dev ens3 proto kernel scope link src 192.168.122.114
192.168.122.1 dev ens3 proto dhcp scope link src 192.168.122.114 metric 100
First troubleshooting
If the above steps didn’t resolve the issue, try the following:
Check your journal with journal -xe.
Ensure that the key filenames are correctly specified in both the client and server configuration files.
Verify if the client can connect to the server machine; a firewall might be blocking access. Check the server’s journal for any related messages.
Both the client and server must use the same protocol and port (e.g., UDP port 1194). Refer to the port and proto configuration options.
Both must have the same compression settings. Check the comp-lzo configuration option.
Ensure that both client and server are configured consistently regarding bridged vs. routed mode, referring to server vs. server-bridge configuration options.
Advanced configuration.
Advanced Routed VPN Configuration on the Server
The setup described above is a basic, functional VPN where the client can access services on the VPN server through an encrypted tunnel. If you need to access additional servers or other networks, you’ll need to push routes to the clients. For instance, if your company’s network can be summarized as 192.168.0.0/16, you could push this route to the clients. However, you must also adjust the routing for the return path—your servers need to be aware of a route to the VPN client network.
The example configuration files provided in this guide include these advanced options as comments and disabled configuration lines for reference.
Note: Refer to the OpenVPN hardening security guide for additional security recommendations.
Advanced bridged VPN configuration on server
OpenVPN can be configured for either routed or bridged VPN modes, sometimes referred to as OSI layer-2 versus layer-3 VPNs. In bridged VPN mode, all layer-2 frames, such as Ethernet frames, are transmitted to the VPN peers. In contrast, in routed VPN mode, only layer-3 packets are sent to the VPN peers. In bridged mode, all types of traffic—including traditionally LAN-local traffic like broadcasts, DHCP requests, and ARP requests—are forwarded to VPN partners. In routed mode, however, such traffic would be filtered out.
Prepare interface config for bridging on server
First, use Netplan to configure a bridge device with the desired Ethernet device:
$ cat /etc/netplan/01-netcfg.yaml
network:
version: 2
renderer: networkd
ethernets:
enp0s31f6:
dhcp4: no
bridges:
br0:
interfaces: [enp0s31f6]
dhcp4: no
addresses: [10.0.1.100/24]
gateway4: 10.0.1.1
nameservers:
addresses: [10.0.1.1]
Static IP addressing is highly recommended. Although DHCP addressing can also be used, you will need to specify a static address in the OpenVPN configuration file.
The next step on the server is to configure the Ethernet device for promiscuous mode on boot. To achieve this, ensure that the networkd-dispatcher package is installed and create the following configuration script:
sudo apt update
sudo apt install networkd-dispatcher
sudo touch /usr/lib/networkd-dispatcher/dormant.d/promisc_bridge
sudo chmod +x /usr/lib/networkd-dispatcher/dormant.d/promisc_bridge
Then add the following contents:
#!/bin/sh
set -e
if [ “$IFACE” = br0 ]; then
# no networkd-dispatcher event for ‘carrier’ on the physical interface
ip link set enp0s31f6 up promisc on
fi
Prepare server config for bridging
Edit /etc/openvpn/server.conf to use tap instead of tun and set the server to use the server-bridge directive:
;dev tun
dev tap
;server 10.8.0.0 255.255.255.0
server-bridge 10.0.0.4 255.255.255.0 10.0.0.128 10.0.0.254
After configuring the server, restart OpenVPN by entering:
sudo systemctl restart openvpn@myserver
Prepare client config for bridging
The only change required on the client side for bridged mode compared to the previous configuration is to edit /etc/openvpn/client.conf and set it to use tap mode:
dev tap
;dev tun
Finally, restart OpenVPN:
sudo systemctl restart openvpn@client
You should now be able to connect to the fully remote LAN through the VPN.