A commercial VPN is a promise: we will not log you, trust us. A self-hosted VPN is a fact: the only logs are the ones you configure, on a server only you can reach. WireGuard makes the second option a ten-minute job.
This is the complete setup on a fresh Ubuntu VPS, with the hardening most tutorials skip, and an honest answer to whether you should bother.
Is a self-hosted VPN worth it?
It depends on what you want from a VPN.
If you want to hide in a crowd, a commercial VPN is better: thousands of users share each exit IP, so a site seeing that IP learns nothing about you. On your own server you are the only user of that IP; a site can tie every visit from it to one person, even if it cannot tell who.
If you want to control the endpoint, self-hosting wins outright: nobody else's traffic, nobody else's logging policy, no app phoning home, a fixed IP that does not get blocklisted because a stranger abused it yesterday, and a place to run other things (a private DNS resolver, a file sync, a Tor bridge). It also costs a few dollars a month instead of a subscription.
Most people who search "how to self-host a VPN" want the second thing: an encrypted tunnel out of a hostile or nosy network (hotel wifi, a corporate network, a country that filters), terminating on a box they own. That is exactly what follows. We wrote separately about why a VPN alone is not privacy; keep those limits in mind.
WireGuard vs OpenVPN
WireGuard is about 4,000 lines of code, lives in the Linux kernel, uses one modern cipher suite with no negotiation, and connects in a single round trip. OpenVPN is a hundred times larger, runs in userspace, and carries two decades of options. WireGuard is faster on the same hardware, simpler to audit, and reconnects instantly when your phone changes networks. Use OpenVPN only if you need something WireGuard deliberately does not do, such as TCP transport to escape a network that blocks UDP. Otherwise, WireGuard.
What you need
- A VPS running Ubuntu 24.04 (Debian 12 or 13 is identical apart from package names). Any small plan is plenty; a VPN moves packets, not CPU. The location decides where your traffic exits, so pick one close to you or in the jurisdiction you want.
- Root or sudo over SSH.
- Ten minutes.
Step 1: install WireGuard
sudo apt update
sudo apt install -y wireguard qrencode
qrencode is for the phone client later.
Step 2: generate the server keys
umask 077
wg genkey | sudo tee /etc/wireguard/server_private.key | wg pubkey | sudo tee /etc/wireguard/server_public.key
The umask line makes the key files readable by root only. Keep it.
Step 3: write the server configuration
Find your public network interface name with ip route get 1.1.1.1; it is usually eth0 or ens18. Then create /etc/wireguard/wg0.conf:
[Interface]
Address = 10.8.0.1/24
ListenPort = 51820
PrivateKey = <contents of server_private.key>
PostUp = iptables -t nat -A POSTROUTING -o ens18 -j MASQUERADE
PostDown = iptables -t nat -D POSTROUTING -o ens18 -j MASQUERADE
Replace ens18 with your interface. The PostUp rule makes the server NAT your client traffic out to the internet, which is the entire point.
Step 4: enable IP forwarding
echo 'net.ipv4.ip_forward=1' | sudo tee /etc/sysctl.d/99-wireguard.conf
sudo sysctl --system
Without this the server accepts the tunnel and silently drops everything you send through it, which is the most common "it connects but nothing loads" problem.
Step 5: open the port
WireGuard listens on UDP 51820 by default. If you use ufw:
sudo ufw allow 51820/udp
sudo ufw allow OpenSSH
sudo ufw enable
If your host has a cloud firewall in the panel, allow UDP 51820 there too.
Step 6: start it
sudo systemctl enable --now wg-quick@wg0
sudo wg
sudo wg should show the interface, its public key and the listening port.
Step 7: add a client (your phone or laptop)
Each client needs its own key pair and an address in the 10.8.0.0/24 range. Generate them on the server for convenience:
wg genkey | tee phone_private.key | wg pubkey > phone_public.key
Append the client to the server's wg0.conf:
[Peer]
PublicKey = <contents of phone_public.key>
AllowedIPs = 10.8.0.2/32
Reload without dropping existing tunnels:
sudo wg syncconf wg0 <(sudo wg-quick strip wg0)
Now write the client's own config, phone.conf:
[Interface]
PrivateKey = <contents of phone_private.key>
Address = 10.8.0.2/32
DNS = 1.1.1.1
[Peer]
PublicKey = <contents of server_public.key>
Endpoint = YOUR.SERVER.IP:51820
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25
AllowedIPs = 0.0.0.0/0 sends all traffic through the tunnel. Change it to just 10.8.0.0/24 if you only want to reach the server's private network. Show it as a QR code and scan it with the WireGuard app:
qrencode -t ansiutf8 < phone.conf
Delete phone_private.key from the server afterwards; the private key belongs on the phone only.
Step 8: the two settings that decide whether it logs
WireGuard itself keeps no connection log, but the system around it can.
The kernel's peer state. wg show displays each peer's last handshake time and endpoint IP while the tunnel is up. That is in memory only and vanishes on reboot, but it is there. If you care, do not leave wg show output in shell histories or monitoring.
DNS. Whatever DNS = you set in the client is who sees every domain you visit. 1.1.1.1 is a reasonable default; running Unbound on the same VPS, so DNS never leaves your box, is the better one and takes five more minutes.
Also check that the server itself is not logging: no iptables LOG rules, and journald retention set low if you want minimal traces (SystemMaxUse=50M in /etc/systemd/journald.conf).
Hardening in five lines
- SSH by key only:
PasswordAuthentication noin/etc/ssh/sshd_config. - Automatic security updates:
sudo apt install unattended-upgrades. - Move the WireGuard port off 51820 if your network fingerprints it; any UDP port works.
- One peer per device, so revoking a lost phone is deleting one
[Peer]block. - Back up
/etc/wireguard/somewhere encrypted; it is your whole VPN.
Picking the server
The server's IP is the address the internet sees, so the provider and the country matter more than they do for a web server. On Servury the account is a credential rather than an identity, payment can be crypto, and there are no access logs, so the VPN endpoint is not linked back to you by the host. The WireGuard VPS page covers locations and the questions people ask before they buy; any plan from $9.99 runs WireGuard with room to spare.
Frequently asked questions
How do I set up WireGuard on a VPS?
Install the package, generate a key pair, write /etc/wireguard/wg0.conf with an address, port and NAT rule, enable IP forwarding, open UDP 51820, start wg-quick@wg0, then add each client as a [Peer] with its own key. The steps above take about ten minutes.
Is a self-hosted VPN worth it?
For controlling your own exit point, avoiding shared blocklisted IPs, and knowing exactly what is logged: yes. For blending into a crowd of users: no, a commercial VPN does that better.
WireGuard vs OpenVPN: which should I use?
WireGuard, unless you specifically need TCP transport. It is faster, far smaller, and simpler to configure and audit.
Can I use one server for several devices?
Yes. Add a [Peer] block per device, each with a unique key and a unique address in the tunnel subnet.
Does WireGuard log my traffic?
Not to disk. It keeps peer handshake state in memory while running. What gets logged is decided by the rest of the server: your DNS resolver, your firewall rules, and journald.







