Blog

Self-hosted WireGuard vs a VPN service

We timed a WireGuard server build on Debian, key generation to first handshake, then set its upkeep against what a VPN service does for you.

Published October 16, 2026 · 11 minutes read

Key takeaways

  • wireguard-tools on Debian 13: 5.401 seconds of elapsed time, gaps between commands included, from first key to a fetch through the NAT in run 3; installing the packages took over 200 seconds under emulation.
  • The first run failed on one line: with ip_forward at 0 the handshake and ping worked, but the fetch through the NAT timed out.
  • Four upkeep jobs were outside the run: boot persistence, firewall persistence and config backups were never tried, and updates were installed once but not tested.
  • My exits, ForestVPN's home-computer exit, runs the self-hosted idea on every plan; a rented server gives you one exit address under your billing identity.
  • The Noise_IKpsk2 handshake is the same on both sides, so the choice is about who does the work around it.
On this page (7)

Our first run handshook, answered three pings and still failed the fetch. The clean runs went from first key to a fetched page in one short stretch; the job around the tunnel takes the time.

We timed it: two Debian containers, a server and a client, plus a plain target to fetch from, from installing the tools to a fetch through the server's NAT (network address translation), with a clock on every step.

Is a self-hosted WireGuard server worth it, or should you use a VPN service?

For one person who wants one exit address and enjoys owning the settings, a self-hosted server is worth it. For everyone who wants apps on every device and a status they can read, a service saves more work than a server does. We did not compare cost.

The tunnel itself is not where the two differ.

WireGuard's protocol page names its construction, the key-exchange pattern WireGuard runs when two ends meet, as Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s, and ForestVPN's core uses the same unmodified Noise_IKpsk2 handshake (protocol page). What differs is who does the work around it.

Choose a self-hosted server if you:

  • want to read every line of your own configuration;
  • are happy to patch a machine and to be the only person who can fix it;
  • need one fixed address that only you use.

A service fits better if you:

  • want apps for phones, TVs and laptops instead of a config file per device;
  • want to see whether data flows, in words, instead of reading wg show;
  • would rather the keeping-up was somebody's job.

Other options, and where to read about them:

This post is about the build-or-buy decision.

How long does it take to set up a WireGuard server?

In run 3 the elapsed time from the first key to a page fetched through the server's NAT was 5.401 seconds, including the gaps between commands and a 2.1-second three-packet ping; run 3's timed rows after the installs add up to 4.537 seconds. Installing the packages took over 200 seconds in total, but the installs ran amd64 under emulation on an arm64 host, which inflates them, and we did not time a native install.

How this was tested

Product
wireguard-tools (Debian package) on Debian 13 trixie
Version
1.0.20210914-3, installed 2026-10-16
System
Debian 13 in containers on a Colima VM, kernel 6.8.0-117-generic, amd64 emulated on an arm64 host
Checked
Runs
3
Not tested

Three runs, with a container standing in for a virtual private server (VPS), in three Debian containers: a server and a client on one container network, and a plain target on a second.

The in-kernel wireguard module carried the tunnel (wg-quick ran ip link add wg0 type wireguard); no userspace implementation was involved. Every step was timed with date +%s.%N inside the server container, and every command and its output was saved.

Run 1 failed on a missing forward setting, described below. Runs 2 and 3 are clean and are the ones in the table. Each step's time includes starting the command in its container through docker exec, so the per-step numbers are upper bounds. Keys and addresses are throwaway lab values.

Not tested:

  • a real VPS, a cloud firewall or a provider panel
  • IPv6, throughput, DNS through the tunnel, a default route through the tunnel
  • key rotation, boot persistence, unattended upgrades
  • any server OS other than Debian
  • the time a person spends typing and reading

No public server was rented, and a container network is not a cloud firewall.

Three terms before the table:

  • AllowedIPs: the addresses a peer may send from, and the addresses wg-quick routes to that peer.
  • wg-quick: the script that reads wg0.conf and brings the interface up.
  • PersistentKeepalive: makes a client send a packet at a set interval so a NAT keeps the path open.
StepWhat ranRun 2 (s)Run 3 (s)
Install, serverapt install wireguard-tools, iproute2, iptables, plus iputils-ping and procps for the test87.55889.075
Install, clientthe same, plus curl115.200115.641
Install, lab targetpython3 and a one-line web server34.29134.656
Keys, serverwg genkey, tee, wg pubkey0.1560.157
Keys, clientthe same0.1570.158
Forwarding checkread ip_forward (set at container start)0.1410.136
Server configwg0.conf with one peer and AllowedIPs of one address0.1820.183
NAT ruleiptables MASQUERADE plus two FORWARD rules0.2220.218
Server upwg-quick up wg00.4680.464
Client configwg0.conf with PersistentKeepalive of 250.1770.166
Client AllowedIPs fixsed to the tunnel subnet plus the target's single address0.1550.148
Client upwg-quick up wg00.4420.424
First handshakepoll wg show until a handshake time appears0.1900.173
Ping through the tunnelthree packets2.1572.148
Fetch through the NATcurl to the target, HTTP 2000.1580.162
Run 3: three installs of 115.641, 89.075 and 34.656 seconds against 5.401 seconds of elapsed time from key generation to the fetch, gaps between commands included. Run 2 measured 5.502 seconds for the same stretch.

In all three runs the handshake was already in place on the polling loop's first check, before the loop had sent a ping; we did not capture which packet started it.

The web log on the target showed the request coming from the server's own address, not the client's tunnel address: that is what the MASQUERADE rule does.

What happens when ip_forward is 0 on a WireGuard server?

In the first run the fetch timed out with curl's exit code 28 after 5.171 seconds, while the handshake and the three pings had worked. The cause was ip_forward at 0, which tells the kernel not to pass packets between interfaces, so the NAT rule had nothing to forward.

Setting it from inside the container failed: sysctl -w answered "permission denied on key". The fix was to start the server container with the sysctl already set, which is why the table shows only a check.

On a normal Debian host it is one command and one line in a config file, but this is the shape of the failure to expect: a tunnel that handshakes, pings and still carries nothing.

What do you have to keep up on your own WireGuard server?

A self-hosted WireGuard server leaves you the operating system, a key and an address per device, keepalive, reboot persistence and backups. The tunnel needs no daemon of its own once it is up, but the machine around it does.

JobWhat the sources sayDid our run test it?
Operating system and tools stay currentDebian's package page lists wireguard-tools 1.0.20210914-3 for trixie; the version you get is whatever your release shipsInstalled once; no upgrade path tested
Keys per deviceWireGuard's quick start generates a key pair with wg genkey and wg pubkey under a restrictive umaskYes, two pairs; no rotation
One address per deviceEach peer on the server gets its own AllowedIPs entry; our run used one peerOne peer only
Keepalive for clients behind NATThe quick start says a sensible interval is 25 seconds and that the feature is off by defaultSet to 25; not exercised over time
Forwarding and NAT survive a rebootNot covered by the WireGuard quick startNo, rules were typed by hand
The tunnel returns after a rebootNot covered by the WireGuard quick startNo
A copy of the configurationNot covered by either sourceNo

Three of the seven rows are plain gaps in what we tested, and a fourth, updates, was installed once but never upgraded. They are also the ones that bite at 3 a.m.

The NAT rule in the table was typed into a shell, which means it is gone when the host restarts unless you save it somewhere. We did not test that, and we will not pretend a lab minute proves a year.

WireGuard's install page lists Debian among the systems with a module and tools, and also lists apps for other platforms, so the client side is rarely the hard part. The server's long life is.

Does a self-hosted VPN give you more privacy than a VPN service?

It moves the trust to a different place rather than removing it. A server you rent has one exit address, one renter and one billing identity, and the renter is you.

That cuts both ways. Nobody else's traffic leaves from your address, which is the point for some people. Everything that leaves it is attributable to a single customer account at the host.

What that host records and allows is written on its own terms page, which you should read before you rent. We rented nothing in this run, so we make no claim about any host.

What does ForestVPN hold about you?

On ForestVPN's side the account is a 32-character number, optional on Free, with no email or password (account number), and the security page answers "Does ForestVPN know who I am?" with "No name, no email and no password." The payment step still leaves a purchase record with a store or processor; VPN without email lays out who holds what. Read the policy of whoever you pay.

What does a VPN service do for you that your own server does not?

It does the jobs around the tunnel: apps, exits you do not have to patch, and a status in words. A server hands you the tunnel and leaves the rest as a task list.

JobYour own WireGuard serverForestVPN
AppsWireGuard lists apps for several platforms; you hand each one a configApps for iPhone, iPad, Mac, Apple TV, Android phone and tablet, Android TV, Windows and Linux, from the downloads page
Is it working?wg show prints a last-handshake time; a handshake and a ping prove the tunnel, not the path past the serverOne of eight verdicts, Working (connection verdict), appears only when data flows both ways; the main screen has no Connected state (status)
Kill switchYou write firewall rules; our run did notIn every app, enforced by the operating system; none is absolute (kill switch)
Sign-inA key pair per device, kept by youAn optional 32-character account number; Free needs no sign-up (account number)
DevicesAs many peers as you add by handAn account holds up to ten devices (devices help)
ExitThe one machine you runExits run for you, and your own computer as an exit (home anywhere)
SpeedNot measured in this runNot compared in this post; our measured Linux numbers are in the Linux benchmark

Look at the status row first. In our first run the pings came back and wg show counted bytes received, so data did flow both ways through the tunnel; what failed was forwarding past the server. ForestVPN's status page has a verdict for that state, ExitUnreachable: "The path to the exit works; the exit can't reach the internet." (see status). We did not test ForestVPN against this failure.

Can you use your home computer as the exit instead of renting a server?

Yes, and it keeps the self-hosted idea, your own exit address, without renting a server. In ForestVPN you turn on Use as an exit on the home computer, then pick it under My exits in Locations from your phone or laptop (home anywhere).

It has honest limits, and the page says so:

  • The computer has to be on, or that exit is offline.
  • Your home connection's upload speed is the ceiling for everything you move through it.
  • Sharing works on every plan: up to 10 exits, each shared with up to 5 people, from a device that has been on your account for a week or more.
  • An iPhone can use an exit and reach your other devices, but cannot be one yet.

Compared with a self-hosted server at home, the difference is setup: the home-anywhere page says there is no port forwarding and no router setup, and you write no NAT rule.

If your home line is behind a router that does NAT, a hand-built server needs its UDP port reachable from outside first, and that is a project of its own. Similar router-side work, for people who want a tunnel on the router itself, is covered in OpenWrt WireGuard.

When should you build your own WireGuard server instead of paying for a VPN?

Build the server if the build is the point: you will learn what NAT (masquerade) does and own every setting. Before you trust it, reboot the host once and check that wg0, the forwarding setting and the NAT rule all come back; our run did not, and that test shows the gap.

Use a service, or your own computer as an exit inside one, if the point is the result. The plans are below.

Prices in USD
PlanPriceBilled
Free–2 GB per connection, 5 connections a day
Monthly$7.99per month
Yearly$49.99per year

Questions and answers

Is it better to use a VPS instead of a VPN?

They do different jobs. A VPS you rent and configure gives you one exit address and all the upkeep. A VPN service gives you apps, exits run for you and a status you can read. Pick the VPS when you want to own every setting, and the service when you want the setting-up and keeping-up done.

Is it possible to self host a VPN?

Yes. WireGuard's tools install from Debian's package repositories, and in our run a server and a client reached a handshake within seconds of the second configuration being loaded. Self-hosting at home also needs the server's UDP port reachable from outside, which a router doing NAT blocks until you open it. Behind carrier-grade NAT, where your provider shares one public address among many homes, opening the home router's port is not enough.

How long does it take to set up a WireGuard server?

In run 3 the elapsed time from key generation to a fetch through the tunnel was 5.401 seconds, gaps between commands and a three-packet ping included; run 3's timed steps after the installs add up to 4.537 seconds. In run 3 the three package installs took 34.656 to 115.641 seconds each, amd64 under emulation on an arm64 host. That excludes the time you spend reading, choosing addresses and renting a host, which we did not measure, and a native install was not timed.

What do you have to keep up on your own WireGuard server?

The operating system and the WireGuard tools, the firewall and NAT rules after a reboot, one address and one key pair per device, a backup of the configuration and the keepalive setting for any client behind NAT. Our run did not exercise any of these over time.

Does a self-hosted VPN give you more privacy than a VPN service?

It moves the trust rather than removing it. The server has one exit address and one renter, you, under the billing identity you gave the host. The host's own terms say what it records. ForestVPN's security page answers 'Does ForestVPN know who I am?' with 'No name, no email and no password.'

Can I use my own home computer as the exit instead of renting a server?

Yes, with ForestVPN's My exits: turn on Use as an exit on the home computer and pick it in Locations from your other devices. The computer has to be on, and your home upload speed is the ceiling. It works on every plan.

Sources

  1. WireGuard Quick Start (read October 16, 2026)
  2. WireGuard installation (read October 16, 2026)
  3. WireGuard protocol and cryptography (read October 16, 2026)
  4. Debian package wireguard-tools in trixie (read October 16, 2026)

How this was made

Drafted with AI assistance from our own timed lab run of wireguard-tools on Debian, wireguard.com and Debian's package page, and ForestVPN's product pages read on the drafting date, checked by automated gates and an editor; no public server was rented.

All posts

Back to top

Ask us anything