WireGuard is often described as a VPN, but it’s just as useful for building a private, encrypted network between machines without routing all of their internet traffic. This article walks through a simple hub-and-spoke design where peers communicate securely over the public Internet while continuing to use their own local internet connections.
Network Design
We’ll use the following private network:
- VPN subnet:
10.20.0.0/21 - Usable addresses:
10.20.0.1–10.20.7.254 - Total usable hosts: 2046
In this design:
- One server has a public IP address and acts as the WireGuard hub.
- Clients can be behind NAT and have dynamic public IPs.
- Internet traffic stays on each client’s normal connection.
- Only traffic destined for the VPN subnet is sent through WireGuard.
Internet
Public WireGuard Hub
203.0.113.10
10.20.0.1
|
---------------------
| | |
10.20.0.2 10.20.0.3 10.20.0.4
Laptop Server Phone
Why Use a /21?
A /21 subnet provides:
- Network:
10.20.0.0 - Broadcast:
10.20.7.255 - Usable hosts: 2046
This leaves plenty of room to add peers without redesigning the network.
A suggested addressing scheme:
| Device | VPN Address |
|---|---|
| Hub | 10.20.0.1 |
| Peer 1 | 10.20.0.2 |
| Peer 2 | 10.20.0.3 |
| Peer 3 | 10.20.0.4 |
Generating Keys
Each WireGuard peer requires its own unique key pair.
Generate one with:
umask 077 wg genkey | tee privatekey | wg pubkey > publickey
The generated files are:
privatekey— keep secretpublickey— share with peers
A common place to store them is:
/etc/wireguard/
Ensure the private key is readable only by root.
Server Configuration
Example /etc/wireguard/wg0.conf:
[Interface] PrivateKey = SERVER_PRIVATE_KEY Address = 10.20.0.1/21 ListenPort = 51820 [Peer] PublicKey = CLIENT_A_PUBLIC_KEY AllowedIPs = 10.20.0.2/32 [Peer] PublicKey = CLIENT_B_PUBLIC_KEY AllowedIPs = 10.20.0.3/32
Notice that each peer is assigned a single /32 address in AllowedIPs. This tells WireGuard which VPN IP belongs to which peer.
Client Configuration
Example client configuration:
[Interface] PrivateKey = CLIENT_PRIVATE_KEY Address = 10.20.0.2/21 [Peer] PublicKey = SERVER_PUBLIC_KEY Endpoint = vpn.example.com:51820 AllowedIPs = 10.20.0.0/21 PersistentKeepalive = 25
The important setting is:
AllowedIPs = 10.20.0.0/21
This means only traffic destined for the VPN subnet is routed through the tunnel.
Traffic to websites and the public Internet continues to use the client’s normal network connection.
How WireGuard Works Over the Internet
WireGuard uses encrypted UDP packets.
For example:
Outer Packet ------------- Source: 198.51.100.23 Destination: 203.0.113.10 Protocol: UDP Port: 51820 Encrypted Payload ----------------- Source: 10.20.0.2 Destination: 10.20.0.3
The Internet only sees encrypted UDP traffic between public IP addresses.
The private 10.20.x.x addresses exist only inside the encrypted tunnel.
Clients Behind NAT
Most WireGuard clients don’t have public IP addresses.
Typical examples include:
- Home computers
- Laptops
- Mobile phones
- Cloud VMs behind provider NAT
This is completely normal.
Clients initiate an outbound UDP connection to the hub, which records the client’s current public IP and UDP port.
Because residential ISPs and mobile networks often assign dynamic public IPs, clients should include:
PersistentKeepalive = 25
This sends a small packet every 25 seconds, keeping the NAT mapping alive and allowing the server to learn a client’s new public endpoint if it changes.
Internet Routing
A common misconception is that a VPN must carry all internet traffic.
It doesn’t.
This design intentionally uses split tunneling.
Destination: 10.20.x.x
↓
WireGuard
Destination: Everything Else
↓
Normal Internet Connection
This means:
- Browsing continues through the user’s ISP.
- Only private network traffic uses WireGuard.
No NAT or internet gateway configuration is required on the WireGuard hub.
Understanding Peers and Servers
WireGuard itself has no concept of “server” and “client.”
Every participant is a peer.
The machine with the public IP is commonly called the “server” simply because it listens for incoming connections and is always online.
From WireGuard’s perspective, however, every node is just another peer with a key pair and a routing configuration.
Protecting Local Services
One common concern is:
“If I connect my machine to WireGuard, can other peers access services running on my computer?”
The answer depends on how those services are configured.
If a service listens on:
0.0.0.0
it accepts connections on every network interface, including the WireGuard interface.
WireGuard itself does not control which services are reachable.
That is the job of your operating system’s firewall.
For example, you can allow only one peer to access a service:
iptables -A INPUT -i wg0 -s 10.20.0.2 -p tcp --dport 8080 -j ACCEPT iptables -A INPUT -i wg0 -p tcp --dport 8080 -j DROP
Alternatively, many applications can be configured to listen only on their WireGuard address instead of 0.0.0.0.
For example:
10.20.0.2
instead of
0.0.0.0
This limits the service to the VPN interface and avoids exposing it on other network interfaces.
Can the Hub See Everything?
No.
With split tunneling:
- The hub sees only traffic sent across the VPN.
- It does not see normal web browsing or other internet traffic that stays on the client’s local network.
However, like any network endpoint, if a client sends data directly to a service running on the hub, that service can see the data it receives. WireGuard encrypts traffic in transit; it does not hide information from the endpoint that is intentionally receiving it.
Final Thoughts
WireGuard makes it straightforward to build a secure private network across the public Internet.
A simple hub-and-spoke topology provides:
- Encrypted communication between peers
- Support for clients behind NAT
- Dynamic public IP handling
- Split tunneling
- Simple static addressing
- Excellent performance
Combined with sensible firewall rules and good service binding practices, this architecture provides a clean, scalable foundation for private networking without forcing all internet traffic through a central VPN server.
