
wireguard vpn, key pair to handshake in six steps
wg genkey | wg pubkeywhy wireguard is worth your time
most vpn writeups make this look scarier than it is. wireguard was built specifically to not be that. it's a few thousand lines of code instead of the sprawling mess that is openvpn or ipsec, it uses modern crypto with no configurable cipher list to mess up, and you can stand up a working tunnel in about six commands. that small footprint isn't just convenient, it's a security feature. fewer lines means fewer places for bugs to hide, and fewer knobs means fewer ways to misconfigure it into something insecure.
step 1: generate your key pair
wg genkey | wg pubkey
this is the foundation of the whole system. wg genkey spits out a private key, and piping it into wg pubkey derives the matching public key. wireguard uses curve25519 for this, which is fast and well vetted. your private key never gets shared, ever. treat it like a password. the public key is what you hand to peers so they can identify and encrypt traffic to you. in practice you'll save these to files:
wg genkey | tee privatekey | wg pubkey > publickey
lock that privatekey file down with chmod 600. if someone can read it, they can impersonate your side of the tunnel.
step 2 and 3: create the interface and configure it
ip link add wg0 type wireguard
this creates a virtual network interface named wg0. it doesn't do anything on its own yet, it's just the empty container. next you give it an identity: an internal vpn address, your private key, and a listen port (51820 is the default, but you can change it, which is a nice bit of obscurity against casual port scanning).
ip address add 10.0.0.1/24 dev wg0
wg set wg0 private-key ./privatekey listen-port 51820
at this point wg0 knows who it is. it just doesn't know who it's allowed to talk to.
step 4: add the peer
this is the step people skip when they're rushing and it's the one that actually enforces your security boundary. you add the peer's public key and define allowed-ips, which controls two things at once: what source ips are accepted from that peer, and what destination traffic gets routed to them.
wg set wg0 peer <peer-public-key> allowed-ips 10.0.0.2/32 endpoint 203.0.113.5:51820
tighten allowed-ips as much as your setup allows. wireguard uses this like a built-in access control list, not just a routing hint. a peer entry with 0.0.0.0/0 means "route everything," which is fine for a full tunnel vpn but way too broad if you meant to only allow one host to reach a specific service.
step 5 and 6: bring it up and verify
ip link set wg0 up
wg show
wg show is your proof the whole thing actually works, not just that you typed the commands correctly. look for a "latest handshake" timestamp that's recent. no handshake usually means one of three things: your firewall is blocking the udp port, the endpoint address is wrong, or the keys don't match on both sides. wireguard fails silently by design, there's no noisy error, it just won't complete a handshake with garbage credentials. that's good for security, mildly annoying for debugging.
the takeaway
the appeal of wireguard for defenders is that there's very little attack surface to defend. no cipher negotiation to downgrade, no sprawling config file to misread, and it doesn't even respond to unauthenticated packets, which makes it naturally resistant to scanning and probing. if you're running it yourself, keep your private keys off shared systems, rotate them if a device is ever lost or compromised, run wg show periodically to catch handshakes from peers you don't recognize, and keep allowed-ips as narrow as your use case allows. a vpn is only as trustworthy as the key hygiene behind it, and wireguard just makes it easier to get that part right.