Install a VPN on a Linux VPS: WireGuard vs OpenVPN
Turning a VPS (Virtual Private Server) into a VPN (Virtual Private Network) lets you secure a connection from a public network, reach internal services without exposing them to the whole Internet, or route traffic through your server’s dedicated IP address. The VPN encrypts the connection between your devices and the VPS, but it does not make you anonymous: traffic then reaches the Internet from the server’s IP address.
In this guide, we will cover two simple options. WireGuard is the modern choice: lightweight, fast, integrated into recent Linux kernels, and easy to use every day. OpenVPN is the long-standing reference: heavier, but very flexible, especially when you need TCP or a common port such as 443.
Which VPN should you choose for your VPS?
For a new setup, start with WireGuard in most cases. The configuration is shorter, performance is excellent, and the clients for Windows and Linux are straightforward.
Choose OpenVPN when you have a specific compatibility requirement: a very restricted network, mandatory TCP, a required port, an existing client deployment, or an infrastructure that already depends on it.
In practice:
- WireGuard is recommended for a fast modern private VPN.
- OpenVPN is recommended when network compatibility matters more than simplicity.
- Avoid installing both on the same VPS unless you really need both.
Requirements
Before you begin, you need:
- a Linux VPS with root or sudo access.
- Ubuntu 24.04 or a recent Debian release.
- a public IPv4 address or a domain name pointing to the VPS.
- access to the server firewall and, if your provider offers one, to the external network firewall.
- a working SSH session before changing any firewall rule.
The examples below use 203.0.113.10 as a documentation IP address. Replace it with your VPS public address.
The profiles below route IPv4 traffic only. If your device uses IPv6, configure it in the VPN as well or disable it on that connection so that it does not bypass the tunnel.
Prepare the server
Connect to the VPS over SSH. Check that its clock is synchronized because OpenVPN certificates depend on the correct date. Then enable IPv4 forwarding, which is required for the VPS to pass VPN traffic to the Internet:
timedatectl status
sudo tee /etc/sysctl.d/99-vpn-forward.conf > /dev/null <<'EOF'
net.ipv4.ip_forward=1
EOF
sudo sysctl -p /etc/sysctl.d/99-vpn-forward.conf
The last command must display net.ipv4.ip_forward = 1. Then choose the VPN you want to install and follow only the corresponding section. The commands use packages provided by Ubuntu 24.04 and recent Debian releases. No remote installation script is downloaded.
Install WireGuard
Install WireGuard and the routing commands used by the configuration:
sudo apt update
sudo apt install -y wireguard iptables
Create one key pair for the server and another for the first client computer, named client here:
sudo install -d -m 700 /etc/wireguard
sudo sh -c 'umask 077; wg genkey > /etc/wireguard/server.key'
sudo sh -c 'wg pubkey < /etc/wireguard/server.key > /etc/wireguard/server.pub'
sudo sh -c 'umask 077; wg genkey > /etc/wireguard/client.key'
sudo sh -c 'wg pubkey < /etc/wireguard/client.key > /etc/wireguard/client.pub'
Create the wg0 interface. The PostUp and PostDown rules only allow forwarding VPN traffic and applying NAT through the main network interface. They do not change inbound rules or SSH access.
WAN_IF=$(ip route show default | awk '{print $5; exit}')
CLIENT_PUBLIC_KEY=$(sudo cat /etc/wireguard/client.pub)
sudo tee /etc/wireguard/wg0.conf > /dev/null <<EOF
[Interface]
Address = 10.66.66.1/24
ListenPort = 51820
PostUp = wg set %i private-key /etc/wireguard/server.key
PostUp = iptables -I FORWARD 1 -i %i -o $WAN_IF -j ACCEPT; iptables -I FORWARD 1 -i $WAN_IF -o %i -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT; iptables -t nat -A POSTROUTING -s 10.66.66.0/24 -o $WAN_IF -j MASQUERADE
PostDown = iptables -C FORWARD -i %i -o $WAN_IF -j ACCEPT 2>/dev/null && iptables -D FORWARD -i %i -o $WAN_IF -j ACCEPT || true; iptables -C FORWARD -i $WAN_IF -o %i -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 2>/dev/null && iptables -D FORWARD -i $WAN_IF -o %i -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT || true; iptables -t nat -C POSTROUTING -s 10.66.66.0/24 -o $WAN_IF -j MASQUERADE 2>/dev/null && iptables -t nat -D POSTROUTING -s 10.66.66.0/24 -o $WAN_IF -j MASQUERADE || true
[Peer]
PublicKey = $CLIENT_PUBLIC_KEY
AllowedIPs = 10.66.66.2/32
EOF
sudo chmod 600 /etc/wireguard/wg0.conf
Start WireGuard and enable it automatically with the VPS:
sudo systemctl enable --now wg-quick@wg0
Create the Windows or Linux client profile. The command asks for the public IP address or DNS name of the VPS so that no example value remains in the file:
SERVER_PUBLIC_KEY=$(sudo cat /etc/wireguard/server.pub)
CLIENT_PRIVATE_KEY=$(sudo cat /etc/wireguard/client.key)
read -rp "Public IP address or DNS name of the VPS: " VPN_ENDPOINT
install -m 600 /dev/null "$HOME/client.conf"
tee "$HOME/client.conf" > /dev/null <<EOF
[Interface]
PrivateKey = $CLIENT_PRIVATE_KEY
Address = 10.66.66.2/32
DNS = 1.1.1.1, 1.0.0.1
[Peer]
PublicKey = $SERVER_PUBLIC_KEY
Endpoint = $VPN_ENDPOINT:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25
EOF
unset CLIENT_PRIVATE_KEY
The client.conf profile is now in your home directory. From your Windows or Linux computer, retrieve it over SSH, then import it into the WireGuard app:
scp [email protected]:client.conf .
Run the scp command from your computer. Replace username with your SSH account and 203.0.113.10 with the VPS address.
On a headless Ubuntu or Debian client, also install resolvconf so that wg-quick applies the profile’s DNS line:
sudo apt install wireguard resolvconf
sudo install -m 600 client.conf /etc/wireguard/client.conf
sudo wg-quick up client
After importing the profile and storing an encrypted backup, delete the client private key and profile copies left on the VPS:
sudo rm -f /etc/wireguard/client.key
rm -f "$HOME/client.conf"
If your hosting provider applies an external network firewall, allow 51820/udp to the VPS. If UFW is already used locally, check its status and add the port:
sudo ufw status verbose
sudo ufw allow 51820/udp
If UFW is inactive, do not enable it automatically only to follow this guide. If you decide to enable it, allow the SSH port actually in use first. With an existing iptables policy, the temporary equivalent is:
sudo iptables -C INPUT -p udp --dport 51820 -j ACCEPT 2>/dev/null || sudo iptables -I INPUT -p udp --dport 51820 -j ACCEPT
Make this rule persistent using the mechanism already used on your server and do not mix multiple firewall managers.
An ufw reload or firewall rule reset can remove the direct forwarding and NAT rules. If this happens, restart wg-quick@wg0 to apply them again.
Once the client is connected, check the service and latest handshake:
sudo systemctl status wg-quick@wg0 --no-pager
sudo wg show
sudo sysctl net.ipv4.ip_forward
The client peer should show a recent handshake. From the connected computer, the public IP address should match the VPS address.
Always create a new key pair and address, for example 10.66.66.3/32, for each additional device. To revoke a device, remove its [Peer] block from /etc/wireguard/wg0.conf, then reload the configuration with sudo systemctl restart wg-quick@wg0. The other devices may take a few seconds to reconnect after this restart.
Install OpenVPN
Install OpenVPN and Easy-RSA, then prepare the certificate authority, server certificate and first client certificate:
sudo apt update
sudo apt install -y openvpn easy-rsa iptables
getent group openvpn > /dev/null || sudo groupadd --system openvpn
getent passwd openvpn > /dev/null || sudo useradd --system --gid openvpn --home-dir /nonexistent --shell /usr/sbin/nologin openvpn
sudo install -d -o root -g openvpn -m 750 /etc/openvpn/server
sudo make-cadir /etc/openvpn/easy-rsa
cd /etc/openvpn/easy-rsa
sudo ./easyrsa init-pki
sudo env EASYRSA_REQ_CN=Private-VPN-CA ./easyrsa build-ca
sudo ./easyrsa build-server-full server nopass
sudo ./easyrsa build-client-full client nopass
sudo env EASYRSA_CRL_DAYS=3650 ./easyrsa gen-crl
sudo openvpn --genkey tls-crypt /etc/openvpn/server/tc.key
sudo install -m 600 pki/ca.crt pki/private/server.key /etc/openvpn/server/
sudo install -m 644 pki/issued/server.crt /etc/openvpn/server/
sudo install -o root -g openvpn -m 640 pki/crl.pem /etc/openvpn/server/crl.pem
sudo chmod 600 /etc/openvpn/server/tc.key
Easy-RSA asks for a passphrase to protect the certificate authority private key. Keep it safe: it will be required to create or revoke profiles. The server and client keys remain without a passphrase so that the service and app can start automatically. The .ovpn file must therefore be protected like a private key.
The dedicated openvpn system account limits the service privileges. The revocation list remains readable by this account, unlike the private keys. Its validity is set to ten years to avoid the default expiration after 180 days, which would make new connections fail. Regenerate it before that deadline and after every revocation.
Easy-RSA 3.1.7 generates server and client certificates with a default validity of 825 days. Check and record their expiration dates during installation:
sudo openssl x509 -in /etc/openvpn/server/server.crt -noout -enddate
sudo openssl x509 -in /etc/openvpn/easy-rsa/pki/issued/client.crt -noout -enddate
Schedule their renewal before that date: a CRL that is still valid does not extend an expired certificate.
Add a local script that only manages OpenVPN routing and NAT. systemd will run it with the required privileges when the service starts and stops:
sudo tee /etc/openvpn/server/network.sh > /dev/null <<'EOF'
#!/bin/sh
WAN_IF=$(ip route show default | awk '{print $5; exit}')
DEV=tun0
case "$1" in
up)
iptables -C FORWARD -i "$DEV" -o "$WAN_IF" -j ACCEPT 2>/dev/null || iptables -I FORWARD 1 -i "$DEV" -o "$WAN_IF" -j ACCEPT
iptables -C FORWARD -i "$WAN_IF" -o "$DEV" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || iptables -I FORWARD 1 -i "$WAN_IF" -o "$DEV" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -t nat -C POSTROUTING -s 10.8.0.0/24 -o "$WAN_IF" -j MASQUERADE 2>/dev/null || iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o "$WAN_IF" -j MASQUERADE
;;
down)
iptables -C FORWARD -i "$DEV" -o "$WAN_IF" -j ACCEPT 2>/dev/null && iptables -D FORWARD -i "$DEV" -o "$WAN_IF" -j ACCEPT || true
iptables -C FORWARD -i "$WAN_IF" -o "$DEV" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 2>/dev/null && iptables -D FORWARD -i "$WAN_IF" -o "$DEV" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT || true
iptables -t nat -C POSTROUTING -s 10.8.0.0/24 -o "$WAN_IF" -j MASQUERADE 2>/dev/null && iptables -t nat -D POSTROUTING -s 10.8.0.0/24 -o "$WAN_IF" -j MASQUERADE || true
;;
*)
exit 2
;;
esac
EOF
sudo chmod 700 /etc/openvpn/server/network.sh
Create the server configuration on 1194/udp:
sudo tee /etc/openvpn/server/server.conf > /dev/null <<'EOF'
port 1194
proto udp4
dev tun0
ca ca.crt
cert server.crt
key server.key
dh none
tls-crypt tc.key
crl-verify /etc/openvpn/server/crl.pem
server 10.8.0.0 255.255.255.0
topology subnet
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
data-ciphers AES-256-GCM:AES-128-GCM:CHACHA20-POLY1305
tls-version-min 1.2
user openvpn
group openvpn
persist-key
persist-tun
explicit-exit-notify 1
verb 3
EOF
sudo install -d /etc/systemd/system/[email protected]
sudo tee /etc/systemd/system/[email protected]/firewall.conf > /dev/null <<'EOF'
[Service]
ExecStartPost=/etc/openvpn/server/network.sh up
ExecStopPost=/etc/openvpn/server/network.sh down
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now openvpn-server@server
Finally, build the self-contained client.ovpn profile in your home directory:
cd /etc/openvpn/easy-rsa
read -rp "Public IP address or DNS name of the VPS: " VPN_ENDPOINT
CA_CERT=$(sudo cat pki/ca.crt)
CLIENT_CERT=$(sudo sed -ne '/BEGIN CERTIFICATE/,$ p' pki/issued/client.crt)
CLIENT_KEY=$(sudo cat pki/private/client.key)
TLS_CRYPT_KEY=$(sudo cat /etc/openvpn/server/tc.key)
install -m 600 /dev/null "$HOME/client.ovpn"
tee "$HOME/client.ovpn" > /dev/null <<EOF
client
dev tun
proto udp4
remote $VPN_ENDPOINT 1194
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
verify-x509-name server name
tls-version-min 1.2
data-ciphers AES-256-GCM:AES-128-GCM:CHACHA20-POLY1305
verb 3
<ca>
$CA_CERT
</ca>
<cert>
$CLIENT_CERT
</cert>
<key>
$CLIENT_KEY
</key>
<tls-crypt>
$TLS_CRYPT_KEY
</tls-crypt>
EOF
unset CLIENT_KEY TLS_CRYPT_KEY
Copy this file to your computer. On Windows or Linux, import it into OpenVPN Connect using the file import option.
scp [email protected]:client.ovpn .
Run the scp command from your computer. Replace username with your SSH account and 203.0.113.10 with the VPS address.
After importing the profile and storing an encrypted backup, delete the client private key and profile copies left on the VPS. The public certificate remains in the PKI so it can be revoked:
sudo rm -f /etc/openvpn/easy-rsa/pki/private/client.key /etc/openvpn/easy-rsa/pki/inline/client.inline
rm -f "$HOME/client.ovpn"
If your hosting provider applies an external network firewall, allow 1194/udp. If UFW is already used, check its status and add the port:
sudo ufw status verbose
sudo ufw allow 1194/udp
If UFW is inactive, do not enable it automatically only to follow this guide. With an existing iptables policy, the temporary equivalent is:
sudo iptables -C INPUT -p udp --dport 1194 -j ACCEPT 2>/dev/null || sudo iptables -I INPUT -p udp --dport 1194 -j ACCEPT
Make this rule persistent using the mechanism already used on your server.
An ufw reload or firewall rule reset can remove the direct forwarding and NAT rules. If this happens, restart openvpn-server@server to apply them again.
This configuration uses 1194/udp, the recommended mode. If a network blocks UDP and you really need TCP on port 443, first check that no web server is using this port. Then replace port 1194 with port 443 and proto udp4 with proto tcp-server on the server. In the client profile, replace proto udp4 with proto tcp-client, use remote $VPN_ENDPOINT 443, and remove explicit-exit-notify 1 from the server. Finally allow 443/tcp instead of 1194/udp in the firewalls. TCP is generally less efficient than UDP and should remain a compatibility option.
Check the service and confirm that routing is enabled:
sudo systemctl status openvpn-server@server --no-pager
sudo journalctl -u openvpn-server@server -n 50 --no-pager
sudo sysctl net.ipv4.ip_forward
From the connected computer, the public IP address should match the VPS address.
To revoke the profile of a lost device, regenerate the revocation list and restart OpenVPN:
cd /etc/openvpn/easy-rsa
sudo env EASYRSA_BATCH=1 ./easyrsa revoke client
sudo env EASYRSA_BATCH=1 EASYRSA_CRL_DAYS=3650 ./easyrsa gen-crl
sudo install -o root -g openvpn -m 640 pki/crl.pem /etc/openvpn/server/crl.pem
sudo systemctl restart openvpn-server@server
Install the client app
The VPN server runs on your VPS, but every computer that connects to it also needs a client app.
For WireGuard, install the official app from the WireGuard download page:
- Windows and Linux: wireguard.com/install
For OpenVPN, choose the client for your device:
- Windows and Linux: install OpenVPN Connect for free. This official client accepts
.ovpnprofiles generated by OpenVPN Community Edition and does not require a subscription. - On a Linux computer with NetworkManager, you can also install
network-manager-openvpnand import the profile from the network settings. This integration handles DNS better than simply starting OpenVPN from the command line.
On a computer, the idea is simple: copy the configuration file generated by the VPS, then import it into the client app. WireGuard uses a .conf file, OpenVPN uses a .ovpn file.
Security best practices
A VPN gives access to your private network. Treat every client profile as a sensitive key.
- Never share a WireGuard
.conffile or an OpenVPN.ovpnfile publicly. - Create one profile per device.
- Revoke the profile of a lost device immediately.
- Delete unencrypted copies of profiles left on the VPS and your computer after import, unless they are kept in encrypted storage.
- Protect the passphrase and an encrypted backup of the OpenVPN certificate authority: its private key can sign new profiles.
- For a sensitive or multi-user deployment, ideally keep the OpenVPN certificate authority on a separate offline machine.
- A full tunnel is not automatically a kill switch: enable the client’s block-outside-VPN option or always-on VPN mode if no traffic may escape when the tunnel drops.
- Keep SSH open only to the IP addresses that need it when possible.
- Update the VPS regularly.
- Keep a copy of your client profiles in encrypted storage.
For personal use, WireGuard is often the easiest and smoothest solution. OpenVPN remains useful when you need to cross restrictive networks or keep compatibility with an existing setup. In both cases, a VPS gives you the freedom to host your own private gateway, with your own rules, ports and access control.
If you need a server for this kind of setup, you can start with a BoxToPlay VPS server with a dedicated IP, root access, backups and a configurable hardware firewall.
More Articles
Linux VPS: Essential Commands to Get Started
August 06, 2026BoxToPlay Partner Program
July 22, 2026Super Choupy, API and MCP: A Hosting Game Changer
July 16, 2026Minecraft and VPS Summer Sale: 60% Off BoxToPlay
July 06, 2026