LFCE 88 ๐ง WireGuard โ Concepts
WireGuard is a Layer 3 VPN tunnel built into the Linux kernel. It encapsulates IP packets inside UDP and sends them between peers that have exchanged public keys. The previous chapters covered traffic control and QoS, which manage the packets on a link; this chapter covers the tunnel that carries the packets across an untrusted network. The LFCE exam objectives include configuring network traffic tunneling , and WireGuard is the modern implementation that has largely replaced IPsec and OpenVPN for point-to-point and hub-and-spoke tunnels.
The design philosophy is deliberately minimal. WireGuard does not negotiate algorithms, does not use certificates, and does not implement a key distribution protocol. Each peer has a static keypair, and the peers exchange their public keys out of bandโby copying a file, by scanning a QR code, or by a configuration management system. The tunnel is established by a Noise IK handshake that derives ephemeral session keys, and the data is encrypted with ChaCha20-Poly1305 . The result is a protocol that is small enough to be audited and fast enough to run at line rate.
Key point: WireGuard is a Layer 3 tunnel that carries IP packets, not Ethernet frames. It uses UDP and a single port, which makes it firewall-friendly and NAT-traversable. The peers identify each other by public keys, and the allowed IPs configured for each peer determine which packets the peer is permitted to send through the tunnel. The handshake is a Noise IK pattern that provides mutual authentication and forward secrecy, and it completes in one round trip .
Why WireGuard requires a different model
The simplicity problem.
IPsec and OpenVPN are configurable. IPsec has dozens of parametersโIKE versions, encryption algorithms, hash algorithms, DH groups, lifetimes, and proposal lists. OpenVPN has its own set of options for TLS, ciphers, and topology. The configurability is the source of the complexity, and the complexity is the source of the misconfigurations. WireGuard has no algorithm negotiation. The cryptographic primitives are fixed: Curve25519 for the key exchange, ChaCha20-Poly1305 for the encryption, BLAKE2s for the hashing, and SipHash24 for the hashtable keys . The peer either supports the protocol or it does not, and there is no configuration to get wrong.
The stateless-handshake problem.
WireGuard does not maintain a connection in the traditional sense. The handshake establishes session keys, and the session keys are used to encrypt the data packets. The handshake is re-initiated when the session keys expire (every two minutes by default) or when a peer needs to send data and does not have a valid session. The data packets that arrive while the handshake is in progress are queued, and the handshake completes in one round trip . The statelessness is what makes WireGuard resilient to NAT and roaming: the peer’s endpoint is updated from the source address of the last authenticated packet, so the tunnel follows the peer when its IP address changes.
The allowed-IPs problem.
WireGuard does not have a routing protocol or a dynamic topology discovery. Each peer has an AllowedIPs list that serves two purposes. On the sending side, it is the routing table: a packet whose destination matches an allowed IP is sent to that peer. On the receiving side, it is the access control list: a packet from that peer is accepted only if its source address matches one of the allowed IPs . The AllowedIPs is the mechanism that replaces the routing and firewall rules that IPsec and OpenVPN require.
a. The cryptographic foundation
WireGuard uses the Noise protocol framework, specifically the Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s construction . The IK pattern means that the initiator knows the responder’s static public key in advance, and the responder learns the initiator’s static public key during the handshake. The psk2 suffix means that a pre-shared key can be mixed into the handshake for post-quantum resistance, though the pre-shared key is optional.
The handshake has two messages. The initiator sends a message containing its ephemeral public key, its encrypted static public key, and an encrypted timestamp. The responder sends a message containing its ephemeral public key and an empty encrypted payload. The two messages derive four Diffie-Hellman shared secrets: ECDH(ephemeral_initiator, static_responder), ECDH(static_initiator, static_responder), ECDH(ephemeral_initiator, ephemeral_responder), and ECDH(static_initiator, ephemeral_responder) . The combination of the four secrets is the “triple DH” that provides authentication and forward secrecy. The static-static secret authenticates the initiator to the responder in the first message, which is what allows the handshake to complete in one round trip.
The data packets are encrypted with ChaCha20-Poly1305 and a 64-bit counter. The counter is incremented for every packet, and the nonce is the 32 bits of zeros followed by the 64-bit little-endian counter . The counter is reset with every handshake, and the handshake is re-initiated before the counter can overflow. The transport keys are derived from the chaining key that the handshake produces, and there is a separate key for each direction.
b. The interface and the peer configuration
WireGuard is configured through a network interface, typically wg0. The interface is created with ip link add wg0 type wireguard, and it is configured with the wg tool. The interface has a private key and a listening port, and it has a list of peers, each with a public key, an endpoint, and an AllowedIPs list.
# Create the WireGuard interface
sudo ip link add wg0 type wireguard
# Set the private key
sudo wg set wg0 private-key /etc/wireguard/private.key
# Add a peer
sudo wg set wg0 peer <peer-public-key> \
endpoint 203.0.113.5:51820 \
allowed-ips 10.0.0.2/32
# Assign an address and bring the interface up
sudo ip addr add 10.0.0.1/24 dev wg0
sudo ip link set wg0 up
The wg set command configures the interface and the peers. The private-key is the interface’s own key, and the peer command adds a peer with its public key, its endpoint, and its allowed IPs . The endpoint is the remote address and port, which the peer updates automatically when it receives a packet from a different address. The allowed-ips is the list of addresses that the peer is permitted to use, and it is the routing and access-control mechanism.
The wg show command displays the interface’s configuration and the peers’ status.
sudo wg show
# Output shows the interface, the public key, the listening port,
# and each peer with its endpoint, allowed IPs, and latest handshake
The output includes the latest handshake timestamp, which confirms that the handshake has completed, and the transfer counters, which show the bytes sent and received . The persistent-keepalive option sends a keepalive packet every 25 seconds, which is useful when the peer is behind a NAT that expires the UDP mapping.
c. The routing and the AllowedIPs semantics
The AllowedIPs is the most important configuration option, and its semantics are often misunderstood. It is not a firewall rule in the traditional sense; it is the mechanism that maps destination addresses to peers on the sending side and validates source addresses on the receiving side.
When the interface sends a packet, it looks up the destination address in the AllowedIPs of every peer. If the destination matches a peer’s allowed IPs, the packet is encrypted with that peer’s key and sent to the peer’s endpoint. If the destination does not match any peer, the packet is dropped. This is why the AllowedIPs is described as the routing table of the interface .
When the interface receives a packet, it decrypts it with the peer’s key and checks whether the source address matches the peer’s allowed IPs. If it does, the packet is accepted; if it does not, the packet is dropped. This is the access control that prevents a peer from spoofing another peer’s address.
The 0.0.0.0/0 in the AllowedIPs is the default route. A peer with allowed-ips 0.0.0.0/0 receives all the traffic that is not matched by a more specific peer, which is the configuration for a full-tunnel VPN. The peer with the specific allowed IPs receives only the traffic for those addresses, which is the configuration for a split-tunnel VPN.
Complete Example Session
# ============================================
# PART 1: GENERATE THE KEYS
# ============================================
# Generate the private and public keys for the server
wg genkey | tee server-private.key | wg pubkey > server-public.key
chmod 600 server-private.key
# Generate the keys for the client
wg genkey | tee client-private.key | wg pubkey > client-public.key
chmod 600 client-private.key
# ============================================
# PART 2: CREATE THE SERVER INTERFACE
# ============================================
sudo ip link add wg0 type wireguard
sudo wg set wg0 private-key ./server-private.key listen-port 51820
# ============================================
# PART 3: ADD THE CLIENT PEER
# ============================================
sudo wg set wg0 peer $(cat client-public.key) \
allowed-ips 10.0.0.2/32
# ============================================
# PART 4: ASSIGN THE SERVER ADDRESS
# ============================================
sudo ip addr add 10.0.0.1/24 dev wg0
sudo ip link set wg0 up
# ============================================
# PART 5: CREATE THE CLIENT INTERFACE
# ============================================
# On the client:
sudo ip link add wg0 type wireguard
sudo wg set wg0 private-key ./client-private.key
# ============================================
# PART 6: ADD THE SERVER PEER ON THE CLIENT
# ============================================
sudo wg set wg0 peer $(cat server-public.key) \
endpoint 203.0.113.5:51820 \
allowed-ips 10.0.0.0/24 \
persistent-keepalive 25
# ============================================
# PART 7: ASSIGN THE CLIENT ADDRESS
# ============================================
sudo ip addr add 10.0.0.2/24 dev wg0
sudo ip link set wg0 up
# ============================================
# PART 8: VERIFY THE HANDSHAKE
# ============================================
sudo wg show
# Output shows the peer with the latest handshake timestamp
# ============================================
# PART 9: TEST THE TUNNEL
# ============================================
ping -c 2 10.0.0.1
# The tunnel is up and the packets are encrypted
# ============================================
# PART 10: CLEAN UP
# ============================================
sudo ip link del wg0
The ten parts demonstrate the complete WireGuard setup: key generation, server interface, client peer, server address, client interface, server peer, client address, handshake verification, tunnel test, and cleanup. The critical configuration is the allowed-ips on each side: the server allows the client’s tunnel address, and the client allows the server’s tunnel subnet.
Quick Reference
WireGuard Concepts
| Concept | Meaning |
|---|---|
| Interface | wg0, a Layer 3 tunnel |
| Peer | A remote endpoint identified by a public key |
| Private key | The interface’s own key |
| Public key | The peer’s key |
| AllowedIPs | Routing and access control |
| Endpoint | The peer’s remote address and port |
| Handshake | Noise IK, one round trip |
| Transport | UDP, ChaCha20-Poly1305 |
Cryptographic Primitives
| Function | Algorithm |
|---|---|
| Key exchange | Curve25519 |
| Encryption | ChaCha20-Poly1305 |
| Hashing | BLAKE2s |
| Hashtable keys | SipHash24 |
wg Commands
| Command | Purpose |
|---|---|
wg genkey | Generate a private key |
wg pubkey | Derive the public key |
wg set | Configure the interface or peer |
wg show | Display the configuration and status |
wg showconf | Show the configuration in wg format |
Configuration Files
| File | Purpose |
|---|---|
/etc/wireguard/wg0.conf | Persistent configuration |
wg-quick up wg0 | Bring up the interface from the file |
wg-quick down wg0 | Bring down the interface |
Best Practices
โ Do This:
# Generate keys with wg genkey
wg genkey | tee private.key | wg pubkey > public.key # โ
# Set the private key with wg set
wg set wg0 private-key /etc/wireguard/private.key # โ
# Use allowed-ips for routing and access control
wg set wg0 peer <key> allowed-ips 10.0.0.2/32 # โ
# Use persistent-keepalive for NAT traversal
wg set wg0 peer <key> persistent-keepalive 25 # โ
# Verify the handshake with wg show
wg show # โ
# Use wg-quick for persistent configuration
wg-quick up wg0 # โ
โ Don’t Do This:
# Use the same key for multiple peers
# Each peer must have a unique keypair # โ
# Set allowed-ips to 0.0.0.0/0 without a reason
# The peer receives all traffic; the routing must be correct # โ
# Forget the allowed-ips on the receiving side
# The peer's packets are dropped # โ
# Use WireGuard for Layer 2 bridging
# WireGuard is a Layer 3 tunnel # โ
# Expose the private key
# The private key is the identity; never share it # โ
Common Pitfalls
| Pitfall | Why It Happens | Fix |
|---|---|---|
| Handshake does not complete | Wrong public key or endpoint | Verify the keys and the endpoint |
| Packets dropped | Source address not in allowed-ips | Add the source to the peer’s allowed IPs |
| Tunnel works one way | Asymmetric allowed-ips | Configure both sides |
| NAT expires the mapping | No keepalive | Add persistent-keepalive 25 |
| Interface does not exist | Module not loaded or wrong name | ip link add wg0 type wireguard |
Real-World Examples
1. Generate a keypair
wg genkey | tee private.key | wg pubkey > public.key
2. Create the interface
ip link add wg0 type wireguard
3. Set the private key
wg set wg0 private-key /etc/wireguard/private.key
4. Add a peer
wg set wg0 peer <public-key> allowed-ips 10.0.0.2/32
5. Set the endpoint
wg set wg0 peer <public-key> endpoint 203.0.113.5:51820
6. Add keepalive
wg set wg0 peer <public-key> persistent-keepalive 25
7. Show the status
wg show
8. Bring up with wg-quick
wg-quick up wg0
9. Bring down with wg-quick
wg-quick down wg0
10. Show the configuration
wg showconf wg0
Visual
The WireGuard Tunnel
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ WIREGUARD ENCAPSULATES IP PACKETS IN UDP โ
โ โ
โ Peer A (10.0.0.1) โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ IP packet: src 10.0.0.1, dst 10.0.0.2 โ โ
โ โ โ encrypted with peer B's key โ โ
โ โ โ encapsulated in UDP (port 51820) โ โ
โ โ โ sent to peer B's endpoint โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ โ
โ โ Internet (UDP) โ
โ โผ โ
โ Peer B (10.0.0.2) โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ UDP packet received on port 51820 โ โ
โ โ โ decrypted with peer A's key โ โ
โ โ โ source address checked against allowed-ips โ โ
โ โ โ IP packet delivered to the host โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
The Handshake
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ THE HANDSHAKE COMPLETES IN ONE ROUND TRIP โ
โ โ
โ Initiator Responder โ
โ โโโโโโโโโโโ โโโโโโโโโโโ โ
โ โ โโโ handshake initiation โโโถโ โ โ
โ โ โ (ephemeral, static, โ โ โ
โ โ โ timestamp) โ โ โ
โ โ โ โ โ โ
โ โ โโโโ handshake response โโโโโ โ โ
โ โ โ (ephemeral) โ โ โ
โ โโโโโโโโโโโ โโโโโโโโโโโ โ
โ โ
โ Both sides derive the session keys. โ
โ The data packets are encrypted with the session keys. โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
AllowedIPs Semantics
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ AllowedIPs IS ROUTING AND ACCESS CONTROL โ
โ โ
โ Sending: โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Destination 10.0.0.2 โ โ
โ โ โ matches peer B's allowed-ips 10.0.0.2/32 โ โ
โ โ โ encrypted and sent to peer B โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โ Receiving: โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Packet from peer B, source 10.0.0.2 โ โ
โ โ โ matches peer B's allowed-ips 10.0.0.2/32 โ โ
โ โ โ accepted โ โ
โ โ โ โ
โ โ Packet from peer B, source 10.0.0.3 โ โ
โ โ โ does not match peer B's allowed-ips โ โ
โ โ โ dropped โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Summary
| Item | Value |
|---|---|
| Layer | Layer 3 (IP packets) |
| Transport | UDP (default port 51820) |
| Key exchange | Noise IK, Curve25519 |
| Encryption | ChaCha20-Poly1305 |
| Hashing | BLAKE2s |
| Handshake | One round trip |
| Peer identity | Public key |
| Routing and access | AllowedIPs |
| Configuration tool | wg |
| Persistent tool | wg-quick |
Key takeaways:
- WireGuard is a Layer 3 tunnel. It carries IP packets inside UDP, not Ethernet frames. The interface is
wg0, and it is configured with an address and routes like any other interface . - The cryptographic primitives are fixed. Curve25519 for the key exchange, ChaCha20-Poly1305 for the encryption, BLAKE2s for the hashing, and SipHash24 for the hashtable keys. There is no algorithm negotiation and no configuration to get wrong .
- The handshake is a Noise IK pattern. The initiator knows the responder’s static public key in advance, and the responder learns the initiator’s static public key during the handshake. The four Diffie-Hellman secrets provide authentication and forward secrecy, and the handshake completes in one round trip .
- The
AllowedIPsis routing and access control. On the sending side, it maps the destination to the peer. On the receiving side, it validates the source. A packet that does not match the peer’s allowed IPs is dropped . - The
persistent-keepaliveoption keeps the NAT mapping alive. A peer behind a NAT needs the keepalive to prevent the UDP mapping from expiring, or the tunnel stops working after the NAT timeout . - The
wg showcommand verifies the handshake. The output includes the latest handshake timestamp and the transfer counters, which confirm that the tunnel is up and the packets are flowing .
Remember: WireGuard is a simple, fast, and auditable VPN tunnel. The interface is created with ip link, the keys are generated with wg genkey, and the peers are configured with wg set. The AllowedIPs is the routing and access-control mechanism, and the persistent-keepalive keeps the NAT mapping alive. The handshake is a Noise IK pattern that completes in one round trip, and the data is encrypted with ChaCha20-Poly1305. The result is a tunnel that is easy to configure, fast enough for line-rate traffic, and small enough to audit.
Stop using slow, ad-bloated tool sites! ๐คฎ
๐ Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
โ
Finance (Mortgage, Interest, Inflation)
โ
Tech (Base64, JSON, Dev Suite, IP)
โ
Health (BMI, BMR, TDEE)
โ
Productivity (Timer, Workspace, QR)
โก๏ธ Fast & Private
๐ No data leaves your device
๐ 100% Free
๐ Use it now: https://tools.kandz.me
๐ Bookmark itโyouโll need it later!