The first hands-on episode: installing OpenVPN on various platforms, understanding the OpenSSL and LZO dependencies, writing your first server.conf and client.ovpn, then verifying the tunnel is alive with ping.

The theory in episode 2 is enough. Now it's time to get your hands working: install OpenVPN and create a first configuration that actually runs. Episode 3 is a major milestone — by the end of this episode, your first VPN tunnel will be alive and pingable.
We will install on several platforms, understand the required dependencies, write server.conf and client.ovpn from scratch, then run the daemon and verify the connection. If anything fails, the troubleshooting section at the end of this episode will guide you step by step.
The installations below automatically bring two core dependencies: OpenSSL 3.x as the cryptography engine for TLS, and LZO as an optional compression library. Verify OpenSSL with openssl version after installation.
Debian and its derivatives provide OpenVPN in the official repositories:
apt update
apt install -y openvpn easy-rsaThe easy-rsa package is installed as well because it will be used in episode 4 to build your PKI. Make sure there are no errors at this stage before continuing.
For CentOS Stream, Rocky Linux, or AlmaLinux:
dnf install -y epel-release
dnf install -y openvpn easy-rsaEasy-RSA is available from EPEL, so the extra repository must be enabled first.
On macOS, Homebrew is the fastest way:
brew install openvpnNote: on macOS, the OpenVPN Connect or Tunnelblick clients are more commonly used for daily use. The brew install openvpn command provides the same CLI binary as Linux.
For a quick lab or isolation, the kylemanna/openvpn image is very popular:
docker run -v /etc/openvpn:/etc/openvpn --rm kylemanna/openvpn ovpn_genconfig -u udp://203.0.113.10The full Docker workflow will be used again in episodes 17 and 21. For now, a native VM installation makes understanding easier.
The most flexible way — and the least often needed:
apt install -y build-essential libssl-dev liblzo2-dev libpam0g-dev
curl -LO https://swupdate.openvpn.org/community/releases/openvpn-2.7.5.tar.gz
tar xzf openvpn-2.7.5.tar.gz && cd openvpn-2.7.5
./configure && make && make installThis path is useful if you need features not yet in your distro's packages. curl -LO is used to download the official release tarball.
Create the file /etc/openvpn/server/server.conf on the server side. This file is a condensed version of the production configuration we will refine in later episodes:
port 1194
proto udp
dev tun
ca ca.crt
cert server.crt
key server.key
dh dh.pem
topology subnet
server 10.8.0.0 255.255.255.0
keepalive 10 120
user nobody
group nogroup
persist-key
persist-tun
verb 3The directive server 10.8.0.0 255.255.255.0 creates the address pool for clients, while keepalive 10 120 sends a ping every 10 seconds and considers the connection dead if there is no response for 120 seconds.
systemctl enable --now openvpn-server@server
systemctl status openvpn-server@serverThe service openvpn-server@server reads the server.conf configuration in /etc/openvpn/server. The name after the at sign is the configuration filename without its extension.
On the client side, create the file client.ovpn. Notice the differences from the server: the client, remote, and nobind directives apply only to clients:
client
dev tun
proto udp
remote 203.0.113.10 1194
resolv-retry infinite
nobind
ca ca.crt
cert client.crt
key client.key
remote-cert-tls server
verb 3The remote-cert-tls server directive prevents man-in-the-middle attacks by ensuring the peer's certificate is truly a server certificate. remote 203.0.113.10 1194 points to the server address, filled in according to your lab.
The server must accept UDP 1194:
ufw allow 1194/udpFor cloud, also make sure the security group allows UDP 1194 from your client's address. This is the number one cause of first connection failures.
With the key material already prepared (episode 4 will cover how to create it), run the client:
openvpn --config client.ovpnRun it in the foreground so the logs appear immediately. If everything is correct, you will see the message Initialization Sequence Completed — the sign that the tunnel is active.
After the sequence completes, verify from the client:
ip addr show tun0
ping -c 4 10.8.0.1ping -c 4 10.8.0.1 tests connectivity to the server's address inside the tunnel. If replies come back, congratulations — your first VPN works and the basic lab is complete.
Options error: Unrecognized option or missing parameter(s): a typo in the directive name — double-check the spelling.TLS Error: Unroutable control packet received: server and client cannot reach each other, usually a firewall or remote address problem.Cannot open TUN/TAP dev /dev/net/tun: the tun device is not available — go back to episode 0.For deeper connection errors, we will discuss logging and troubleshooting techniques thoroughly in episode 8.
Key takeaways:
server.conf defines the client pool; client.ovpn defines the target server.remote-cert-tls server is required on the client to prevent MITM attacks.Initialization Sequence Completed.In the next episode, episode 4, we will build the PKI and certificate management with Easy-RSA — creating a CA, issuing server and client certificates, generating Diffie-Hellman parameters, and learning to revoke problematic certificates. This replaces the example keys we just used with keys you truly control.