Table of Contents
What you will read?
- 1 Step 1: Verify OS, network, and update
- 2 Step 2: Enable EPEL and CodeReady/CRB repositories
- 3 Step 3: Install OpenVPN, Easy-RSA, and firewalld
- 4 Step 4: Initialize PKI with Easy-RSA 3
- 5 Step 5: Create a secure server configuration
- 6 Step 6: Enable IP forwarding
- 7 Step 7: Open firewall and configure NAT
- 8 Step 8: Start and enable the OpenVPN server
- 9 Step 9: Create client certificates
- 10 Step 10: Build an inline .ovpn profile
- 11 Step 11: Connect and validate routing
- 12 Step 12: SELinux and file contexts
- 13 Step 13: Common maintenance and troubleshooting
OpenVPN on Red Hat Enterprise Linux 9/8 delivers secure, flexible remote access. The process below covers packages, PKI, server configuration, firewall, and client profiles using Easy-RSA 3. Commands are safe to copy, tuned for SELinux, and optimized for UDP performance and modern ciphers.
Step 1: Verify OS, network, and update
Confirm the platform, refresh repositories, and prepare the system for OpenVPN and PKI tooling.
cat /etc/redhat-release
ip a
getenforce
dnf -y update
Optional output example:
Red Hat Enterprise Linux release 9.x (Plow)
Enforcing
Step 2: Enable EPEL and CodeReady/CRB repositories
OpenVPN and Easy-RSA live in EPEL and require CodeReady Builder (or CRB on derivatives). Enable the right channels for RHEL 9/8.
source /etc/os-release
# Enable EPEL
dnf -y install epel-release
# Enable CodeReady Builder (RHEL)
if [[ "$ID" = "rhel" && "$VERSION_ID" =~ ^9 ]]; then
subscription-manager repos --enable codeready-builder-for-rhel-9-$(arch)-rpms
elif [[ "$ID" = "rhel" && "$VERSION_ID" =~ ^8 ]]; then
subscription-manager repos --enable codeready-builder-for-rhel-8-$(arch)-rpms
fi
# Enable CRB/Powertools (Rocky/Alma/CentOS Stream fallback)
if command -v dnf &>/dev/null; then
dnf config-manager --set-enabled crb || dnf config-manager --set-enabled powertools || true
fi
Step 3: Install OpenVPN, Easy-RSA, and firewalld
Install the VPN daemon, certificate tools, and firewall. Ensure firewalld runs persistently.
dnf -y install openvpn easy-rsa firewalld policycoreutils-python-utils
systemctl enable --now firewalld
Step 4: Initialize PKI with Easy-RSA 3
Create the certificate authority, server certificate, Diffie-Hellman parameters, CRL, and a tls-crypt key. Secure key material and place it under /etc/openvpn.
mkdir -p /etc/openvpn/server /etc/openvpn/pki
cp -r /usr/share/easy-rsa /etc/openvpn/
cd /etc/openvpn/easy-rsa/3
./easyrsa init-pki
# Set a concise CA name when prompted
./easyrsa build-ca nopass
# Server cert (CN: server)
./easyrsa build-server-full server nopass
# DH params and CRL
./easyrsa gen-dh
./easyrsa gen-crl
# tls-crypt key for control channel protection
openvpn --genkey secret /etc/openvpn/server/tc.key
# Move PKI artifacts to /etc/openvpn/pki
cp -a pki/* /etc/openvpn/pki/
# Secure permissions
chmod 600 /etc/openvpn/pki/private/*.key /etc/openvpn/server/tc.key
chown -R root:root /etc/openvpn/pki /etc/openvpn/server
Step 5: Create a secure server configuration
Define UDP, TUN, topology, secure ciphers, and push routes/DNS for clients. The config references the PKI and tls-crypt key.
cat >/etc/openvpn/server/server.conf <<'EOF'
port 1194
proto udp
dev tun
user nobody
group nobody
persist-key
persist-tun
topology subnet
server 10.8.0.0 255.255.255.0
ifconfig-pool-persist /var/lib/openvpn/ipp.txt
push "redirect-gateway def1 bypass-dhcp"
push "dhcp-option DNS 1.1.1.1"
push "dhcp-option DNS 8.8.8.8"
keepalive 10 60
explicit-exit-notify 1
# Modern crypto
cipher AES-256-GCM
data-ciphers AES-256-GCM
ncp-ciphers AES-256-GCM
auth SHA256
remote-cert-tls client
# PKI paths
ca /etc/openvpn/pki/ca.crt
cert /etc/openvpn/pki/issued/server.crt
key /etc/openvpn/pki/private/server.key
dh /etc/openvpn/pki/dh.pem
crl-verify /etc/openvpn/pki/crl.pem
tls-crypt /etc/openvpn/server/tc.key
# Logs
status /var/log/openvpn-status.log
log-append /var/log/openvpn.log
verb 3
EOF
Step 6: Enable IP forwarding
Allow the kernel to route traffic from VPN clients to the LAN/Internet. Persist the setting across reboots.
sysctl -w net.ipv4.ip_forward=1
sysctl -w net.ipv6.conf.all.forwarding=1
cat >/etc/sysctl.d/99-openvpn.conf <<'EOF'
net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding = 1
EOF
sysctl --system
Step 7: Open firewall and configure NAT
Open UDP/1194 and enable masquerading so client traffic can exit via the server’s public interface.
firewall-cmd --permanent --add-port=1194/udp
firewall-cmd --permanent --add-masquerade
firewall-cmd --reload
# Optional: restrict VPN source network if you use zones
# firewall-cmd --permanent --zone=public --add-source=10.8.0.0/24
# firewall-cmd --reload
Step 8: Start and enable the OpenVPN server
Use the templated systemd unit. Validate status and logs to confirm a clean start.
systemctl enable --now [email protected]
systemctl status [email protected] --no-pager
tail -n 50 /var/log/openvpn.log
Expected status snippet:
Active: active (running)
UDPv4 link local (bound): [AF_INET][undef]:1194
Initialization Sequence Completed
Step 9: Create client certificates
Issue per-user certificates with Easy-RSA. Protect private keys. Use passwordless or passphrase as your policy dictates.
cd /etc/openvpn/easy-rsa/3
./easyrsa build-client-full alice nopass
# Collect required files for alice:
# - /etc/openvpn/pki/ca.crt
# - /etc/openvpn/pki/issued/alice.crt
# - /etc/openvpn/pki/private/alice.key
# - /etc/openvpn/server/tc.key (tls-crypt)
Step 10: Build an inline .ovpn profile
Create a single-file client profile embedding CA, cert, key, and tls-crypt. Replace YOUR_SERVER_IP with the server’s public IP or DNS.
cat >alice.ovpn <<'EOF'
client
dev tun
proto udp
remote YOUR_SERVER_IP 1194
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
cipher AES-256-GCM
auth SHA256
verb 3
<ca>
# paste /etc/openvpn/pki/ca.crt
</ca>
<cert>
# paste /etc/openvpn/pki/issued/alice.crt
</cert>
<key>
# paste /etc/openvpn/pki/private/alice.key
</key>
<tls-crypt>
# paste /etc/openvpn/server/tc.key
</tls-crypt>
EOF
Step 11: Connect and validate routing
Test with the official OpenVPN client (Windows/macOS/Linux). Verify tunnel creation, assigned IP, and Internet egress via the server.
# On Linux client after connecting:
ip a show tun0
curl -4 ifconfig.me
# On server, watch logs:
journalctl -u openvpn-server@server -f
Step 12: SELinux and file contexts
Default paths work under Enforcing. If you use custom directories, label them correctly and restore contexts.
restorecon -Rv /etc/openvpn
# If using a nonstandard path (example: /opt/openvpn)
semanage fcontext -a -t openvpn_etc_t "/opt/openvpn(/.*)?"
restorecon -Rv /opt/openvpn
Step 13: Common maintenance and troubleshooting
Rotate CRLs, revoke users, and inspect connectivity. Use these quick checks before deeper packet captures.
# Revoke a client and update CRL
cd /etc/openvpn/easy-rsa/3
./easyrsa revoke alice
./easyrsa gen-crl
cp -f pki/crl.pem /etc/openvpn/pki/crl.pem
systemctl reload openvpn-server@server
# Connectivity checks
ss -lunpt | grep 1194
firewall-cmd --list-all
tcpdump -ni any udp port 1194
Result: a secure, performant OpenVPN server on RHEL 9/8 with modern crypto, proper routing, and clean SELinux integration.For more guides and support, visit dropvps.com
