WireGuard from A to Z: how it works and how to set up your own config/server
WireGuard is the most modern and arguably the most convenient VPN protocol available today. It is fast, compact, easy to configure, and works equally well on a server, a laptop, a phone, and even a router. If you want to understand exactly how the tunnel is built, dissect a config field by field, and stand up your own server — this article walks you from the basics to a working installation.
One important point up front: WireGuard is an open standard, not someone’s proprietary technology. Your own WireGuard config will work in GANVAS VPN for free — the app can import it as a custom server. So everything below applies both to a do-it-yourself setup and to using a ready-made service.
What WireGuard is and why it’s fast
WireGuard emerged as an answer to the “heaviness” of older protocols like OpenVPN and IPsec. Its philosophy is to do one thing and do it well, and all of its key advantages flow from that.
- Tiny codebase. WireGuard’s core is about 4,000 lines of code, whereas OpenVPN with its dependencies runs into hundreds of thousands. Less code means a smaller attack surface, fewer security bugs, and an audit that’s actually feasible.
- Modern, opinionated crypto. WireGuard doesn’t let you pick algorithms (the way OpenVPN does). It hardcodes a fixed suite: ChaCha20 for encryption, Poly1305 for authentication, Curve25519 for key exchange, BLAKE2s for hashing. No cipher negotiation means an entire class of downgrade attacks simply doesn’t exist.
- Runs over UDP. All traffic flows over UDP as a single stream. That’s faster than TCP tunnels and avoids the “TCP-over-TCP meltdown” where two reliable transports fight each other.
- Stateless design. The server holds no heavy sessions. If a packet doesn’t match a valid key, it is silently dropped. From the outside an open WireGuard port barely responds to scanning, which makes the server “quiet.”
- Fast roaming. A connection is bound to cryptographic keys, not to an IP address. When a phone switches from Wi-Fi to mobile data, the tunnel doesn’t break — the next packet just arrives from a new address and the server updates the endpoint.
The price for this speed is a recognizable traffic “fingerprint.” We’ll come back to DPI and blocking below.
How it works: keys, peers, and the handshake
WireGuard is built around the concept of peers. At the protocol level there’s no rigid split between “client” and “server” — there are two nodes, each of which knows the other’s public key. What we call a “server” is simply a peer with a static public IP that the others connect to.
Key pairs
Each participant generates a Curve25519 key pair: a private key (kept secret on the device) and a public key (shared with the other side). The principle is the same as SSH keys:
- You put your own private key in your config.
- You put the other party’s public key in their peer section.
Authentication is mutual: both nodes must know each other’s public key, otherwise packets won’t pass.
The handshake
Before any data flows, the two sides perform a handshake using the Noise framework (Noise_IKpsk2). It derives ephemeral symmetric keys for the session. The handshake repeats roughly every 2 minutes to provide forward secrecy — even if a session key were ever leaked, past traffic couldn’t be decrypted. If wg show reports a recent latest handshake, the tunnel is alive; if there’s no handshake, the connection never came up.
Cryptokey routing
WireGuard’s central idea is cryptokey routing. Each peer is associated with an AllowedIPs list, and that table works in both directions:
- Inbound: a packet is accepted only if its source address falls within the
AllowedIPsof the peer whose key encrypted it. Otherwise it’s dropped. - Outbound: when WireGuard needs to send a packet to some IP, it finds the peer whose
AllowedIPscontains that address and sends through it.
So AllowedIPs is simultaneously an allowlist of addresses and a routing table.
Every config field explained
A WireGuard config is a plain ini file with two kinds of sections: one [Interface] (that’s “me”) and one or more [Peer] (that’s “them”). Here’s an annotated client config:
[Interface]
# Private key of THIS device (never share it)
PrivateKey = PRIVATE_KEY_HERE
# This device's internal address inside the VPN subnet
Address = 10.7.0.2/32
# DNS servers to use while the tunnel is up
DNS = 1.1.1.1, 1.0.0.1
# MTU adjustment (optional, see the MTU section)
MTU = 1420
[Peer]
# The SERVER's public key
PublicKey = SERVER_PUBLIC_KEY_HERE
# Optional pre-shared key for post-quantum resistance
PresharedKey = PRESHARED_KEY_HERE
# Where to connect: server's public IP/domain and UDP port
Endpoint = vpn.example.com:51820
# Which traffic to route into the tunnel (0.0.0.0/0 = everything)
AllowedIPs = 0.0.0.0/0, ::/0
# Send a tiny keepalive every 25s to keep NAT open
PersistentKeepalive = 25
Field by field:
- PrivateKey — this node’s private key. It’s the only truly secret element of the config.
- Address — the internal address inside the VPN network. A
/32mask means “just this address.” The server is usually10.7.0.1/24, clients are10.7.0.2/32,10.7.0.3/32, and so on. - DNS — which DNS servers to use while the tunnel is active. Critical for preventing DNS leaks (more below).
- MTU — packet size; sometimes needs tuning.
- PublicKey (in
[Peer]) — the other party’s public key. - PresharedKey — an optional shared secret that layers symmetric crypto on top of the asymmetric exchange. A cheap hedge against future quantum attacks.
- Endpoint — the address and port to send packets to. On a client it points at the server; on the server for a client it’s usually omitted (the client comes to the server, which remembers its address).
- AllowedIPs — on a client,
0.0.0.0/0, ::/0means “all traffic through the VPN.” Specify only10.7.0.0/24and just traffic to the VPN subnet goes through the tunnel (split-tunnel mode). - PersistentKeepalive — the interval for keepalive packets that hold a NAT session open. Needed for peers behind NAT.
Standing up your own WireGuard server
Below are conceptual steps that aren’t tied to a specific distro. The wg and wg-quick commands are the same everywhere; only the package install and the firewall manager differ.
Step 1. Install and generate keys
Install the package (wireguard or wireguard-tools) and generate keys on the server:
# Create the server key pair
wg genkey | tee server_private.key | wg pubkey > server_public.key
# And one for the first client too
wg genkey | tee client1_private.key | wg pubkey > client1_public.key
# (optional) a shared pre-shared key
wg genpsk > client1_preshared.key
wg genkey creates a private key, wg pubkey derives the matching public key. Guard private keys tightly (chmod 600).
Step 2. The server config wg0.conf
Create /etc/wireguard/wg0.conf:
[Interface]
Address = 10.7.0.1/24
ListenPort = 51820
PrivateKey = SERVER_PRIVATE_KEY_HERE
# Enable NAT when the interface comes up, remove it when it goes down
PostUp = iptables -t nat -A POSTROUTING -s 10.7.0.0/24 -o eth0 -j MASQUERADE
PostDown = iptables -t nat -D POSTROUTING -s 10.7.0.0/24 -o eth0 -j MASQUERADE
[Peer]
# First client
PublicKey = CLIENT1_PUBLIC_KEY_HERE
PresharedKey = CLIENT1_PRESHARED_KEY_HERE
AllowedIPs = 10.7.0.2/32
Note: on the server side, the peer’s AllowedIPs is the specific client address (10.7.0.2/32), not 0.0.0.0/0. The server has to know which peer owns which internal address. Replace eth0 with the name of your actual public network interface.
Step 3. Enable forwarding and NAT
For the server to forward client traffic out to the internet, enable IP forwarding:
# Temporarily
sysctl -w net.ipv4.ip_forward=1
# Permanently — add to /etc/sysctl.conf:
# net.ipv4.ip_forward = 1
The MASQUERADE rule from PostUp rewrites internal 10.7.0.x addresses to the server’s public IP — that’s the NAT that lets replies come back to the right client.
Step 4. Open the UDP port and start
WireGuard listens on UDP, port 51820 by default. Open it in your firewall/cloud provider, then bring the interface up:
# Allow the port (ufw example)
ufw allow 51820/udp
# Bring the tunnel up and enable it at boot
wg-quick up wg0
systemctl enable wg-quick@wg0
# Check status
wg show
wg-quick is a wrapper that reads the config, brings up the interface, sets routes, and runs PostUp. The wg show command lists peers, their last handshake, and traffic counters.
Step 5. Add new clients
To add another user: generate them a key pair, add a new [Peer] section to wg0.conf (with a unique AllowedIPs, e.g. 10.7.0.3/32), and apply the change without dropping existing connections:
wg syncconf wg0 <(wg-quick strip wg0)
Client configs and connecting
Each device gets its own config following the template from the “field by field” section. The key point: every client has its own private key and a unique Address.
- Desktop (Windows/macOS/Linux). Install the official WireGuard client, import the
.conf, and click “Connect.” On Windows it’s easiest to use a ready-made app — see our guide VPN for Windows. You can paste your config for free into the GANVAS custom-config client — one client for WireGuard, VLESS and Tor. - Phone. In the WireGuard mobile app, add a tunnel by scanning a QR code. Generate the QR from the config:
# Turn a config into a QR right in the terminal
qrencode -t ansiutf8 < client1.conf
- Router. Many firmwares (OpenWrt, recent versions of popular routers) support WireGuard natively — then your whole home network goes through the tunnel without configuring each device.
After connecting, check your real throughput with our speed test and confirm your public IP changed to the server’s address.
MTU tuning and problems behind NAT
Why MTU matters
WireGuard adds its own header to every packet, so the usable payload inside the tunnel is smaller than on a plain network. If MTU is set too high, packets start fragmenting or get dropped outright — which looks like “the internet seems up but pages won’t load” or “throughput is weirdly low.”
A typical value for WireGuard is 1420. If your link uses PPPoE or other tunnels, it’s safer to drop to 1280. You can find the sweet spot with a do-not-fragment ping:
# Linux: find the largest size that doesn't fragment
ping -M do -s 1372 8.8.8.8
# If you see "Frag needed", lower -s until it passes.
# Working MTU = that size + 28 (IP+ICMP headers)
Put the result in the MTU field of [Interface].
PersistentKeepalive behind NAT
When a client sits behind a home router (i.e. behind NAT), the router keeps a “hole” for the UDP session open only while packets flow through it. In silence that hole closes, the server can no longer reach the client, and inbound connections drop. PersistentKeepalive = 25 sends a tiny packet every 25 seconds, keeping the session alive. For a peer behind NAT this is practically mandatory; for a server with a static IP it isn’t needed.
Common issues
- No handshake (
latest handshakeempty). Usually a closed UDP port at the firewall/provider, a wrongEndpoint, or swapped keys. Verify the port is actually open and that the server’s public key in the client matches. - Asymmetric routing. The server doesn’t know the route back to the client — typically a wrong
AllowedIPsin the server’s peer section. Each client needs its own/32. - Handshake succeeds but there’s no internet. Almost always IP forwarding (
ip_forward) or a missingMASQUERADErule. Less often, an MTU that’s too high.
DNS and leak prevention
Even with the tunnel up, a leak is possible: if DNS queries go around the VPN, your ISP still sees which domains you open. So always set DNS in [Interface]:
[Interface]
# ... other fields ...
DNS = 1.1.1.1, 1.0.0.1
wg-quick will set these as the system resolvers while the tunnel is up, so DNS queries travel inside the encrypted channel. After connecting, always verify — we covered the mechanics in detail in what is a DNS leak. Check your browser separately too: WebRTC can “reveal” your real IP around the VPN — our WebRTC test catches that.
WireGuard vs OpenVPN vs VLESS+Reality
Each protocol has its niche.
- WireGuard — the best default: fast, lightweight, battery-friendly, instant reconnects. Ideal on networks without aggressive DPI.
- OpenVPN — the proven classic. It can run over TCP/443 and blends into HTTPS better, but it’s heavier and slower. Good for old devices and strict corporate firewalls.
- VLESS+Reality — not really a “VPN” but a transport for beating blocks. It mimics a genuine TLS handshake to a major website, so to DPI it looks like an ordinary visit to a popular site.
For a full comparison on speed and resilience, see WireGuard, OpenVPN or VLESS+Reality.
When WireGuard gets blocked
WireGuard’s main weakness is its recognizable traffic signature. Deep packet inspection (DPI) systems can identify the characteristic handshake format and simply cut the UDP stream, or block the port itself. Signs of blocking: the handshake never completes, or it breaks a few seconds after start.
What to do:
- Change the port (moving off the default
51820sometimes helps), though against signature-based DPI it’s a weak measure. - Wrap WireGuard in obfuscation (for example
udp2raw, or WireGuard over an obfuscating layer). - Switch to a protocol built for evasion — VLESS+Reality. Details and strategies are in how to bypass blocks.
Security: handling keys
WireGuard is cryptographically very solid, but the security of the whole system comes down to how you handle keys.
- The private key never leaves the device. Generate the pair right where it will be used; transmit only the public key over the network.
- File permissions. Keep configs containing private keys at mode
600owned by root (chmod 600 /etc/wireguard/wg0.conf). - One key, one device. Don’t reuse the same private key across devices: if one is compromised you’d have to revoke them all.
- Key rotation. If a device is lost or you suspect a leak, generate a new pair, update the
[Peer]section on the server, and applywg syncconf. The old public key stops being accepted instantly. - PresharedKey as a hedge. Adding a pre-shared key protects against future attacks on asymmetric crypto (including quantum ones) — a cheap extra layer.
How GANVAS uses WireGuard
GANVAS VPN uses WireGuard as one of its primary server protocols — precisely for the speed, efficiency, and instant roaming. When the network is “clean,” the app goes through WireGuard by default; when aggressive DPI kicks in, it automatically offers VLESS+Reality or a Tor mode.
And the key takeaway for anyone who read this far: your own WireGuard config works in the app for free. Generate a key pair, stand up a server, import the .conf as a custom server — and use your own infrastructure through a convenient client with leak protection. No subscription is required for your own configs — details on the free VPN page, and a feature/plan breakdown on the compare page.
Want ready-made servers without fiddling with configs? Just try GANVAS VPN. Want full control? Stand up your own WireGuard with this guide and connect it to the very same app. Both paths lead to a fast, private connection.