In 2012, I wrote an article on how to set up a VPN using OpenVPN. With so many companies offering VPN services nowadays, I thought it would be a good idea to run your own VPN service; however, WireGuard is a much better fit for this goal.

WireGuard is a modern VPN protocol built into the Linux kernel since version 5.6. Compared to OpenVPN, it is significantly simpler to configure, faster, and has a much smaller attack surface (~4000 lines of code vs ~100,000 for OpenVPN).

Prefer OpenVPN? See How to set up an OpenVPN server and client on Linux.

How WireGuard works

WireGuard uses public/private key pairs — similar to SSH keys. Each peer (server or client) has its own key pair. You add a peer's public key to your config, and WireGuard handles the rest. There are no certificates, no CA, no certificate revocation lists.

Install WireGuard

Debian / Ubuntu (kernel 5.6+, most current installs):

sudo apt install wireguard

RHEL / Fedora / Rocky Linux:

sudo dnf install wireguard-tools

Server setup

1. Generate server keys

wg genkey | tee server_private.key | wg pubkey > server_public.key

Keep server_private.key secret. You will share server_public.key with clients.

2. Create the server config

Create /etc/wireguard/wg0.conf:

[Interface]
Address    = 10.0.0.1/24
ListenPort = 51820
PrivateKey = <contents of server_private.key>

# Enable routing — forward all client traffic through this server
PostUp   = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

Replace eth0 with your server's public network interface (check with ip link show).

3. Enable IP forwarding

echo 'net.ipv4.ip_forward=1' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

4. Start WireGuard

sudo systemctl enable --now wg-quick@wg0
sudo systemctl status wg-quick@wg0

Client setup

1. Generate client keys

Run this on the client machine:

wg genkey | tee client_private.key | wg pubkey > client_public.key

2. Add the client as a peer on the server

Append to /etc/wireguard/wg0.conf on the server:

[Peer]
PublicKey  = <contents of client_public.key>
AllowedIPs = 10.0.0.2/32

Reload the server config without dropping existing connections:

sudo wg syncconf wg0 <(wg-quick strip wg0)

3. Create the client config

Create /etc/wireguard/wg0.conf on the client:

[Interface]
Address    = 10.0.0.2/24
PrivateKey = <contents of client_private.key>
DNS        = 1.1.1.1

[Peer]
PublicKey  = <contents of server_public.key>
Endpoint   = 12.34.56.78:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25
  • AllowedIPs = 0.0.0.0/0 routes all traffic through the VPN
  • PersistentKeepalive = 25 keeps the tunnel alive through NAT

4. Start the client

sudo systemctl enable --now wg-quick@wg0

Verify the connection

On the server, check connected peers and traffic:

sudo wg show

On the client, verify your public IP has changed:

curl ifconfig.me

Add more clients

Repeat the client steps for each new device. Generate a new key pair, assign a new IP (10.0.0.3/32, 10.0.0.4/32, etc.), and add a [Peer] block to the server config.

WireGuard vs OpenVPN

WireGuard OpenVPN
Configuration Simple key pairs PKI with CA and certificates
Speed Very fast (kernel-level) Slower (userspace)
Code size ~4,000 lines ~100,000 lines
Kernel integration Built-in (Linux 5.6+) Module or userspace
Mobile support Excellent (official apps) Good
Audit history Audited 2017 Long track record
Best for Most new setups Complex enterprise PKI needs

See also