Time flies, tools change a bit and new options are recognised, so I decided to update the step-by-step guide.
Relevance of the article: the current moment. Software: CentOS 7 minimal, SELinux enabled. All software updated with yum update.
⚠️Make an effort not to disable SELinux immediately after installing CentOS! This is briefly touched upon at the end of the article as well. Even the built-in Windows firewall can do a good job, let alone SELinux.
Step 1: Install OpenVPN
Additional utilities:
yum install wget
Installing OpenVPN:
yum install epel-release yum install openvpn
Step 2: PKI Public Key Infrastructure
The directory for keys:
mkdir /etc/openvpn/keys cd /etc/openvpn/keys
In general, all operations with OpenVPN keys can be done using OpenSSL. But there is Easy-RSA utility that used to come with OpenVPN, but now it is a separate project https://github.com/OpenVPN/easy-rsa. We will copy this utility to our server:
wget https://github.com/OpenVPN/easy-rsa/releases/download/v3.0.8/EasyRSA-3.0.8.tgz tar xvf EasyRSA-3.0.8.tgz cd /etc/openvpn/keys/EasyRSA-3.0.8
⚠️ The second option with yum install easy-rsa, but there is a disadvantage here in that you may get a newer version of easy-rsa than the one you are working with now, and you still copy those scripts and work with copies in the future. If via yum, remember to copy the files from /usr/share/easy-rsa/3.0.8.
Create a configuration file, with an understanding of what will happen. For example, the EASYRSA_PKI option (by default, “$PWD/pki”) specifies the path where the directory for the keys will be created. The command “init-pki” will perform “rm -rf” of the directory contents, be careful! You are still initialising the key infrastructure, it’s not there yet, but if anything is there it will be erased. Most options are default, edit country, OU, email etc. to your liking. Pay attention to validity periods (in days) of CA, CRL, CERT certificates.
⚠️ Attention! Different manuals have different sets of options, think about them all. For example, somewhere I saw: set_var EASYRSA_SSL_CONF “$EASYRSA/openssl-1.0.cnf”. Are you sure you need it? The description says: if you need to use a specific openssl config file, you can reference it here. Normally this file is auto-detected from a file named openssl-easyrsa.cnf from theEASYRSA_PKI or EASYRSA dir (in that order.) NOTE that this file is Easy-RSA specific and you cannot just use a standard config file, so this is an advanced feature.
⚠️ Attention! If you want any special OpenSSL options, specify the config file, understanding that you have at least one, and understanding why you want it.
In the “vars” configuration file, try to specify either the options that are important to you or the ones you override, but don’t copy the whole default config here.
nano vars
set_var EASYRSA "/etc/openvpn/keys/EasyRSA-3.0.8" set_var EASYRSA_PKI "$EASYRSA/pki" set_var EASYRSA_REQ_COUNTRY "US" set_var EASYRSA_REQ_PROVINCE "California" set_var EASYRSA_REQ_CITY "San Francisco" set_var EASYRSA_REQ_ORG "Copyleft Certificate Co" set_var EASYRSA_REQ_EMAIL "me@example.net" set_var EASYRSA_REQ_OU "My Organizational Unit" set_var EASYRSA_KEY_SIZE 4096 set_var EASYRSA_ALGO rsa set_var EASYRSA_CA_EXPIRE 3650 set_var EASYRSA_CERT_EXPIRE 3650 set_var EASYRSA_CRL_DAYS 3650 set_var EASYRSA_DIGEST "sha512"
There is nothing complicated there, see for yourself.
Step 3: Create a PKI (Public Key Infrastructure)
./easyrsa init-pki
This will create the directory /etc/openvpn/keys/EasyRSA-3.0.8/pki/.
⚠️ Warning! Once the infrastructure has been created, never run the init-pki command again! This command will, among other things, execute “rm -rf” of the directory contents, be careful!
Step 4: Create your own CA
When connecting clients to the OpenVPN server, to ensure that the server and client certificates are not forged, a CA (Certificate Authority) must be created. CAs can be own (mostly self-signed) and public, like Thawte, StartSSL, etc. In this example we will consider the situation when own CA is used – at least it is much cheaper. Even your CA does not have to be on the same server as the OpenVPN server, but more often the location of the CA for OpenVPN is on the same server as OpenVPN itself.
Creating your own CA:
./easyrsa build-ca
You could avoid entering a password (./easyrsa build-ca nopass), but if someone copies your CA’s private key, they will be able to sign “dummy” keys. You must guard your CA private key as the apple of your eye, as everything else is verified with it. Therefore the password must be brute force. After all, you won’t be using it every day.
We now have a ca.key and a ca.crt certificate:
- /etc/openvpn/keys/EasyRSA-3.0.8/pki/private/ca.key
- /etc/openvpn/keys/EasyRSA-3.0.8/pki/ca.crt
The secret key must be left on the server and not given to anyone else. Every time a new server or user certificate is issued we will need the secret key password! The CA certificate (ca.crt) is public and we will share it with the user certificates with clients.
Step 5: OpenVPN server certificates
Create a certificate request for the server without a password using the nopass option, otherwise you will have to enter the password from the console every time the server starts up:
./easyrsa gen-req server nopass Keypair and certificate request completed. Your files are: req: /etc/openvpn/keys/EasyRSA-3.0.8/pki/reqs/server.req key: /etc/openvpn/keys/EasyRSA-3.0.8/pki/private/server.key
Sign the certificate request with our CA:
./easyrsa sign-req server server
As the script runs, we enter the password from the CA we specified earlier and answer yes. We got a certificate signed by our certificate authority for the server – /etc/openvpn/keys/easy-rsa-master/easyrsa3/pki/issued/server.crt
Step 6: Generate a Diffie-Helman key
./easyrsa gen-dh
In the case of OpenVPN, the Diffie-Helman file is needed to provide protection against decryption if the keys have been stolen. This refers to traffic that was recorded and stored before the keys were stolen. It’s a wide topic and I didn’t dare to overload the article with lyric digressions.
The generation takes a decent amount of time (in relation to other keys). In the end we get the key /etc/openvpn/keys/EasyRSA-3.0.8/pki/dh.pem
Step 7: List of withdrawn CRL certificates
Employees quit, lose their mobile phones and therefore need to be denied access to a VPN. You must revoke their certificate. To be able to revoke a client certificate you must create a list of revoked CRL certificates:
./easyrsa gen-crl
The file /etc/openvpn/keys/EasyRSA-3.0.8/pki/crl.pem will be created, which will contain a list of revoked certificates. This file must be copied to /etc/openvpn/ directory, specified in the OpenVPN server config and the OpenVPN server restarted.
Copy to /etc/openvpn folder all keys required for openvpn server (remember, we are in /etc/openvpn/keys/EasyRSA-3.0.8):
cp pki/{ca.crt,dh.pem,crl.pem} /etc/openvpn/ cp pki/issued/server.crt /etc/openvpn/ cp pki/private/server.key /etc/openvpn/
Create an HMAC file, for additional client and server verification (to protect against DDoS):
cd /etc/openvpn openvpn --genkey --secret ta.key
The file ta.key must be copied and transferred to the client.
In a normal server configuration, after startup (from root) permissions are changed to an unprivileged user (nobody or specially created). This user must have read permissions to the certificates for client authentication:
chmod 644 /etc/openvpn/ca.crt chmod 644 /etc/openvpn/crl.pem chmod 644 /etc/openvpn/dh.pem chmod 644 /etc/openvpn/server.crt
The server.key, ta.key should only be available to root (chmod 600)!
Step 8: Client keys
Create a key for the openvpn client:
cd /etc/openvpn/keys/EasyRSA-3.0.8 ./easyrsa gen-req client1 nopass ./easyrsa sign-req client client1
There may be situations where it is better to protect the client key with a password, at least a simple one. Then whenever you connect to the VPN you will need to enter the password. This can be handy if, for example, you don’t want your child to accidentally connect to your work network and cause trouble. You just don’t need to specify “nopass” at the end of the command above.
We will end up with two files:
Public client certificate: /etc/openvpn/keys/EasyRSA-3.0.8/pki/issued/client1.crt
Client private key: /etc/openvpn/keys/EasyRSA-3.0.8/pki/private/client1.key
The client will need to pass copies of the following files along with the config (see below):
client1.crt;
client1.key;
ca.crt;
ta.key
which are all used in the client config. No files other than those specified in the client config need to be transferred to the client!
Step 9: Configure OpenVPN
The default server configuration file is /etc/openvpn/server.conf. You will probably not need to change its location.
Note the common options for client and server. These are encryption type, traffic compression, etc. Some options are mirrored. For example, on the server ta.key 0, on the client ta.key 1, etc.
Example 1 (OpenVPN server config):
port 1194 proto udp dev tun ca ca.crt cert server.crt key server.key dh dh.pem # Checking whether the client certificate has been withdrawn crl-verify crl.pem server 10.8.12.0 255.255.255.0 ifconfig-pool-persist ipp.txt # Let all client traffic go through the VPN push "redirect-gateway def1" # DNS hosting server (or others as you see fit): push "dhcp-option DNS 8.8.8.8" keepalive 10 120 tls-server tls-auth ta.key 0 tls-timeout 120 auth MD5 cipher BF-CBC comp-lzo max-clients 10 user nobody group nobody persist-key persist-tun status openvpn-status.log log /var/log/openvpn.log # 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 4
Example 2 (OpenVPN server configuration):
port 3725 proto udp dev tun ca ca.crt cert server.crt key server.key dh dh.pem crl-verify crl.pem server 10.8.0.0 255.255.255.0 ifconfig-pool-persist ipp.txt push "redirect-gateway def1" push "dhcp-option DNS 8.8.8.8" remote-cert-eku "TLS Web Client Authentication" keepalive 10 120 tls-server tls-auth ta.key 0 tls-timeout 120 auth SHA512 cipher AES-256-CBC comp-lzo max-clients 10 user nobody group nobody persist-key persist-tun status openvpn-status.log #log-append openvpn.log #log /dev/null #log /var/log/openvpn.log log openvpn.log verb 6
Step 10: Configure a OpenVPN Client
Some options must be symmetrical to the server options, in particular encryption type (here BF-CBC), traffic compression, etc. All of the configs below work.
These are examples of OpenVPN client configs for Windows. For Linux all the same, only paths to the key files have to be specified as in the server config (see above).
Example 1 (OpenVPN client config):
client dev tun proto udp remote 1.2.3.4 1194 resolv-retry infinite nobind persist-key persist-tun mute-replay-warnings ns-cert-type server tls-auth "C:Program FilesOpenVPNconfigta.key" 1 auth MD5 ca "C:\\Program Files\\OpenVPN\\config\\ca.crt" cert "C:\\Program Files\\OpenVPNconfig\\client1.crt" key "C:\\Program Files\\OpenVPN\\config\\client1.key" cipher BF-CBC comp-lzo verb 3
Example 2 ( matches the example of the second server config):
client dev tun proto udp remote 1.2.3.4 3725 resolv-retry infinite nobind block-outside-dns persist-key persist-tun mute-replay-warnings remote-cert-eku "TLS Web Server Authentication" remote-cert-tls server tls-client tls-auth "C:\\Program Files\\OpenVPN\\config\\ta.key" 1 auth SHA512 ca "C:\\Program Files\\OpenVPN\\config\\ca.crt" cert "C:\\Program Files\\OpenVPN\\config\\client1.crt" key "C:\\Program Files\\OpenVPN\\config\\client1.key" cipher AES-256-CBC comp-lzo verb 3
Step 11: Start OpenVPN
systemctl start openvpn@server
Check if it is running or not (assume that port 3876/udp is specified in the config):
netstat -tulnp | grep 3876 udp 0 0 0.0.0.0:3876 0.0.0.0:* 10431/openvpn
Great, it’s running on the specified port.
Well, or so we check:
systemctl status openvpn@server
If all is OK, enable autostart
systemctl enable openvpn@server
If something is wrong, look at the log. SELinux may not be allowing OpenVPN to run on the port you selected.
semanage port -a -t openvpn_port_t -p udp 3876
and try running OpenVPN again.
In any case, the log file will help you. After debugging, the log file can also be disabled (log /dev/null).
Step 12: Revoke client certificates
To revoke client1’s certificate:
cd /etc/openvpn/keys/EasyRSA-3.0.8/pki/ ./vars ./easyrsa revoke client1
This will create a new file crl.pem which must be copied into /etc/openvpn directory, replacing the old one and restarting the OpenVPN server.
And in the index.txt file the corresponding certificate will be marked with R (working V and withdrawn – R).
The OpenVPN key infrastructure is essentially a normal OpenSSL CA, so much of what you know about OpenSSL will work for OpenVPN. For example, a list of certificates with serial numbers, whether they are revoked, and other information can be found in the index.txt file.
If you try to connect to a server with a revoked certificate, the server log may show the following events (verb level 4):
CRL CHECK FAILED: C=RU, ST=NW, L=City, O=Org, OU=OU, CN=client1, name=EasyRSA, emailAddress=client1@localhost.local (serial 04) is REVOKED TLS_ERROR: BIO read tls_read_plaintext error: error:140890B2:SSL routines:SSL3_GET_CLIENT_CERTIFICATE:no certificate returned TLS Error: TLS object -> incoming plaintext read error TLS Error: TLS handshake failed
Note the line “CRL CHECK FAILED”: the certificate with serial number 04 is REVOKED!
Step 13: Firewall (iptables) and Routing Configuration
Allow access to the OpenVPN server from the external interface:
iptables -A INPUT -i eth0 -p udp --dport 3876 -j ACCEPT
After this, OpenVPN clients will be able to connect to the server but may not be able to go outside the server, depending on the current firewall settings.
To allow clients to access the Internet or LAN resources, first enable routing on the OpenVPN server (applies until reboot):
echo 1 > /proc/sys/net/ipv4/ip_forward
To save after reloading, save the line at the end of the file:
nano /etc/sysctl.conf net.ipv4.ip_forward = 1
To allow OpenVPN clients to access the internet on behalf of the server (external interface eth0):
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
To allow OpenVPN clients to work with the local network (LAN interface eth1):
iptables -A FORWARD -i tun0 -o eth1 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT iptables -A FORWARD -i eth1 -o tun0 -m state --state ESTABLISHED,RELATED -j ACCEPT
Example of a working iptables script for an OpenVPN server:
#!/bin/sh IF_EXT="eth0" IF_OVPN="tun0" OVPN_PORT="3876" IPT="/sbin/iptables" IPT6="/sbin/ip6tables" # flush $IPT --flush $IPT -t nat --flush $IPT -t mangle --flush $IPT -X $IPT6 --flush # loopback $IPT -A INPUT -i lo -j ACCEPT $IPT -A OUTPUT -o lo -j ACCEPT # default $IPT -P INPUT DROP $IPT -P OUTPUT ACCEPT $IPT -P FORWARD ACCEPT $IPT6 -P INPUT DROP $IPT6 -P OUTPUT ACCEPT $IPT6 -P FORWARD ACCEPT # allow forwarding echo 1 > /proc/sys/net/ipv4/ip_forward # NAT # ######################################### # SNAT - local users to out internet $IPT -t nat -A POSTROUTING -o $IF_EXT -j MASQUERADE # INPUT chain # ######################################### $IPT -A INPUT -p tcp ! --syn -m state --state NEW -j DROP $IPT -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT # ssh $IPT -A INPUT -i $IF_EXT -p tcp --dport 2685 -j ACCEPT # icmp (vpn) $IPT -A INPUT -i $IF_OVPN -p icmp -s 10.8.0.0/24 -j ACCEPT # openvpn and dns (vpn) $IPT -A INPUT -i $IF_OVPN -p udp --dport 53 -s 10.8.0.0/24 -j ACCEPT # openvpn $IPT -A INPUT -i $IF_EXT -p udp --dport $OVPN_PORT -j ACCEPT
Step 14: Creating a script to generate client configuration file .OVPN
Create a simple script to generate configuration files with relevant certificates, keys and encryption files.
Create and open make_config.sh.
#!/bin/bash # First argument: Client identifier KEY_DIR=~/openvpn-ca/keys 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}/${1}.crt \ <(echo -e '</cert>\n<key>') \ ${KEY_DIR}/${1}.key \ <(echo -e '</key>\n<tls-auth>') \ ${KEY_DIR}/ta.key \ <(echo -e '</tls-auth>') \ > ${OUTPUT_DIR}/${1}.ovpn
- base.conf – copy of the configuration file for the client
- OUTPUT_DIR – directory in which the .ovpn file will be created
- KEY_DIR – directory to which all previously generated keys should be copied
Make it an executable file by command:
chmod 700 make_config.sh
It is now easy and straightforward to generate client configuration files. Generate the .ovpn file for the client created in Step 8: Client keys.
./make_config.sh client1
If everything went well, we should get the client1.ovpn file in the OUTPUT_DIR directory. You must now copy or move the resulting configuration file to the client device: computer or smartphone.
Step 15: Connect a Client to OpenVPN
For Linux Users
To connect to OpenVPN, run the command:
openvpn --config /path/to/client1.ovpn
For Windows Users
- First, copy the client.ovpn configuration file in the c:\Program Files\OpenVPN\config\ directory.
- Download and install the OpenVPN application. You can find the latest build on the https://openvpn.net/community-downloads/. Once you have installed the application, launch OpenVPN.
- Right-click the OpenVPN system tray icon and select Connect. To perform this task, you need administrative privileges.
- To connect automatically, you need to change the shortcut on the desktop:
openvpn-gui.exe --connect client1.ovpn
For macOS Users
You can connect to OpenVPN from a macOS system using Tunnelblick (an open-source graphic user interface for OpenVPN on OS X and macOS).
Before launching Tunnelblick, make sure to store the client.ovpn configuration file in the ~/Library/Application Support/Tunnelblick/Configurations directory
Conclusion
After reading this article, you should have successfully installed and configured OpenVPN on a CentOS server. If you have any questions, feel free to write in the comments.
Thank you very much, I didn’t know how to install it.