JF / 2026
Available

Self-Hosted VPN — OpenVPN on a VPS, From Scratch

Rolling your own VPN instead of trusting a provider: SSH hardening, OpenVPN setup, certificate management, and the honest trade-offs — maintenance, attribution, and what a self-hosted tunnel does and does not protect against.

Watch video

Why self-host a VPN

Commercial VPNs are a commodity. A subscription buys access to a network of servers in dozens of countries, a polished client app, and a privacy policy that claims the provider does not log. For most users, that is a reasonable trade: a few euros a month, zero maintenance, and a service that works.

The trade-off is trust. A commercial VPN terminates your encrypted traffic at their server. They can see your IP address, the timing of your connections, the volume of your traffic, and — unless the traffic is also encrypted at the application layer (HTTPS, TLS) — its content. Their privacy policy may promise not to log, but the promise is unverifiable, and several providers have been caught breaking it, coerced by courts, or acquired by companies with different privacy postures.

A self-hosted VPN moves the trust from the provider to yourself. You rent a VPS, you install the VPN software, and you control the server. There is no third party who can be subpoenaed, no logging policy to trust, and no client app that might have been compromised. The trade-off is that you are now responsible for the maintenance, the configuration, and the security of the server.

This writeup covers the full setup: VPS selection, SSH hardening, OpenVPN installation, certificate management, firewall configuration, and the honest assessment of what a self-hosted VPN actually protects against. It is based on a common setup that has been documented in countless tutorials, but the security analysis is what most tutorials leave out.

Part one — VPS selection

The VPS is the foundation. The choice matters because it determines the cost, the performance, and the trust model.

Provider choice. The major providers — Hetzner, DigitalOcean, Linode (now Akamai), Vultr, OVH — all offer comparable VPS plans in the €4–6 per month range with 1 vCPU, 1GB RAM, and 20–40GB of SSD storage. That is more than sufficient for a VPN that serves a handful of clients. Higher-tier plans matter only if the VPN is expected to serve many concurrent users or handle high bandwidth.

Jurisdiction. The provider’s jurisdiction determines what legal process can compel the disclosure of data. A provider in a jurisdiction with strong privacy protections and a track record of resisting overbroad requests is preferable to one in a jurisdiction with weak protections. This is a consideration, not a decisive factor — a self-hosted VPN with no logs and no client list has little to disclose regardless of the jurisdiction.

Payment method. A provider that accepts cryptocurrency or anonymous payment methods allows the VPS to be rented without a personal identity being attached. Providers that require identity verification (KYC) — increasingly common, driven by regulatory pressure — eliminate this option. The choice depends on the threat model: for a user who simply wants their own VPN, KYC is fine; for a user who needs the VPN to be anonymous, KYC is a problem.

The alternative: dedicated hardware in a datacenter. A variation on the same idea is to colocate a small physical server in a datacenter rather than renting a virtual one. This is more expensive and more involved, but it eliminates the hypervisor as a trust point — the datacenter operator provides power and network, but cannot inspect the running machine. It is overkill for most users.

Part two — SSH hardening

The first thing to configure on a fresh VPS is SSH. The default configuration on most distributions is functional but not secure: it uses the standard port (22), and it accepts password authentication. Both are attack surfaces.

The hardening has two parts: change the port and switch to key-only authentication.

Part 2a — SSH keys.

If you do not already have an SSH key pair, generate one on your local machine:

ssh-keygen -t ed25519 -a 100 -f ~/.ssh/vpn_server

The -t ed25519 flag specifies the key type. Ed25519 is the modern choice — smaller keys, faster operations, and no known weaknesses. RSA is the legacy option; it works but is slower and larger. The -a 100 flag specifies the number of KDF rounds, which slows down brute-force attempts against a stolen private key. The -f flag sets the filename.

The command produces two files: vpn_server (the private key) and vpn_server.pub (the public key). The private key stays on your local machine and is never transmitted. The public key goes on the server.

Part 2b — copy the key to the server.

The initial connection to a fresh VPS uses password authentication. Use that one time to copy the public key:

ssh-copy-id -i ~/.ssh/vpn_server.pub root@<server-ip>

The ssh-copy-id command appends the public key to ~/.ssh/authorized_keys on the server. After this, you can connect using the key instead of the password:

ssh -i ~/.ssh/vpn_server root@<server-ip>

Part 2c — disable password authentication.

Once key-based login is confirmed working, edit the SSH daemon configuration:

sudo nano /etc/ssh/sshd_config

Change the following lines:

PasswordAuthentication no
PubkeyAuthentication yes
PermitRootLogin prohibit-password

The first disables password authentication entirely. The second ensures key authentication is enabled (which it should be by default). The third prevents root from logging in with a password while still allowing key-based root login — a middle ground. Some guides recommend PermitRootLogin no entirely and creating a separate user; that is more secure but requires additional setup. For a personal VPS, prohibit-password is a reasonable compromise.

Part 2d — change the SSH port.

Edit the same file and uncomment or add:

Port 22022

Choose a port above 1024 and below 65535, avoiding well-known service ports (80, 443, 3306, 8080, etc.). The exact number is not important — any non-standard port eliminates the vast majority of automated scanning and brute-force attempts, which target port 22 by default.

After changing the config, restart the SSH daemon:

sudo systemctl restart sshd

Important: before closing your current session, open a second terminal and verify that the new configuration works. If you disable password authentication and lock yourself out, recovering access requires contacting the provider and using a recovery console. Verify first, disconnect second.

Part 2e — install fail2ban.

Fail2ban monitors authentication logs and blocks IP addresses that fail authentication repeatedly. Even with password authentication disabled, a basic fail2ban installation reduces log noise and blocks scanners:

sudo apt install fail2ban
sudo systemctl enable fail2ban

The default configuration is usually sufficient. For finer control, adjust /etc/fail2ban/jail.local.

Part three — OpenVPN installation

OpenVPN is the traditional choice for self-hosted VPNs. WireGuard is the modern alternative — faster, simpler, and easier to configure — but it has different characteristics that some use cases do not accommodate. This writeup covers OpenVPN because it is the one in the video, and because it remains the most widely supported option.

Part 3a — install the server package.

On Debian or Ubuntu:

sudo apt update
sudo apt install openvpn easy-rsa

The easy-rsa package provides the scripts for managing the certificate authority, which is how OpenVPN authenticates clients and servers.

Part 3b — set up the certificate authority.

Easy-RSA expects its configuration in a specific directory. Copy the templates:

make-cadir ~/openvpn-ca
cd ~/openvpn-ca

Edit the vars file to set the certificate parameters (country, province, organization, email). These appear in the generated certificates and are not functionally important, but they should be set consistently:

nano vars

The KEY_NAME, KEY_OU, and KEY_CN values are the important ones — they affect the file names and the certificate subjects.

Part 3c — build the CA and server certificates.

Source the variables and run the build scripts:

source vars
./clean-all
./build-ca

The build-ca command generates the root certificate authority. You will be prompted for a passphrase — use a strong one and remember it.

Next, build the server certificate:

./build-key-server server

The server argument sets the common name to “server”, which must match the OpenVPN server configuration.

Generate the Diffie-Hellman parameters, which are used for key exchange:

./build-dh

This step takes several minutes — the DH parameter generation is intentionally slow.

Generate the HMAC signature to protect against TLS vulnerabilities:

openvpn --genkey secret ta.key

Part 3d — build client certificates.

For each client (each device that will connect), generate a separate certificate:

./build-key client1
./build-key client2
./build-key client3

Each certificate is unique. If a device is lost or compromised, its certificate can be revoked without affecting the others. This is the fundamental advantage of certificate-based authentication over shared keys.

Part four — server configuration

OpenVPN needs a server configuration file and a set of files from the CA directory.

Part 4a — copy the server files.

sudo cp ~/openvpn-ca/keys/ca.crt /etc/openvpn/
sudo cp ~/openvpn-ca/keys/server.crt /etc/openvpn/
sudo cp ~/openvpn-ca/keys/server.key /etc/openvpn/
sudo cp ~/openvpn-ca/keys/dh2048.pem /etc/openvpn/
sudo cp ~/openvpn-ca/keys/ta.key /etc/openvpn/

Part 4b — write the server configuration.

Create /etc/openvpn/server.conf:

port 1194
proto udp
dev tun

ca ca.crt
cert server.crt
key server.key
dh dh2048.pem
tls-auth ta.key 0

server 10.8.0.0 255.255.255.0
ifconfig-pool-persist ipp.txt

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
cipher AES-256-GCM

user nobody
group nogroup
persist-key
persist-tun

status openvpn-status.log
verb 3

The key directives:

Part 4c — enable IP forwarding.

The server needs to forward packets between the VPN interface and the public interface:

sudo nano /etc/sysctl.conf

Uncomment or add:

net.ipv4.ip_forward=1

Apply the change:

sudo sysctl -p

Part 4d — configure NAT.

The server must translate packets from the VPN subnet to the public interface:

sudo iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE

Replace eth0 with the actual public interface name (ip a shows the interfaces). To make the rule persistent across reboots, use iptables-persistent:

sudo apt install iptables-persistent
sudo netfilter-persistent save

Part 4e — start the server.

sudo systemctl start openvpn@server
sudo systemctl enable openvpn@server

Check the status:

sudo systemctl status openvpn@server

Part five — client configuration

The client needs the CA certificate, its own certificate and key, and the ta.key.

Part 5a — create the client configuration file.

Create a file (e.g., client1.ovpn) with the following content:

client
dev tun
proto udp
remote <server-ip> 1194
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
cipher AES-256-GCM
verb 3

<ca>
-----BEGIN CERTIFICATE-----
... contents of ca.crt ...
-----END CERTIFICATE-----
</ca>

<cert>
-----BEGIN CERTIFICATE-----
... contents of client1.crt ...
-----END CERTIFICATE-----
</cert>

<key>
-----BEGIN PRIVATE KEY-----
... contents of client1.key ...
-----END PRIVATE KEY-----
</key>

<tls-auth>
-----BEGIN OpenVPN Static key V1-----
... contents of ta.key ...
-----END OpenVPN Static key V1-----
</tls-auth>
key-direction 1

The inline format embeds all the certificates into a single file, which is convenient for distribution. The key-direction 1 directive must match the 0 on the server side.

Part 5b — distribute the file.

The .ovpn file contains the client’s private key. It must be transmitted securely — not over email, not over a chat that retains history. Options: physical transfer (USB drive), encrypted email, or a self-destructing message service.

Part 5c — install the client.

On desktop, install the OpenVPN client (openvpn package on Linux, OpenVPN Connect on Windows/macOS). Import the .ovpn file and connect. On mobile, OpenVPN Connect (iOS/Android) accepts the same file.

Part six — what this protects against (and what it does not)

The honest assessment of a self-hosted VPN’s security properties.

What it protects against:

What it does not protect against:

Operational considerations:

Part seven — the broader lesson

Self-hosting a VPN is an exercise in accepting responsibility. The convenience of a commercial VPN is that someone else handles the maintenance, the updates, the scaling, and the customer support. The cost is that you have to trust that someone else. Self-hosting removes the trust requirement and replaces it with a maintenance requirement.

The trade-off is not for everyone. For a user whose threat model is “I do not want my ISP to see my traffic”, a commercial VPN is sufficient and the trust assumption is acceptable. For a user whose threat model includes the possibility of the provider being compelled to disclose data, being breached, or being acquired by a company with different practices, self-hosting is a reasonable response.

The technical setup is not hard. The SSH hardening, the OpenVPN configuration, the certificate management — all of it is documented, and the process is a few hours of work. The hard part is the ongoing commitment: keeping the server patched, monitoring the logs, and responding to incidents. A self-hosted VPN that is set up once and forgotten is less secure than a commercial VPN with a good track record, because the unpatched server is a bigger risk than the trusted provider.

Takeaway

A self-hosted VPN on a VPS is a way to own the trust assumptions that commercial VPNs ask you to accept. It is not a way to become anonymous, it is not a way to defeat device identification, and it is not a way to hide from a state-level adversary. It is a way to control the network layer, and only the network layer.

The setup is accessible: rent a VPS, harden SSH, install OpenVPN, configure certificates, and connect clients. The maintenance is the real cost, and it is ongoing. The user who understands both the technical and the operational aspects makes a better decision than the user who follows a tutorial and assumes the result is a complete privacy solution.

The VPN is one layer. The value of self-hosting is that you own it. The limitation is that one layer is all it is.

Back