Server — WireGuard

Posted on 6 2026

The case for running your own VPN rather than buying one from a provider is simple: you know exactly what it does, because you built it. There is no privacy policy to read, no logging practices to trust, and no subscription to forget about. The traffic goes from your device to February and from there to wherever it was going. That is the entire chain.

WireGuard is the right tool for this. It is fast, it is built into the Linux kernel, its configuration is minimal, and the client apps are available on every platform that matters. Setup on the server side takes about 20 minutes. Setup on the client side takes as long as it takes to scan a QR code.

This article covers setting up February as a WireGuard server and generating client profiles for each device or user that needs access.

How WireGuard thinks about peers

WireGuard does not have a strict client/server distinction at the protocol level. Every device is a peer. What makes February the server is that it has a static public IP, it listens on a known port, and every other peer has its address in their configuration. The clients do not know about each other; they only know about February.

Each peer is identified by a public key. February holds the public key of every device it talks to. Each device holds February’s public key. Private keys never leave the device they were generated on.

All peers connect to the same wg0 interface on February. You do not create wg1, wg2, and so on for each client. Each client gets a unique internal VPN IP address and is identified by their key.

Installation

On February:

sudo apt install wireguard wireguard-tools

WireGuard ships in the standard Ubuntu repository. No PPA needed.

Server setup

Generate February’s keypair

cd /etc/wireguard
umask 077
wg genkey | tee server_private.key | wg pubkey > server_public.key

umask 077 ensures the key files are created with permissions that only root can read. Do this before generating anything; do not fix permissions after the fact.

Enable IP forwarding

WireGuard needs the kernel to forward packets between the VPN interface and the outside world. Add this to /etc/sysctl.conf:

net.ipv4.ip_forward = 1

Apply it immediately:

sudo sysctl -p

Create the server config

Create /etc/wireguard/wg0.conf. The private key goes in here; get it with cat /etc/wireguard/server_private.key:

[Interface]
Address = 10.10.0.1/24
ListenPort = 51820
PrivateKey = <February's private key>
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

A few notes. 10.10.0.1/24 is February’s address on the VPN subnet. Clients will be assigned addresses in the 10.10.0.0/24 range. ListenPort 51820 is the conventional WireGuard port but can be anything. eth0 in the PostUp/PostDown rules should match February’s actual network interface name, which you can find with ip link show. The iptables rules handle routing traffic from VPN clients out to the internet.

Open the port in UFW

sudo ufw allow 51820/udp

WireGuard is UDP only.

Start the interface

sudo systemctl enable wg-quick@wg0
sudo systemctl start wg-quick@wg0

Confirm it is up:

sudo wg show

You should see the wg0 interface with February’s public key and listening port. No peers yet.

Adding a client

Each device that needs access gets its own keypair and its own entry in February’s config. The process is the same regardless of whether the client is a phone, a laptop, or another server.

Generate the client keypair

Do this on February. You are generating keys on behalf of the client and will distribute them securely. If the client is a Linux machine, you can generate there instead and copy only the public key back to February.

cd /etc/wireguard/clients
wg genkey | tee alice_private.key | wg pubkey > alice_public.key

Keep a clients/ directory under /etc/wireguard/ to keep things tidy. Use a name that identifies the person or device clearly. You will accumulate these over time.

Add the client to wg0.conf

Append a [Peer] block to /etc/wireguard/wg0.conf for each client:

[Peer]
# Alice — laptop
PublicKey = <alice's public key>
AllowedIPs = 10.10.0.2/32

AllowedIPs with a /32 means only traffic from exactly that IP will be accepted from this peer. Each client gets a unique address in the subnet: 10.10.0.2 for Alice, 10.10.0.3 for Bob, and so on.

Reload the WireGuard interface to pick up the new peer without dropping existing connections:

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

Or simply restart the interface if no active sessions need preserving:

sudo systemctl restart wg-quick@wg0

Create the client profile

The client needs a config file that tells it how to reach February and what traffic to send through the tunnel. Create /etc/wireguard/clients/alice.conf:

[Interface]
PrivateKey = <alice's private key>
Address = 10.10.0.2/32
DNS = 1.1.1.1

[Peer]
PublicKey = <February's public key>
Endpoint = <February's public IP>:51820
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25

AllowedIPs = 0.0.0.0/0, ::/0 routes all traffic through the tunnel. If you only want homelab access and not full tunnel routing, use the VPN subnet and your home network range instead, for example 10.10.0.0/24, 192.168.1.0/24.

PersistentKeepalive = 25 keeps the tunnel alive through NAT, which matters for mobile devices and any client that is not listening on a known port.

Distributing the profile

For phones and tablets, the easiest method is a QR code. Install qrencode on February:

sudo apt install qrencode

Generate a QR code from the client config:

qrencode -t ansiutf8 < /etc/wireguard/clients/alice.conf

The QR code prints directly in the terminal. Open the WireGuard app on the phone, tap the plus button, choose to scan a QR code, and point the camera at the screen. The profile imports in one step.

For laptops and servers, copy the .conf file directly and place it in /etc/wireguard/ on the client. Start it with:

sudo wg-quick up wg0

Or enable it as a service to connect on boot:

sudo systemctl enable --now wg-quick@wg0

Verifying the connection

On February, sudo wg show will list all peers and show the latest handshake time for each. A handshake in the last two minutes means the client is actively connected. A handshake that is stale or absent means the client has not connected or has dropped.

From the client, confirm traffic is routing correctly:

curl ifconfig.me

If the IP returned matches February’s public IP, all traffic is flowing through the tunnel as expected.

Managing peers over time

Add a comment to each [Peer] block in wg0.conf identifying who it belongs to and what device it is. When you come back to this file in six months, you will not remember which key belongs to which phone.

When a device is lost, stolen, or decommissioned, remove its [Peer] block from wg0.conf and restart the interface. That key will no longer be accepted. You do not need to rotate February’s keys or touch any other client’s config.

When someone needs access, generate a new keypair, add a peer block, create a config, hand them a QR code. The process is the same every time.