Introduction
OpenVPN is an open-source virtual private network (VPN) solution that allows creating secure connections between devices, protecting network traffic from interception. Its flexibility and support for strong encryption make it ideal for businesses and users who need secure remote access or interconnection between networks.
This article details the process of installing and configuring an OpenVPN server and client on Linux, also covering the creation of digital certificates using the Easy-RSA script. The certificate generation process will be presented briefly and technically, focusing on practical application for OpenVPN operation.
For a deeper understanding of certificate management, including conceptual aspects, security criteria, and details on using Easy-RSA, we recommend reading the complementary article:
Installation Environment
The configurations demonstrated in this article were tested on Slackware Linux 15.0 (64-bit), using OpenVPN 2.5.5 and Easy-RSA 3.3.0.
This tutorial can be adapted to other Linux distributions with minor modifications, mainly in the OpenVPN installation command and the method of automatic service startup. Whenever possible, specific commands for different distributions will be presented, but these commands have not been tested.
Otherwise, the steps for downloading Easy-RSA, configurations, and certificate creation should be the same in most distributions.
Installing OpenVPN
OpenVPN is available in the official Slackware repositories.
# bash
# Slackware
slackpkg install openvpn
Commands for installation on other distributions:
# bash
# Debian and Ubuntu sudo apt install openvpn # Fedora sudo dnf install openvpn # Arch Linux sudo pacman -S openvpn # openSUSE sudo zypper install openvpn
Downloading Easy-RSA
Easy-RSA is a script that facilitates the creation and management of keys and certificates necessary for secure communication between client and server. The script should be executed as a regular user, without administrative permissions.
For security reasons, Easy-RSA will be installed on a USB drive, whose path will be represented here by the mount point /mnt/usb. Using a removable device allows keeping the certificate management structure offline, reducing the risk of private key exposure. For more details on the security practices involved, refer to the article mentioned in the introduction.
To download Easy-RSA directly to the USB drive, use the following commands:
$ bash
cd /mnt/usb git clone https://github.com/OpenVPN/easy-rsa
Configuring EasyRSA
Before starting, it is necessary to adjust the value of some default script variables to ensure data consistency during certificate issuance. Make a copy of the example file vars.example to vars:
$ bash
cd easy-rsa/easyrsa3/ cp vars.example vars vi vars
Now, customize the vars file with your favorite editor. Uncomment the lines below and configure with your information:
vars
# Organizational fields set_var EASYRSA_REQ_COUNTRY "US" # Country set_var EASYRSA_REQ_PROVINCE "California" # State set_var EASYRSA_REQ_CITY "Los Angeles" # City set_var EASYRSA_REQ_ORG "My Company" # Organization name set_var EASYRSA_REQ_EMAIL "contact@mycompany.com.br" # Email set_var EASYRSA_REQ_OU "IT Department" # Organizational Unit # Expiration (in days) set_var EASYRSA_CA_EXPIRE 7300 # CA validity set_var EASYRSA_CERT_EXPIRE 3650 # Validity of issued certificates
The first set of variables refers to organizational fields, values that will be incorporated into the issued certificates. The second set of variables defines the expiration time of the (CA) certificate, and the certificates generated for the VPN server and clients.
The other variables present in the vars file should only be changed with prior knowledge of their functions and will not be covered in this article.
Running Easy-RSA
The easyrsa script is located in easy-rsa/easyrsa3, from the initial directory cloned with the git command. The basic format for executing the command is:
./easyrsa command [ options ]
Where command is the name of the command to be executed and options are the parameters that customize the command. To get help on a specific command, use:
./easyrsa help [ command ]
When executed without any parameters, the ./easyrsa script will display a list of available commands.
Initializing the PKI
This step creates the basic directory structure necessary for managing keys and certificates. Execute the command ./easyrsa init-pki.
$ bash
# Access the EasyRSA directory cd /mnt/usb/easy-rsa/easyrsa3/ # Initialize the PKI ./easyrsa init-pki
With the Public Key Infrastructure created, you are ready to create a Certificate Authority (CA). Note that a new folder called pki/ has been created, where requests, private keys, and issued certificates will be stored, among other things.
Creating Your Own Certificate Authority (CA)
A CA is the entity responsible for issuing and managing digital certificates, which ensure security and authenticity in online communications.
During the creation of the CA's private key, you will be prompted for a password from which the file encryption will be generated. Enter a strong password and remember it, as it will be needed when signing new certificates.
You will also need to enter a name (Common Name) that will be used only for display. Choose a name to represent your CA; common options include: username, hostname, or server name.
Execute the command ./easyrsa build-ca:
# bash
# Access the EasyRSA directory cd /mnt/usb/easy-rsa/easyrsa3/ # Create the CA ./easyrsa build-ca
If everything goes well, you will be able to see some new files inside the pki/ folder, including the ca.crt certificate.
Generating the TLS Key and Diffie-Hellman (DH) Parameters
Before proceeding with the creation of keys and certificates for the VPN client and server, two more files are needed. The TLS key prevents third parties from interfering or discovering that the VPN is in operation, while the Diffie-Hellman (DH) parameters allow OpenVPN to create a shared secret without transmitting the actual key.
$ bash
# Generate the TLS key ./easyrsa gen-tls-crypt-key # Generate the Diffie-Hellman (DH) parameters ./easyrsa gen-dh
The TLS key can be found in pki/private/easyrsa-tls.key and the file containing the DH parameters in pki/dh.pem.
Fictional Scenario
To illustrate the following examples, let's consider a fictional scenario where employees of an office work remotely and need to connect to the company's network to perform their duties.
In this context, the OpenVPN server will be installed in the office, while the VPN clients will be configured on the employees' devices at their homes.
Generating Key and Certificate for the Server
In this step, a private key and a request for the VPN server will be generated. The request, when signed by the CA, will be converted into a certificate. The nopass parameter will be used to disable password encryption for the key.
Using a password requires it to be entered every time the VPN service is started, which may not be feasible on remote servers or those without easy keyboard access. The command follows the format:
./easyrsa gen-req [ server-name ] [ options ]
Confirm the server name when prompted during the process.
$ bash
./easyrsa gen-req office nopass
The request was generated in pki/reqs/office.req and the private key is in pki/private/office.key.
Sign the request with the following command. Answer yes when prompted to confirm the request details and enter the CA password to complete the signing.
$ bash
./easyrsa sign-req server office
The certificate will be available in pki/issued/office.crt.
Configuring the Server
From this point on, all commands must be executed as root or using sudo. Copy the following files generated by Easy-RSA to the OpenVPN configuration directory:
# bash
cp /mnt/usb/easy-rsa/easyrsa3/pki/ca.crt /etc/openvpn/certs/ cp /mnt/usb/easy-rsa/easyrsa3/pki/issued/office.crt /etc/openvpn/certs/ cp /mnt/usb/easy-rsa/easyrsa3/pki/dh.pem /etc/openvpn/certs/ cp /mnt/usb/easy-rsa/easyrsa3/pki/private/office.key /etc/openvpn/keys/ cp /mnt/usb/easy-rsa/easyrsa3/pki/private/easyrsa-tls.key /etc/openvpn/keys/
In Slackware, the OpenVPN configuration directory contains a link to sample files. Make a copy of the server.conf file to the OpenVPN folder and rename it to office.conf. If you are using another distribution and do not find this file, a complete version of the configuration file will be provided.
# bash
cd /etc/openvpn/ cp sample-config-files/server.conf office.conf
Create the ccd/ directory inside the OpenVPN folder. It will be used for client-specific configurations:
# bash
mkdir /etc/openvpn/ccd
Open the office.conf file with your favorite text editor. Below is a commented example of a functional configuration file for an OpenVPN server:
office.conf
############################################## # Example configuration for a OpenVPN # # server with support for multiple clients. # ############################################## local x.x.x.x # Local IP address on which OpenVPN should listen port 1194 # TCP/UDP port used by OpenVPN proto udp # Transport protocol (TCP or UDP) dev tun # Tunnel type: routed (tun) or Ethernet (tap) ca /etc/openvpn/certs/ca.crt # CA certificate dh /etc/openvpn/certs/dh.pem # Diffie-Hellman (DH) parameters cert /etc/openvpn/certs/office.crt # Server certificate key /etc/openvpn/keys/office.key # Server private key tls-auth /etc/openvpn/keys/easyrsa-tls.key 0 # TLS key (0 on server and 1 on client) ;crl-verify /etc/openvpn/crl.pem # Certificate Revocation List topology subnet # Subnet /24 (255.255.255.0) server 10.8.0.0 255.255.255.0 # Set the VPN network, server will be 10.8.0.1 ifconfig-pool-persist ipp.txt # Keeps a record of IPs assigned to clients # Sends a route to clients, # allowing access to internal networks push "route 192.168.10.0 255.255.255.0" # Set a folder for client-specific # configurations. Allows assigning # fixed IPs and routes. client-config-dir ccd # Uncomment to allow clients to # communicate with each other ;client-to-client # Sends a ping every 10 seconds and considers # the client offline after 120 seconds keepalive 10 120 cipher AES-256-GCM # Default encryption algorithm data-ciphers AES-256-GCM:AES-128-GCM:AES-256-CBC # Supported algorithms ;data-ciphers-fallback AES-256-CBC # Support for older versions # Disables compression for security reasons allow-compression no # Maximum number of simultaneous clients max-clients 100 # Reduces privileges after initialization user nobody group nobody # Improves connection stability persist-key # Prevents reloading keys after a reconnection persist-tun # Keeps the VPN interface active during a reconnection # Path to log files status /var/log/openvpn-status.log log-append /var/log/openvpn.log verb 3 # Log detail level mute 20 # Silences repeated log messages after 20 displays # Notifies clients when the server is # restarted so they can reconnect explicit-exit-notify 1
Tips
You can enable the service only for IPv4 using proto udp4 or only for IPv6 with proto udp6. If you prefer TCP, use proto tcp4 or proto tcp6.
It is possible to configure multiple OpenVPN servers simultaneously. To do this, simply generate the corresponding certificates and create a separate configuration file for each server within the OpenVPN directory. For example, you can have office.conf, hr.conf, it.conf, etc. In Slackware, the OpenVPN startup script will automatically load all configuration files ending in .conf within /etc/openvpn.
The entry ;crl-verify /etc/openvpn/crl.pem refers to the Certificate Revocation List. More information about this feature can be found here.
File and Directory Permissions
To increase security, it is necessary to set appropriate permissions for the files and directories within /etc/openvpn, ensuring that only authorized users have access.
# bash
# Set root as the owner of # OpenVPN files and directories chown -R root:root /etc/openvpn # Only root can read and write # configuration files chmod 600 *.conf # Set root as the owner and # assign the nobody group to the # ccd/ folder and the ipp.txt file chown -R root:nobody ccd/ ipp.txt # Read-only for root on # keys and certificates chmod -R 400 keys/ certs/ # Full access for root, read # and execute for nobody on ccd/ chmod 750 ccd/ # Allows read and write for # root and nobody on the ipp.txt file chmod 660 ipp.txt
On Linux, folders need execute (x) permission to be accessed, except for the root user. Therefore, directories storing keys and certificates are configured as read-only.
Keys, certificates, and main configuration files (.conf) are read before privileges are reduced to the nobody user. Therefore, these files must belong to the root user and group. Keys and certificates only need read permission (400). Main configuration files (.conf) need read and write permission (600) for root.
The nobody user needs read and execute permission on the ccd/ directory to access client-specific configuration files. Additionally, it needs read and write permission on the ipp.txt file, which records the assigned IP addresses.
To verify the directory structure and applied permissions, use the command:
# bash
tree -ugp ├── [drwxr-x--- root nobody ] ccd ├── [dr-------- root root ] certs │ ├── [-r-------- root root ] ca.crt │ ├── [-r-------- root root ] dh.pem │ └── [-r-------- root root ] office.crt ├── [-rw------- root root ] office.conf ├── [-rw-rw---- root nobody ] ipp.txt ├── [dr-------- root root ] keys │ ├── [-r-------- root root ] easyrsa-tls.key │ └── [-r-------- root root ] office.key
Starting the OpenVPN Server
The following commands are specific to Slackware. If you are using another distribution, consult the corresponding documentation, as the process may vary.
Before starting the service, grant execute permission to the OpenVPN startup script:
# bash
chmod +x /etc/rc.d/rc.openvpn
By setting this permission, the script will be executed automatically at system startup.
Commands to manage the service:
# bash
# Start the service /etc/rc.d/rc.openvpn start # Stop the service /etc/rc.d/rc.openvpn stop # Restart the service /etc/rc.d/rc.openvpn restart
Checking Logs
Checking logs is essential to ensure that OpenVPN is functioning correctly. To facilitate debugging, it is recommended to open multiple terminals and monitor the logs while starting and stopping the service.
To follow the logs in real-time, use the following commands:
# bash
# Service log tail -f /var/log/openvpn.log # Connection log tail -f /var/log/openvpn-status.log # System log tail -f /var/log/syslog
The above commands display new messages as they are logged until manually interrupted.
Debugging Errors
If a problem occurs in the configuration, OpenVPN will usually indicate the error in the logs. For example, if the ccd/ directory is not created or if its permissions do not allow access by the nobody user, you may receive the following message:
Options error: --client-config-dir fails with 'ccd': No such file or directory (errno=2)
Check the logs to identify and fix errors during service startup. If OpenVPN starts correctly, the openvpn.log file will display the following message: Initialization Sequence Completed.
Important
In this example, OpenVPN was configured to reduce privileges after initialization, switching to the nobody user. However, when shutting down OpenVPN on Slackware, both on the server and client, permission errors occur when removing IPs and routes. These failures generate messages like the following in the logs:
/var/log/openvpn.log
/usr/sbin/ip addr del dev tun0 10.8.0.1/24 RTNETLINK answers: Operation not permitted Linux ip addr del failed: external program exited with error status: 2
To work around this issue, various approaches were tested without success, such as executing external scripts via the down and down-pre options along with the script-security directive, configuring sudo to allow the nobody user to execute the ip command, and using the openvpn-plugin-down-root.so plugin.
The good news is that, even with the error messages, the necessary actions are executed correctly: the IPs and routes are removed, and the VPN interface is deactivated as expected. During the tests conducted for this material, no functional issues arising from this error were identified, so the adopted option was simply to ignore it.
If you wish to avoid these messages, an alternative is to run OpenVPN directly as root, without reducing privileges. However, this may have security implications.
Checking the VPN
Confirm if the VPN interface has been created:
# bash
ifconfig
tun0: flags=4305[UP,POINTOPOINT,RUNNING,NOARP,MULTICAST] mtu 1500
inet 10.8.0.1 netmask 255.255.255.0 destination 10.8.0.1
If the interface is active, your server is running and ready to receive connections. Now, let's move on to the client configuration.
Generating Key and Certificate for the Client
In this step, a private key and a certificate request for the VPN client will be generated. Execute the commands from the Easy-RSA base directory. In the example, we use /mnt/usb/easy-rsa/easyrsa3/. When prompted, confirm the client name. Here, we will use home.
$ bash
./easyrsa gen-req home nopass
This will generate the request in pki/reqs/home.req and the private key in pki/private/home.key.
Sign the request using the CA's private key. Answer yes when prompted to confirm the details and enter the CA password when prompted:
$ bash
./easyrsa sign-req client home
The client certificate will be generated in pki/issued/home.crt.
Configuring the Client
Copy the files generated by Easy-RSA to the OpenVPN configuration directory. In this article, the files are stored on a USB drive. If transferring them to a remote location, use secure methods such as SSH (scp, sftp) or HTTPS:
# bash
cp /mnt/usb/easy-rsa/easyrsa3/pki/ca.crt /etc/openvpn/certs/ cp /mnt/usb/easy-rsa/easyrsa3/pki/issued/home.crt /etc/openvpn/certs/ cp /mnt/usb/easy-rsa/easyrsa3/pki/private/home.key /etc/openvpn/keys/ cp /mnt/usb/easy-rsa/easyrsa3/pki/private/easyrsa-tls.key /etc/openvpn/keys/
Create the configuration file home.conf in the OpenVPN configuration directory. You can use the example file client.conf, available in sample-config-files, as a base.
Open the home.conf file with your favorite editor.
# bash
vi /etc/openvpn/home.conf
Below is a commented example of a functional configuration file for an OpenVPN client:
home.conf
################################################### # Example configuration for an OpenVPN client # ################################################### client # Configure as client dev tun # Use a routed tunnel (tun) proto udp # TCP or UDP? remote 10.0.0.68 1194 # Server IP and port ca /etc/openvpn/certs/ca.crt # CA certificate cert /etc/openvpn/certs/home.crt # Client certificate key /etc/openvpn/keys/home.key # Client private key tls-auth /etc/openvpn/keys/easyrsa-tls.key 1 # TLS key (1 on client) # If a domain name is used in the "remote" # parameter, this option makes the client # try to resolve it indefinitely resolv-retry infinite # Uses random ports when connecting to the server nobind # Reduces privileges after initialization user nobody group nobody # Improves connection stability persist-key # Keeps keys loaded after a reconnection persist-tun # Keeps the network interface active during a reconnection # Requires the server certificate to be correctly validated remote-cert-tls server # Defines the encryption algorithm for communication cipher AES-256-GCM # Path to log files status /var/log/openvpn-status.log log-append /var/log/openvpn.log verb 3 # Log message detail level mute 20 # Silences repeated log messages after 20 occurrences
Starting the OpenVPN Client
Grant execute permission to the OpenVPN startup script:
# bash
chmod +x /etc/rc.d/rc.openvpn
With this permission, the script can be executed manually and will also start automatically with the system.
Commands to manage the service:
# bash
# Start the service /etc/rc.d/rc.openvpn start # Stop the service /etc/rc.d/rc.openvpn stop # Restart the service /etc/rc.d/rc.openvpn restart
Checking Logs
As with the server, logs are essential for diagnosing issues and verifying that the OpenVPN client is functioning correctly.
Use the following commands to monitor logs in real-time:
# bash
# Service log tail -f /var/log/openvpn.log # Connection log tail -f /var/log/openvpn-status.log # System log tail -f /var/log/syslog
Checking the VPN
If the message Initialization Sequence Completed appears in the openvpn.log file, it indicates that the client has started correctly. To confirm that the VPN is working as expected, check if the VPN interface has been created and if the routes configured with the push command on the server have been applied correctly:
# bash
# Check if the tun0 interface has been created ifconfig tun0: flags=4305[UP,POINTOPOINT,RUNNING,NOARP,MULTICAST] mtu 1500 inet 10.8.0.2 netmask 255.255.255.0 destination 10.8.0.2 # List the configured network routes route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 192.168.10.0 10.8.0.1 255.255.255.0 UG 0 0 0 tun0
If everything is correct, your VPN tunnel is active and ready for use.
Conclusion
This text provides a detailed guide for configuring an OpenVPN tunnel on Linux, using Easy-RSA for certificate and key management. It covers everything from installing the necessary packages to creating and signing certificates, configuring the OpenVPN server and client, adjusting file and directory permissions, and checking logs to ensure the service is functioning correctly.
For a deeper understanding of certificate management, including conceptual aspects, security criteria, and details on using Easy-RSA, we recommend reading the complementary article:
References
Older articles from this site served as a starting point for the creation of this text. The manuals (man pages) available on Slackware Linux were also used.
- https://openvpn.net/community-resources/how-to/
- https://easy-rsa.readthedocs.io/en/latest/
- https://telazul.drusian.com.br/pt/artigo/configuracao-do-openvpn-server-e-easy-rsa-3-no-slackware
- https://telazul.drusian.com.br/pt/artigo/configuracao-do-openvpn-cliente-e-easy-rsa-3-no-slackware