
OpenVPN remains one of the most dependable ways to build a private, encrypted network path between remote users and a Fedora server. It is mature, flexible, well supported across operating systems, and straightforward enough to run on a small VPS while still scaling to a production remote-access environment.
This guide walks through installing OpenVPN on Fedora 45, creating a proper certificate authority with Easy-RSA, configuring the server, opening the necessary firewall rules, issuing client certificates, and testing the connection. It also covers SELinux, systemd, NAT, troubleshooting, and the operational details that matter once real users depend on the VPN.
The instructions assume you are setting up a road-warrior VPN: remote clients connect to a central Fedora 45 server and receive access to the internet, a private network, or both. The same foundation works for site-to-site links, though those require additional routing and firewall planning.
Prerequisites
Before touching OpenVPN, make sure the server has the basics in place.
- A Fedora 45 server with root or sudo access
- A public IPv4 address, or a correctly forwarded UDP port if the server sits behind NAT
- UDP port 1194 available externally, unless you plan to use another port
- Accurate system time, preferably maintained by chronyd or another NTP service
- A domain name pointing to the server, which makes certificate management and client configuration easier
- At least 512 MB RAM for a small deployment; 1 GB or more is more comfortable for multiple users
Fedora’s official OpenVPN documentation recommends installing both openvpn and easy-rsa, copying the Easy-RSA files into /etc/openvpn/easy-rsa, and keeping the CA private key off the VPN server whenever possible. [16]
A quick health check is worth doing first:
sudo dnf upgrade --refresh -y
sudo systemctl status chronyd
ip -brief address
sudo firewall-cmd --state
If chronyd is inactive, enable it:
sudo systemctl enable --now chronyd
Certificate validation depends heavily on correct time. A clock drift of even a few minutes can cause confusing TLS errors later, especially after certificates are renewed or clients reconnect from different time zones.
Install OpenVPN and Easy-RSA
Fedora ships OpenVPN and Easy-RSA in its standard repositories, so there is no need to add third-party repositories for a normal deployment.
sudo dnf install -y openvpn easy-rsa
Confirm the installed versions:
openvpn --version
rpm -q easy-rsa
You should see OpenVPN 2.x and Easy-RSA 3.x. Avoid older tutorials that reference Easy-RSA 2, build-key, or pkitool; those workflows are obsolete and can produce certificates that modern OpenVPN configurations handle poorly.
Create a dedicated working directory for the PKI:
sudo mkdir -p /etc/openvpn/easy-rsa
sudo cp -rai /usr/share/easy-rsa/3/* /etc/openvpn/easy-rsa/
cd /etc/openvpn/easy-rsa
Fedora’s wiki uses this same approach: copy Easy-RSA version 3 into /etc/openvpn/easy-rsa, edit vars, initialize the PKI, then build the CA and server certificate. [16]
Plan the Certificate Authority
This is the part people rush, and it usually causes problems later.
OpenVPN uses a public key infrastructure. The server and every client need a certificate signed by a trusted certificate authority. If someone obtains your CA private key, they can issue valid certificates for themselves. That is why the CA should be treated as sensitive infrastructure, not as just another configuration directory.
For a small personal VPN, creating the CA on the same server is acceptable if the server is properly hardened. For a business or production environment, generate the CA on a separate offline machine or a tightly controlled administrative host. The OpenVPN project explicitly recommends separating CA duties from the VPN server because compromise of the CA key undermines the entire PKI. [18]
The files matter:
| File | Purpose | Where it belongs |
|---|---|---|
ca.crt |
Public CA certificate | Server and every client |
ca.key |
CA private signing key | Secure CA system only |
server.crt |
Server certificate | OpenVPN server |
server.key |
Server private key | OpenVPN server only |
dh.pem |
Diffie-Hellman parameters | OpenVPN server |
client.crt |
Client certificate | Individual client |
client.key |
Client private key | Individual client only |
Never distribute ca.key, server.key, or a client private key through a public channel. Use SFTP, SCP, or an encrypted transfer method.
Configure Easy-RSA Variables
Copy the example variables file and edit it:
sudo cp vars.example vars
sudo nano vars
Set values appropriate for your organization. These fields appear in certificates and help identify issued credentials later.
set_var EASYRSA_REQ_COUNTRY "ID"
set_var EASYRSA_REQ_PROVINCE "Yogyakarta"
set_var EASYRSA_REQ_CITY "Yogyakarta"
set_var EASYRSA_REQ_ORG "Example Company"
set_var EASYRSA_REQ_EMAIL "admin@example.com"
set_var EASYRSA_REQ_OU "IT Operations"
set_var EASYRSA_KEY_SIZE 2048
set_var EASYRSA_CA_EXPIRE 3650
set_var EASYRSA_CERT_EXPIRE 825
For most deployments, RSA 2048 is still practical and compatible. If you prefer modern elliptic-curve cryptography, Easy-RSA supports EC certificates, but check client compatibility before committing to it. Mixed client environments, older mobile apps, and unusual embedded devices sometimes behave differently with EC-based PKIs.
Initialize a clean PKI:
sudo ./easyrsa init-pki
If you are rebuilding an existing PKI, stop and make a backup first. clean-all or deleting the pki directory will remove certificates that may still be in use.
Build the CA and Server Certificate
Create the certificate authority:
sudo ./easyrsa build-ca
Easy-RSA will ask for a CA passphrase. Use a strong passphrase and store it in your organization’s password manager. Do not use nopass for the CA unless you fully understand the operational tradeoff.
Next, build the server certificate and key:
sudo ./easyrsa build-server-full server nopass
The nopass option is common for servers because OpenVPN must start automatically at boot without a human entering a passphrase. The server private key is still sensitive, so restrict its permissions and ensure only the OpenVPN service can read it.
Generate Diffie-Hellman parameters:
sudo ./easyrsa gen-dh
This can take a few minutes on a small VPS. It is normal. The resulting dh.pem file is used during TLS key exchange and is not secret, but it should still be stored safely with the other server files.
Create the OpenVPN Server Directory
Fedora’s systemd integration expects server configurations under /etc/openvpn/server/. Create that directory and copy only the files the VPN server needs:
sudo mkdir -p /etc/openvpn/server
sudo cp pki/ca.crt /etc/openvpn/server/
sudo cp pki/issued/server.crt /etc/openvpn/server/
sudo cp pki/private/server.key /etc/openvpn/server/
sudo cp pki/dh.pem /etc/openvpn/server/
Set restrictive permissions:
sudo chown root:root /etc/openvpn/server/*
sudo chmod 600 /etc/openvpn/server/server.key
sudo chmod 644 /etc/openvpn/server/ca.crt \
/etc/openvpn/server/server.crt \
/etc/openvpn/server/dh.pem
The Fedora documentation emphasizes that the OpenVPN server only needs ca.crt, server.crt, server.key, and the DH parameters. It does not need the CA private key or the full Easy-RSA PKI. [16]
Generate a TLS Crypt Key
A TLS control-channel protection key adds another layer of defense. It helps protect against denial-of-service attempts and unauthorized packets reaching the OpenVPN process.
Generate the key:
sudo openvpn --genkey secret /etc/openvpn/server/tls-crypt.key
sudo chmod 600 /etc/openvpn/server/tls-crypt.key
This key must also be copied to every client. Unlike a certificate, it is shared between server and clients, so protect it carefully. If it leaks, rotate it and redistribute new client profiles.
tls-crypt is generally preferable to the older tls-auth approach because it encrypts as well as authenticates control-channel traffic. tls-auth still works, but there is rarely a reason to choose it for a new deployment unless compatibility requires it.
Create the OpenVPN Server Configuration
Create the main server configuration:
sudo nano /etc/openvpn/server/server.conf
A solid baseline configuration looks like this:
port 1194
proto udp
dev tun
ca /etc/openvpn/server/ca.crt
cert /etc/openvpn/server/server.crt
key /etc/openvpn/server/server.key
dh /etc/openvpn/server/dh.pem
tls-crypt /etc/openvpn/server/tls-crypt.key
server 10.8.0.0 255.255.255.0
push "redirect-gateway def1 bypass-dhcp"
push "dhcp-option DNS 1.1.1.1"
push "dhcp-option DNS 1.0.0.1"
keepalive 10 120
remote-cert-tls client
user nobody
group nobody
persist-key
persist-tun
explicit-exit-notify 1
auth SHA256
cipher AES-256-GCM
data-ciphers AES-256-GCM:AES-128-GCM
data-ciphers-fallback AES-256-GCM
status /var/log/openvpn-status.log
log-append /var/log/openvpn.log
verb 3
A few settings deserve explanation.
proto udp is usually the best default. UDP handles packet loss more gracefully for VPN traffic and generally performs better for interactive use. Use TCP only when UDP is blocked or unreliable, such as on some restrictive corporate or hotel networks.
server 10.8.0.0 255.255.255.0 defines the virtual VPN subnet. Choose a range that does not overlap with your office LAN, home network, cloud VPC, or Docker networks. Overlapping subnets are one of the most common causes of “the VPN connects but nothing works.”
push "redirect-gateway def1 bypass-dhcp" sends all client traffic through the VPN. Remove that line if you only want clients to reach specific internal resources.
remote-cert-tls client requires client certificates to have the correct extended key usage attributes. The OpenVPN project recommends this directive for man-in-the-middle protection, especially because older Netscape certificate attributes are deprecated. [18]
data-ciphers AES-256-GCM:AES-128-GCM uses authenticated encryption. Avoid legacy BF-CBC, DES, or old static-key configurations in new deployments.
Enable IP Forwarding
If VPN clients should reach the internet or other machines on the server’s network, enable IPv4 forwarding.
Check the current setting:
sysctl net.ipv4.ip_forward
Enable it temporarily:
sudo sysctl -w net.ipv4.ip_forward=1
Make it persistent:
echo 'net.ipv4.ip_forward = 1' | sudo tee /etc/sysctl.d/99-openvpn-forward.conf
sudo sysctl --system
Without forwarding, clients can connect to the VPN but cannot route traffic beyond the server. This is a frequent source of confusion: the tunnel comes up, the client receives an IP address, yet browsing fails.
Configure firewalld and NAT
Fedora uses firewalld by default. The OpenVPN service definition references UDP port 1194, and Fedora’s documentation recommends allowing OpenVPN traffic, adding the tunnel interface, enabling forwarding, and enabling masquerading. [16]
First, identify your public interface:
ip route get 1.1.1.1
Assume it is eth0. Adjust the commands if yours is ens3, enp1s0, or something else.
Allow OpenVPN:
sudo firewall-cmd --permanent --add-service=openvpn
If you changed the port or protocol, open it explicitly instead:
sudo firewall-cmd --permanent --add-port=1194/udp
Enable masquerading so VPN clients can reach the internet through the server:
sudo firewall-cmd --permanent --add-masquerade
Allow forwarding within the active zone:
sudo firewall-cmd --permanent --add-forward
Reload the firewall:
sudo firewall-cmd --reload
Verify the configuration:
sudo firewall-cmd --list-all
You should see openvpn under services, masquerade: yes, and forwarding enabled.
For a more restrictive production setup, avoid exposing broad forwarding rules. Permit only the VPN subnet to reach the specific internal networks or services it needs. For example, if clients should access only a database server at 192.168.10.20, use targeted rich rules rather than allowing unrestricted access to the entire LAN.
Fix SELinux Contexts
SELinux is enabled by default on Fedora, and that is a good thing. It can prevent an OpenVPN process from reading files with unexpected labels or writing logs to unintended locations.
After copying certificates and creating configuration files, restore the correct contexts:
sudo restorecon -Rv /etc/openvpn
Fedora’s OpenVPN documentation specifically calls out this step after placing keys and configuration files under /etc/openvpn. [16]
Check for SELinux denials if the service fails:
sudo ausearch -m avc -ts recent
Do not disable SELinux to solve a VPN problem. In most cases, restoring contexts, placing logs in an approved location, or adding a targeted local policy is the correct fix.
Start and Enable OpenVPN
Fedora uses template systemd units. The service name matches the configuration filename, minus the .conf extension.
With a file named /etc/openvpn/server/server.conf, start:
sudo systemctl enable --now openvpn-server@server
Check its status:
sudo systemctl status openvpn-server@server
Confirm the tunnel interface exists:
ip addr show tun0
Check that OpenVPN is listening:
sudo ss -lunp | grep 1194
You should see a UDP socket bound to port 1194.
Review logs if something fails:
sudo journalctl -u openvpn-server@server -e
sudo tail -n 100 /var/log/openvpn.log
Create a Client Certificate
Each user or device should have its own certificate. Sharing one client certificate across a team makes revocation and auditing difficult.
From the Easy-RSA directory:
cd /etc/openvpn/easy-rsa
sudo ./easyrsa build-client-full alice
Easy-RSA will prompt for a passphrase for the client key. For laptop and mobile users, a passphrase-protected key is strongly recommended. If the device is lost, the certificate alone is not enough for someone to connect.
Copy the required files into a staging directory:
sudo mkdir -p /tmp/openvpn-client-alice
sudo cp pki/ca.crt /tmp/openvpn-client-alice/
sudo cp pki/issued/alice.crt /tmp/openvpn-client-alice/
sudo cp pki/private/alice.key /tmp/openvpn-client-alice/
sudo cp /etc/openvpn/server/tls-crypt.key /tmp/openvpn-client-alice/
Transfer those files securely to the client. Then remove the temporary directory from the server:
sudo rm -rf /tmp/openvpn-client-alice
Create an Inline Client Profile
An .ovpn profile is convenient because it bundles the configuration, CA certificate, client certificate, client key, and TLS key into one file.
Create a base client configuration:
sudo nano /tmp/client-base.conf
Use the following:
client
dev tun
proto udp
remote vpn.example.com 1194
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
auth SHA256
data-ciphers AES-256-GCM:AES-128-GCM
verb 3
Replace vpn.example.com with your server’s public hostname or IP address.
Now build the inline profile:
cd /etc/openvpn/easy-rsa
{
cat /tmp/client-base.conf
echo '<ca>'
sudo cat pki/ca.crt
echo '</ca>'
echo '<cert>'
sudo cat pki/issued/alice.crt
echo '</cert>'
echo '<key>'
sudo cat pki/private/alice.key
echo '</key>'
echo '<tls-crypt>'
sudo cat /etc/openvpn/server/tls-crypt.key
echo '</tls-crypt>'
} | sudo tee /tmp/alice.ovpn > /dev/null
Move the profile somewhere secure and transfer it to the user:
sudo chown $(whoami):$(whoami) /tmp/alice.ovpn
After transfer, delete it from the server:
rm /tmp/alice.ovpn /tmp/client-base.conf
For Linux clients using NetworkManager, install the OpenVPN plugin:
sudo dnf install -y NetworkManager-openvpn NetworkManager-openvpn-gnome
Then import the profile through the desktop network settings, or use nmcli if you prefer the terminal.
Test the VPN Connection
On a client machine, import alice.ovpn and connect.
Then verify the tunnel:
ip addr show tun0
Check the assigned VPN address:
ip route
Test general connectivity:
ping -c 4 1.1.1.1
curl -4 https://ifconfig.me
If curl returns the VPN server’s public IP, full-tunnel routing and NAT are working. If it returns the client’s original IP, the client connected but redirect-gateway or masquerading is not configured correctly.
On the server, watch live connections:
sudo tail -f /var/log/openvpn.log
Or inspect connected clients:
cat /var/log/openvpn-status.log
Common OpenVPN Problems and Fixes
The service fails to start
Run:
sudo journalctl -u openvpn-server@server -xe
Typical causes include:
- A wrong certificate or key path in
server.conf - A missing
dh.pemfile - Incorrect permissions on
server.key - A typo in
tls-crypt - SELinux denying access to a file
Check paths first. Then run:
sudo restorecon -Rv /etc/openvpn
sudo systemctl restart openvpn-server@server
Clients connect but cannot access the internet
This almost always means one of three things:
- IP forwarding is disabled.
- firewalld masquerading is missing.
- The client is not receiving the
redirect-gatewaydirective.
Verify:
sysctl net.ipv4.ip_forward
sudo firewall-cmd --query-masquerade
Both should indicate that forwarding and masquerading are enabled.
The VPN connects but DNS does not work
The client may be using a DNS server unreachable through the tunnel. Push reliable DNS servers:
push "dhcp-option DNS 1.1.1.1"
push "dhcp-option DNS 1.0.0.1"
For a corporate VPN, push internal DNS servers instead, provided they are reachable from the VPN subnet.
UDP port 1194 is blocked
Some networks block UDP entirely or restrict nonstandard outbound traffic. Test from the client:
nc -vzu vpn.example.com 1194
If UDP is blocked, configure OpenVPN on TCP 443 as a fallback. It is not always the fastest option, but it can get users connected from restrictive networks.
A second OpenVPN instance can listen on TCP 443 while the primary instance remains on UDP 1194. Use a separate configuration file, such as /etc/openvpn/server/server-tcp.conf, and start:
sudo systemctl enable --now openvpn-server@server-tcp
Remember to open TCP 443 in firewalld and ensure no web server is already using that port.
Certificate errors appear
Common messages include certificate is not yet valid, certificate has expired, or unable to get local issuer certificate.
Check time synchronization:
timedatectl
Then inspect certificate dates:
sudo openssl x509 -enddate -noout -in /etc/openvpn/server/server.crt
If the CA certificate expired, you generally need to build a new PKI and reissue client certificates. Plan CA expiry carefully; a ten-year CA lifetime is common, while client certificates should expire much sooner.
A client certificate must be revoked
Revoke the certificate:
cd /etc/openvpn/easy-rsa
sudo ./easyrsa revoke alice
sudo ./easyrsa gen-crl
Copy the new certificate revocation list to the server:
sudo cp pki/crl.pem /etc/openvpn/server/crl.pem
Add this to server.conf:
crl-verify /etc/openvpn/server/crl.pem
Restart OpenVPN:
sudo systemctl restart openvpn-server@server
Without a CRL, revoking a certificate does not actually prevent it from connecting.