WireGuard is a modern VPN protocol designed around a small codebase, strong cryptography and a configuration model that is considerably simpler than many traditional VPN stacks. On Linux it integrates directly with the networking subsystem and is an excellent fit for remote administration, secure access to private services and small site-to-site deployments.
This guide builds a complete WireGuard server on Linux and prepares the foundation for two common scenarios: client-to-server remote access and site-to-site connectivity between separate networks.
Example topology
Internet
|
203.0.113.10
|
+----------------------+
| WireGuard Server |
| wg0: 10.50.0.1/24 |
| UDP: 51820 |
+----------------------+
|
+---- Client 1: 10.50.0.2
+---- Client 2: 10.50.0.3
Replace the documentation IP addresses, interface names and private networks with values appropriate for your environment. The VPN subnet must not overlap with networks already used by clients or by the server.
Prerequisites
- a Linux server with root or sudo access;
- a public IP address or a UDP port-forward from the edge router;
- UDP 51820 reachable from remote clients;
- a dedicated private VPN subnet;
- accurate system time and working DNS.
Install WireGuard
Ubuntu / Debian
apt update
apt install wireguard
On AlmaLinux or Rocky Linux, use the packages appropriate for the exact release and verify the userspace tools and kernel support after installation:
wg --version
modprobe wireguard
Generate server keys
install -d -m 700 /etc/wireguard
cd /etc/wireguard
umask 077
wg genkey | tee server.key | wg pubkey > server.pub
The private key must remain private. Treat it like any other high-value credential. The public key can be distributed to peers.
Choose the VPN subnet
10.50.0.0/24
Server: 10.50.0.1
Client1: 10.50.0.2
Client2: 10.50.0.3
Overlapping networks are a frequent source of routing problems. Avoid ranges used by the client LAN, server LAN, Docker networks, cloud networks or other VPNs.
Enable IP forwarding
If clients must reach other networks through the server or use it as an Internet gateway, enable IPv4 forwarding:
cat > /etc/sysctl.d/99-wireguard.conf <<'EOF'
net.ipv4.ip_forward = 1
EOF
sysctl --system
sysctl net.ipv4.ip_forward
Create /etc/wireguard/wg0.conf
[Interface]
Address = 10.50.0.1/24
ListenPort = 51820
PrivateKey = SERVER_PRIVATE_KEY
# Example only: replace eth0 with the actual WAN interface.
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -D FORWARD -o wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
Modern distributions may route these commands through an nftables compatibility layer. In production, integrate WireGuard with the firewall framework already used on the server instead of maintaining multiple unrelated rule sets.
Identify the external interface
ip route get 1.1.1.1
The output normally shows the interface used for the default route. Replace eth0 in the example with the real interface name.
Protect the configuration
chmod 600 /etc/wireguard/wg0.conf
chmod 600 /etc/wireguard/server.key
Open UDP 51820
UFW
ufw allow 51820/udp
ufw status verbose
firewalld
firewall-cmd --permanent --add-port=51820/udp
firewall-cmd --reload
firewall-cmd --list-ports
If the server sits behind a router, configure a UDP port-forward to the WireGuard server. Do not expose unrelated management ports simply because the VPN server is reachable from the Internet.
Start WireGuard
systemctl enable --now wg-quick@wg0
ip addr show wg0
wg show
systemctl status wg-quick@wg0
Generate a client key pair
Whenever possible, generate the client private key on the client itself so it never has to leave that device.
umask 077
wg genkey | tee client1.key | wg pubkey > client1.pub
Register the peer on the server
[Peer]
# client1
PublicKey = CLIENT1_PUBLIC_KEY
AllowedIPs = 10.50.0.2/32
Every peer needs a unique VPN address. Do not assign the same AllowedIPs address to multiple peers.
Example client configuration
[Interface]
Address = 10.50.0.2/32
PrivateKey = CLIENT1_PRIVATE_KEY
DNS = 1.1.1.1
[Peer]
PublicKey = SERVER_PUBLIC_KEY
Endpoint = vpn.example.com:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25
AllowedIPs = 0.0.0.0/0 creates a full IPv4 tunnel. If the client should reach only private resources, use only the VPN and private destination networks.
Split tunnel example
AllowedIPs = 10.50.0.0/24, 192.168.10.0/24
Normal Internet traffic then remains on the client’s existing connection while only the selected private networks traverse WireGuard.
PersistentKeepalive
PersistentKeepalive = 25 is useful on peers behind NAT when idle UDP mappings would otherwise expire. It is normally configured on the NATed peer and should not be added blindly everywhere.
Test the tunnel
ping 10.50.0.1
wg show
A healthy peer should show a recent handshake and transfer counters increasing as traffic passes through the tunnel.
No handshake: what to check
- endpoint hostname or public IP;
- UDP 51820 through host and edge firewalls;
- NAT port-forwarding;
- server and client public keys;
- whether another process is using the UDP port.
ss -lunp | grep 51820
wg show
tcpdump -ni any udp port 51820
Handshake works but traffic does not
If the peer handshakes but cannot reach its destination, WireGuard cryptography is usually working. Investigate routes, forwarding, firewall policy, NAT and AllowedIPs.
ip route
ip rule
sysctl net.ipv4.ip_forward
iptables -S
iptables -t nat -S
MTU troubleshooting
A tunnel can work for small packets while larger transfers stall. This often points to path-MTU issues, especially when WireGuard traverses PPPoE or another tunnel. Measure the path before changing the MTU and document any non-default value.
Back up the configuration securely
/etc/wireguard/
This directory contains private cryptographic material. Encrypt the backup and limit access just as you would for SSH private keys.
Operational security
- use one key pair per client;
- remove retired or lost peers promptly;
- restrict peer routes to what they actually need;
- keep the Linux host patched;
- protect SSH and local administrative access;
- monitor peer activity and unexpected configuration changes.
Useful commands
wg show
wg showconf wg0
ip addr show wg0
ip route
systemctl status wg-quick@wg0
journalctl -u wg-quick@wg0
ss -lunp | grep 51820
Checklist
- Install WireGuard from trusted repositories.
- Generate a unique server key pair.
- Select a non-overlapping VPN subnet.
- Enable forwarding only when routing is required.
- Protect
wg0.confand the private key. - Open only the required UDP port.
- Configure edge NAT where necessary.
- Start and enable the WireGuard interface.
- Generate unique keys for every peer.
- Assign unique VPN addresses.
- Test handshake and routing separately.
- Back up configuration securely.
Final thoughts
WireGuard makes VPN configuration refreshingly small, but the complete solution still depends on correct routing, firewall policy, NAT decisions and disciplined key management. Build the tunnel in layers and verify each layer before moving on.
A WireGuard tunnel is simple. Reliable VPN design still depends on correct routing, firewall policy and key management.