securityproxy

How to Use WireGuard on Linux: From Installation to Multi-Peer Setup

FastSox Team2026-03-2711 min read

WireGuard is a modern VPN protocol built directly into the Linux kernel since version 5.6. It replaces older solutions like OpenVPN and IPsec with something radically simpler: a small, auditable codebase, state-of-the-art cryptography, and kernel-level performance. WireGuard connections are fast, stable, and roam seamlessly between networks — making it the go-to choice for anyone who needs a serious VPN layer in 2026.

In this guide you will go from zero to a fully working WireGuard setup: a server that forwards traffic for multiple peers, clients that can bring the tunnel up or down with a single command, and enough diagnostic knowledge to fix problems when they arise.

Deeper reading: If you want to understand why WireGuard is secure — the Noise protocol handshake, ChaCha20-Poly1305 encryption, and Curve25519 key exchange — see our companion article How WireGuard Works.


1. Installation

WireGuard is included in the mainline kernel, so installation on modern distributions is straightforward.

Ubuntu / Debian

sudo apt update
sudo apt install -y wireguard wireguard-tools

On Ubuntu 20.04 and earlier you may need the backports PPA:

sudo add-apt-repository ppa:wireguard/wireguard
sudo apt update
sudo apt install -y wireguard

Fedora / CentOS / RHEL

On Fedora, WireGuard is in the default repositories:

sudo dnf install -y wireguard-tools

On CentOS 8 / RHEL 8 you need to enable EPEL and the ELRepo kernel module:

sudo dnf install -y epel-release elrepo-release
sudo dnf install -y kmod-wireguard wireguard-tools

On CentOS 9 Stream and RHEL 9, WireGuard is already built into the kernel — only the tools package is needed:

sudo dnf install -y wireguard-tools

Arch Linux

sudo pacman -S wireguard-tools

Verify the install

wg --version
# wireguard-tools v1.0.20210914 - https://git.zx2c4.com/wireguard-tools/

If the command returns a version, the userspace tools are ready. The kernel module loads automatically when you bring an interface up.


2. Key Generation

WireGuard uses Curve25519 public-key cryptography. Every peer — server and client alike — needs its own key pair. Keys are just base64 strings; there are no certificate authorities or revocation lists.

Generate the server keys first:

# Create a private key and derive the public key in one pipeline
wg genkey | tee /etc/wireguard/server_private.key | wg pubkey > /etc/wireguard/server_public.key

# Lock down permissions — private keys must never be world-readable
chmod 600 /etc/wireguard/server_private.key

Print the values so you can paste them into config files:

cat /etc/wireguard/server_private.key
cat /etc/wireguard/server_public.key

Repeat for each client. You can do this on the server and distribute keys securely, or generate on the client device and only share the public key:

wg genkey | tee client1_private.key | wg pubkey > client1_public.key
wg genkey | tee client2_private.key | wg pubkey > client2_public.key
chmod 600 client1_private.key client2_private.key

3. Server Configuration

Enable IP forwarding

Before writing the WireGuard config, enable packet forwarding in the kernel. Without this, the server will receive packets from peers but refuse to route them onward:

# Apply immediately (survives until next reboot)
sudo sysctl -w net.ipv4.ip_forward=1
sudo sysctl -w net.ipv6.conf.all.forwarding=1

# Make persistent across reboots
echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.d/99-wireguard.conf
echo "net.ipv6.conf.all.forwarding=1" | sudo tee -a /etc/sysctl.d/99-wireguard.conf
sudo sysctl -p /etc/sysctl.d/99-wireguard.conf

Write /etc/wireguard/wg0.conf

Replace the placeholder values with your actual keys. The example below uses 10.0.0.0/24 as the VPN subnet and assumes your server's public internet interface is eth0 — adjust PostUp/PostDown if your interface is named differently (check with ip link show):

[Interface]
# The private IP address this server uses inside the VPN tunnel
Address = 10.0.0.1/24

# Port WireGuard listens on — open this in your firewall
ListenPort = 51820

# Paste your server private key here
PrivateKey = <SERVER_PRIVATE_KEY>

# NAT masquerade: forward peer traffic through the server's internet interface
PostUp   = iptables -A FORWARD -i %i -j ACCEPT; \
           iptables -A FORWARD -o %i -j ACCEPT; \
           iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; \
           iptables -D FORWARD -o %i -j ACCEPT; \
           iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

# --- Peer: Client 1 ---
[Peer]
PublicKey = <CLIENT1_PUBLIC_KEY>
# The IP address assigned to this client inside the VPN
AllowedIPs = 10.0.0.2/32

# --- Peer: Client 2 ---
[Peer]
PublicKey = <CLIENT2_PUBLIC_KEY>
AllowedIPs = 10.0.0.3/32

Lock down the config file:

sudo chmod 600 /etc/wireguard/wg0.conf

Open the firewall port

# UFW (Ubuntu/Debian)
sudo ufw allow 51820/udp

# firewalld (Fedora/CentOS)
sudo firewall-cmd --permanent --add-port=51820/udp
sudo firewall-cmd --reload

# iptables directly
sudo iptables -A INPUT -p udp --dport 51820 -j ACCEPT

4. Client Configuration

On each client machine, create /etc/wireguard/wg0.conf. The client config is structurally identical to the server config — it has an [Interface] block for its own identity and a [Peer] block pointing at the server:

[Interface]
# This client's private IP inside the VPN
Address = 10.0.0.2/24

# This client's private key
PrivateKey = <CLIENT1_PRIVATE_KEY>

# Optional: use the VPN as the DNS resolver
DNS = 1.1.1.1

[Peer]
# The server's public key
PublicKey = <SERVER_PUBLIC_KEY>

# Server's public IP (or hostname) and port
Endpoint = <SERVER_PUBLIC_IP>:51820

# Route all internet traffic through the VPN
# Use "10.0.0.0/24" here instead to only route VPN subnet traffic (split tunnel)
AllowedIPs = 0.0.0.0/0, ::/0

# Keep the tunnel alive through NAT — send a keepalive every 25 seconds
PersistentKeepalive = 25

Set permissions:

sudo chmod 600 /etc/wireguard/wg0.conf

5. Bringing the Tunnel Up

wg-quick is a convenience wrapper around wg and ip that handles interface creation, routing, and iptables rules automatically.

# Start the tunnel
sudo wg-quick up wg0

# Stop the tunnel
sudo wg-quick down wg0

Enable on boot with systemd

# Enable auto-start at boot
sudo systemctl enable wg-quick@wg0

# Start it now without rebooting
sudo systemctl start wg-quick@wg0

# Check status
sudo systemctl status wg-quick@wg0

To disable:

sudo systemctl disable wg-quick@wg0
sudo systemctl stop wg-quick@wg0

6. Multi-Peer Setup

WireGuard's peer model is flat — there is no hierarchy between server and clients. The "server" is just a peer that happens to have ListenPort set and acts as a router. Adding more clients is as simple as adding more [Peer] blocks to the server config and assigning each one a unique IP in the VPN subnet.

Adding a third client

Generate keys for the new client:

wg genkey | tee client3_private.key | wg pubkey > client3_public.key

Add a block to /etc/wireguard/wg0.conf on the server:

[Peer]
PublicKey = <CLIENT3_PUBLIC_KEY>
AllowedIPs = 10.0.0.4/32

You can reload the running interface without a full restart using wg syncconf or wg addpeer:

# Hot-reload from the config file (no downtime for existing peers)
sudo wg syncconf wg0 <(wg-quick strip wg0)

The wg-quick strip command strips wg-quick-specific directives (Address, PostUp, etc.) before passing the config to wg syncconf, which only understands native WireGuard options.

Subnet allocation tip

Keep a simple allocation table so you don't accidentally reuse addresses:

| Peer | VPN IP | |----------|-------------| | Server | 10.0.0.1 | | Client 1 | 10.0.0.2 | | Client 2 | 10.0.0.3 | | Client 3 | 10.0.0.4 |

For large deployments, consider a /16 subnet (10.0.0.0/16) to give yourself room to grow.


7. Verifying the Tunnel

wg show

On the server, wg show is your first diagnostic tool:

sudo wg show

Sample output:

interface: wg0
  public key: <SERVER_PUBLIC_KEY>
  private key: (hidden)
  listening port: 51820

peer: <CLIENT1_PUBLIC_KEY>
  endpoint: 203.0.113.42:54321
  allowed ips: 10.0.0.2/32
  latest handshake: 14 seconds ago
  transfer: 1.23 MiB received, 4.56 MiB sent

What to look for:

  • latest handshake — if this is missing or very stale (> 3 minutes with PersistentKeepalive = 25), the peer is not connected.
  • transfer — bytes are moving, which confirms data is flowing.
  • endpoint — the peer's current public IP and ephemeral port. WireGuard auto-updates this when a peer roams.

Ping across the tunnel

From a connected client, ping the server's VPN IP:

ping 10.0.0.1

From the server, ping a client:

ping 10.0.0.2

Verify traffic routing

If you used AllowedIPs = 0.0.0.0/0 on the client, all traffic should now egress through the server. Confirm with:

curl https://ifconfig.me

The returned IP should be the server's public IP, not your local ISP address.


8. Troubleshooting

Tunnel comes up but no traffic flows

Check IP forwarding. This is the most common cause:

sysctl net.ipv4.ip_forward
# Should return: net.ipv4.ip_forward = 1

If it returns 0, re-apply the sysctl settings from Section 3.

Check iptables NAT rules:

sudo iptables -t nat -L POSTROUTING -n -v

You should see a MASQUERADE rule for eth0. If not, the PostUp script did not run — bring the interface down and up again:

sudo wg-quick down wg0 && sudo wg-quick up wg0

Handshake never completes

This almost always means the UDP port is blocked by a firewall. Verify from the client side:

# Test UDP reachability (requires nmap)
sudo nmap -sU -p 51820 <SERVER_PUBLIC_IP>

On the server, confirm the port is actually listening:

sudo ss -ulnp | grep 51820

Make sure both your OS firewall (UFW/firewalld/iptables) and any cloud security group / VPS firewall panel are open for 51820/udp.

MTU issues causing dropped packets or slow connections

WireGuard adds overhead to each packet (headers + encryption). If the MTU on wg0 is too large, packets get fragmented or silently dropped. The default wg-quick MTU is usually fine, but if you see issues with large transfers while small pings work:

# Check current MTU
ip link show wg0

# Set a lower MTU (1380 is a safe choice for most networks)
sudo ip link set wg0 mtu 1380

To make the MTU persistent, add it to the [Interface] section of your config:

[Interface]
Address = 10.0.0.2/24
PrivateKey = <CLIENT1_PRIVATE_KEY>
MTU = 1380

DNS leaks

If you set DNS = 1.1.1.1 in the client config but DNS queries still go out over the unencrypted interface, check that systemd-resolved is active and that wg-quick is correctly applying the DNS setting:

# See which DNS is currently active
resolvectl status

# Force flush the cache
sudo resolvectl flush-caches

Logging

WireGuard intentionally produces minimal kernel logs to avoid leaking metadata. To enable debug output temporarily:

echo module wireguard +p | sudo tee /sys/kernel/debug/dynamic_debug/control
# Watch output
sudo dmesg -w | grep wireguard

Remember to disable debug logging when you are done:

echo module wireguard -p | sudo tee /sys/kernel/debug/dynamic_debug/control

FastSox and WireGuard

FastSox uses WireGuard as the foundation of its VPN layer, extended with intelligent routing, multi-gateway failover, and a subscription-based access model. If you prefer a managed solution over running your own WireGuard server, FastSox handles key distribution, gateway provisioning, and routing policy automatically — you connect, it works.

For a deep dive into the cryptographic protocol that makes all of this possible, read How WireGuard Works.

FastSox is developed by OneDotNet Ltd.


Summary

Here is a quick reference for the commands used in this guide:

| Task | Command | |------|---------| | Install (Ubuntu) | sudo apt install wireguard wireguard-tools | | Generate private key | wg genkey | | Derive public key | wg pubkey < private.key | | Bring tunnel up | sudo wg-quick up wg0 | | Bring tunnel down | sudo wg-quick down wg0 | | Enable on boot | sudo systemctl enable wg-quick@wg0 | | Show status | sudo wg show | | Hot-reload config | sudo wg syncconf wg0 <(wg-quick strip wg0) |

WireGuard's simplicity is its greatest strength. A complete, production-ready VPN fits in a handful of config lines — and once you understand the key-exchange model, adding new peers takes under a minute. That same simplicity is why FastSox chose WireGuard as its tunneling backbone.

#wireguard#linux#vpn#networking#kernel

Related Articles