Why Run Your Own VPN Instead of Paying for One
Commercial VPN services have become a crowded market, with dozens of providers competing on price, speed, and privacy promises. The problem is that using any third-party VPN means trusting that provider with every request your device makes – their logs, their infrastructure, their jurisdiction. WireGuard, the modern VPN protocol built directly into the Linux kernel since version 5.6, gives you the tools to cut that dependency entirely and run a private tunnel on hardware you control.
Setting up WireGuard as a self-hosted VPN server is less complicated than most people expect. You need a Linux server with a public IP address – a cheap VPS from any major cloud provider works fine – and about 30 minutes. What you get at the end is a fast, encrypted tunnel between your devices and that server, with no subscription fees, no usage logs you didn’t create, and no company whose privacy policy you need to read twice a year when it quietly changes.

Preparing the Server
Start with a fresh Ubuntu 22.04 or Debian 12 instance. WireGuard is available directly from the default repositories on both, so installation is a single command. Log in as root or a user with sudo privileges and run sudo apt update && sudo apt install wireguard -y. Once that completes, you’ll also want to install resolvconf if you plan to use WireGuard’s built-in DNS management: sudo apt install resolvconf -y. The WireGuard tools include wg for configuration management and wg-quick for bringing interfaces up and down using config files, which is what most people use in practice.
Before touching any WireGuard configuration, enable IP forwarding on the server. This is what allows traffic from your connected clients to actually route out through the server’s network interface rather than stopping at the tunnel endpoint. Open /etc/sysctl.conf and uncomment or add the line net.ipv4.ip_forward=1. Apply it immediately without rebooting by running sudo sysctl -p. If you’re on a server behind a firewall – most cloud VPS instances are – you’ll need to open UDP port 51820 in your provider’s security group or firewall rules. WireGuard uses UDP exclusively, which is part of why its latency is so low compared to OpenVPN.

Generating Keys and Writing the Server Config
WireGuard uses public-key cryptography. Every peer in a WireGuard network – the server and each client – gets a private key and a corresponding public key. The private key never leaves the machine it was generated on. The public key is what you share with other peers so they can authenticate the connection. Generate the server’s key pair with these two commands run from the /etc/wireguard/ directory: wg genkey | tee privatekey | wg pubkey > publickey. This creates both files in one step. Lock down the private key immediately: chmod 600 /etc/wireguard/privatekey.
Now create the server configuration file at /etc/wireguard/wg0.conf. The wg0 name refers to the network interface WireGuard will create. A working base configuration looks like this:
[Interface]
Address = 10.0.0.1/24
ListenPort = 51820
PrivateKey = [paste server private key here]
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
The Address line sets the server’s IP within the private tunnel network – 10.0.0.1 is a common choice, and clients will get addresses in the same /24 range. The PostUp and PostDown lines handle NAT so traffic from tunnel clients can exit through the server’s main network interface. Replace eth0 with whatever your server’s primary interface is called – on some VPS instances it might be ens3 or ens18. You can check with ip link show.
Once the server config is written, enable and start the WireGuard service: sudo systemctl enable wg-quick@wg0 && sudo systemctl start wg-quick@wg0. Run sudo wg show to confirm the interface came up. You should see the interface name, public key, listening port, and an empty peers section – empty because no clients are added yet.
Adding a Client
Each device that connects to your WireGuard server is a peer, and each needs its own key pair. On a Linux client, generate keys the same way you did on the server. On iOS or Android, the WireGuard app can generate a key pair directly inside the app. On Windows or macOS, the official WireGuard GUI application handles this in the “Add Tunnel” screen. The workflow is always the same: generate a key pair on the client, add the client’s public key to the server config, and add the server’s public key to the client config.
On the server, add a [Peer] block to /etc/wireguard/wg0.conf for each client:
[Peer]
PublicKey = [client public key]
AllowedIPs = 10.0.0.2/32
The AllowedIPs value here restricts this peer to a single IP address within the tunnel – 10.0.0.2 for the first client, 10.0.0.3 for the second, and so on. Apply the change without restarting the interface using sudo wg addpeer, or simply restart the service with sudo systemctl restart wg-quick@wg0. The client config needs a corresponding [Interface] and [Peer] block pointing back at the server’s public IP and public key, with AllowedIPs = 0.0.0.0/0 if you want all traffic routed through the tunnel, or a specific subnet if you only want split-tunnel access.

Testing the Connection and Keeping It Running
After activating the tunnel on a client device, run ping 10.0.0.1 to confirm the tunnel is up and the server is responding. Then check your public IP from the client – if everything is routing correctly through the server, the IP address should match your VPS’s public IP rather than your local connection. The sudo wg show command on the server will now display the connected peer with a latest handshake timestamp, which updates roughly every two minutes when the connection is active. A handshake timestamp that’s several minutes old usually means a firewall is blocking the UDP port.
WireGuard’s built-in PersistentKeepalive setting handles one common problem: clients behind NAT that drop idle UDP connections. Adding PersistentKeepalive = 25 to the [Peer] block in the client config tells WireGuard to send a keepalive packet every 25 seconds, which keeps the NAT mapping alive on home routers and firewalls. For managing multiple clients or monitoring tunnel activity, pairing this setup with a metrics tool like Prometheus and Grafana gives you visibility into traffic patterns and uptime without relying on any external service. The server’s systemd service ensures WireGuard restarts automatically after a reboot, so the only ongoing maintenance is adding new peer blocks when you bring a new device onto the network – and revoking access is as simple as deleting that peer’s block and running sudo wg syncconf wg0 /etc/wireguard/wg0.conf.
Frequently Asked Questions
What kind of server do I need to run WireGuard?
Any Linux VPS with a public IP address works. Ubuntu 22.04 or Debian 12 are good choices since WireGuard is available directly from their default repositories.
Can I connect multiple devices to my WireGuard server?
Yes. Each device is added as a separate peer with its own key pair and an assigned IP address within the tunnel’s subnet.





