How to Install and Configure OpenVPN on RHEL 7
OpenVPN is one of the most widely deployed VPN solutions in the enterprise, valued for its flexibility, strong encryption, and compatibility across nearly every operating system. On RHEL 7, OpenVPN is not included in the base repositories but is available from EPEL. Building a proper PKI (Public Key Infrastructure) with Easy-RSA ensures every client has its own signed certificate, giving you fine-grained revocation control — something simpler VPN solutions lack. This guide covers installing OpenVPN and Easy-RSA, building a full certificate authority, generating server and client certificates, writing the server configuration, enabling IP forwarding and firewall masquerade, generating a client .ovpn file, and making a successful connection.
Prerequisites
- RHEL 7 server with a registered subscription or CentOS 7 equivalent
- Root or
sudoaccess - EPEL repository enabled
- A public IP address and UDP port 1194 accessible (or TCP 443 for firewalled environments)
- SELinux in enforcing mode — we will handle context labeling
- A client machine to test the finished configuration
Step 1: Install OpenVPN and Easy-RSA
Enable EPEL if not already done, then install OpenVPN and Easy-RSA:
sudo yum install -y epel-release
sudo yum install -y openvpn easy-rsa
Verify the installed versions:
openvpn --version | head -1
ls /usr/share/easy-rsa/
On RHEL 7 with Easy-RSA 3.x, the scripts live in /usr/share/easy-rsa/3/. Copy the Easy-RSA directory to a working location so your PKI persists independently of package updates:
sudo mkdir -p /etc/openvpn/easy-rsa
sudo cp -r /usr/share/easy-rsa/3/* /etc/openvpn/easy-rsa/
cd /etc/openvpn/easy-rsa
Step 2: Initialize the PKI and Build the Certificate Authority
Initialize the PKI directory structure:
sudo ./easyrsa init-pki
Build the Certificate Authority. You will be prompted for a CA passphrase and a Common Name. The passphrase protects the CA private key — use something strong and store it securely:
sudo ./easyrsa build-ca
This creates pki/ca.crt (the CA certificate, distributed to all clients) and pki/private/ca.key (the CA private key, kept only on the server). Also generate the Diffie-Hellman parameters (this takes several minutes on RHEL 7):
sudo ./easyrsa gen-dh
Generate a TLS Authentication (TA) key for an additional HMAC layer that blocks unauthenticated packets before they reach the OpenVPN daemon:
sudo openvpn --genkey --secret /etc/openvpn/ta.key
Step 3: Generate the Server Certificate
Create a server certificate and key pair. The argument nopass means the server key is not passphrase-protected — necessary because OpenVPN starts unattended at boot:
sudo ./easyrsa build-server-full server nopass
Copy the required files to /etc/openvpn/:
sudo cp pki/ca.crt /etc/openvpn/
sudo cp pki/issued/server.crt /etc/openvpn/
sudo cp pki/private/server.key /etc/openvpn/
sudo cp pki/dh.pem /etc/openvpn/
Restrict permissions on the private key:
sudo chmod 600 /etc/openvpn/server.key
sudo chmod 600 /etc/openvpn/ta.key
Step 4: Generate a Client Certificate
Generate a certificate for each VPN client. Replace client1 with a meaningful identifier for the user or device:
sudo ./easyrsa build-client-full client1 nopass
To require a passphrase on the client key (recommended for user-facing certificates), omit nopass:
sudo ./easyrsa build-client-full client1
The client files are now at:
pki/ca.crt— CA certificate (shared)pki/issued/client1.crt— client certificatepki/private/client1.key— client private key
Step 5: Write the Server Configuration
Copy the sample server configuration as a starting point:
sudo cp /usr/share/doc/openvpn-*/sample/sample-config-files/server.conf /etc/openvpn/
sudo vi /etc/openvpn/server.conf
The key directives you must set or confirm:
# Protocol and port
port 1194
proto udp
dev tun
# Certificate and key files
ca /etc/openvpn/ca.crt
cert /etc/openvpn/server.crt
key /etc/openvpn/server.key
dh /etc/openvpn/dh.pem
# TLS authentication — direction 0 on server
tls-auth /etc/openvpn/ta.key 0
cipher AES-256-CBC
auth SHA256
# VPN subnet — clients get IPs from this range
server 10.8.0.0 255.255.255.0
# Push default gateway so ALL client traffic routes through VPN
push "redirect-gateway def1 bypass-dhcp"
push "dhcp-option DNS 8.8.8.8"
push "dhcp-option DNS 8.8.4.4"
# Keep connections alive
keepalive 10 120
# Persist keys and tunnel across restarts
persist-key
persist-tun
# Drop privileges after startup
user nobody
group nobody
# Logging
status /var/log/openvpn-status.log
log-append /var/log/openvpn.log
verb 3
Step 6: Enable IP Forwarding
Clients need the server to forward their traffic to the internet. Enable forwarding persistently:
sudo vi /etc/sysctl.d/99-openvpn.conf
net.ipv4.ip_forward = 1
sudo sysctl -p /etc/sysctl.d/99-openvpn.conf
sysctl net.ipv4.ip_forward
# Expected: 1
Step 7: Configure Firewall NAT Masquerade
Add masquerade so client VPN traffic appears to come from the server’s public IP:
sudo firewall-cmd --permanent --add-service=openvpn
sudo firewall-cmd --permanent --add-masquerade
sudo firewall-cmd --permanent --add-port=1194/udp
sudo firewall-cmd --reload
sudo firewall-cmd --list-all
Verify masquerade is active:
sudo firewall-cmd --query-masquerade
# Expected: yes
Step 8: Handle SELinux for OpenVPN
On RHEL 7 with SELinux enforcing, OpenVPN needs the correct context for its log files and may need a boolean set if using a non-default port:
# Allow OpenVPN to write logs
sudo semanage fcontext -a -t openvpn_var_log_t "/var/log/openvpn(/.*)?"
sudo restorecon -Rv /var/log/openvpn.log
# If using a non-standard port, label it
sudo semanage port -a -t openvpn_port_t -p udp 1194
If you encounter AVC denials, use audit2why to diagnose:
sudo ausearch -m avc -ts recent | audit2why
Step 9: Start and Enable OpenVPN
sudo systemctl start openvpn@server
sudo systemctl enable openvpn@server
sudo systemctl status openvpn@server
Confirm the tun0 interface is up:
ip addr show tun0
Check the log for errors:
sudo tail -f /var/log/openvpn.log
Step 10: Generate a Client .ovpn File
Bundle all required files into a single portable .ovpn file for easy client distribution. Create a script or build it manually:
sudo bash -c "cat > /tmp/client1.ovpn" <<'OVPN'
client
dev tun
proto udp
remote YOUR_SERVER_PUBLIC_IP 1194
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
cipher AES-256-CBC
auth SHA256
# TLS auth direction 1 on client
key-direction 1
verb 3
OVPN
echo "<ca>" | sudo tee -a /tmp/client1.ovpn
sudo cat /etc/openvpn/easy-rsa/pki/ca.crt | sudo tee -a /tmp/client1.ovpn
echo "</ca>" | sudo tee -a /tmp/client1.ovpn
echo "<cert>" | sudo tee -a /tmp/client1.ovpn
sudo cat /etc/openvpn/easy-rsa/pki/issued/client1.crt | sudo tee -a /tmp/client1.ovpn
echo "</cert>" | sudo tee -a /tmp/client1.ovpn
echo "<key>" | sudo tee -a /tmp/client1.ovpn
sudo cat /etc/openvpn/easy-rsa/pki/private/client1.key | sudo tee -a /tmp/client1.ovpn
echo "</key>" | sudo tee -a /tmp/client1.ovpn
echo "<tls-auth>" | sudo tee -a /tmp/client1.ovpn
sudo cat /etc/openvpn/ta.key | sudo tee -a /tmp/client1.ovpn
echo "</tls-auth>" | sudo tee -a /tmp/client1.ovpn
Securely transfer /tmp/client1.ovpn to the client machine (use scp over an encrypted channel, never email).
Step 11: Connect from the Client
On a Linux client with OpenVPN installed:
sudo openvpn --config client1.ovpn
A successful connection ends with a line like Initialization Sequence Completed. Verify the tunnel:
ip addr show tun0
curl https://ifconfig.me # Should return the server's public IP
ping 10.8.0.1 # Ping the VPN server internal address
You now have a fully functional OpenVPN server on RHEL 7 backed by a proper certificate authority. Every new user requires their own signed certificate, revocable at any time with ./easyrsa revoke client1 followed by regenerating the CRL and adding crl-verify /etc/openvpn/easy-rsa/pki/crl.pem to the server config. This certificate-per-client model is what sets OpenVPN apart for enterprise deployments requiring accountability and access control. Regularly update OpenVPN from EPEL (yum update openvpn) and rotate your DH parameters and TA key annually.