#dedicated-servers

WireGuard Server Setup on Linux (wg0, NAT, Peers)

12 min read - June 22, 2026

hero section cover
Table of contents
  • When to use a WireGuard server
  • Server setup
  • Adding and removing peers
  • Troubleshooting
  • Key rotation and pre-shared keys
Share

Practical WireGuard server setup for Linux: keys, wg0.conf, NAT, peer management with syncconf, and the troubleshooting commands sysadmins actually use.

Run a WireGuard server when you want private access to hosted infrastructure without exposing admin ports to the public internet. It uses public-key authentication, runs inside the Linux kernel since 5.6, and stays out of the way once it's up. This post covers when to use a WireGuard server, how to bring up wg0, and how to keep peers working day to day.

When to use a WireGuard server

Three patterns cover most setups: remote access, server-to-server links, and site-to-site routing.

For remote access, run the server on a VPS or dedicated host and route admin traffic through the tunnel. Set AllowedIPs on each peer to the private management subnet (something like 10.0.0.0/24) so only traffic for internal systems uses the tunnel. Everything else stays on the user's local connection. If users connect from home or mobile networks, add PersistentKeepalive = 25 on the client side to keep NAT sessions from being torn down.

For server-to-server links, keep AllowedIPs narrow. Usually a single /32 or a small backend subnet. That avoids pulling unrelated traffic into the tunnel and keeps routing predictable.

Site-to-site is different. The WireGuard host acts as a gateway between subnets, so IP forwarding has to be enabled and the NAT rules have to send return traffic out the right interface.

PatternAllowedIPs scopeBest fitSetup complexity
Remote accessPrivate subnets, e.g. 10.0.0.0/24Admin and developer accessLow
Server-to-serverSpecific IPs or backend subnetPoint-to-point host linksLow to medium
Site-to-siteEntire remote LAN, e.g. /24Gateway-to-gateway routingMedium to high
Private service accessInternal subnet only (split-tunnel)Backend service isolationMedium

Server setup

The server holds the private key, listens on UDP 51820 by default, and terminates the tunnel. The same base setup works for all three patterns above.

Keys and wg0.conf

Generate the server keypair:

wg genkey | sudo tee /etc/wireguard/server_private.key | wg pubkey | sudo tee /etc/wireguard/server_public.key

Lock down the private key:

sudo chmod 600 /etc/wireguard/server_private.key

The private key stays on the server. The public key is what you hand to peers.

Create /etc/wireguard/wg0.conf:

[Interface]
Address = 10.8.0.1/24
ListenPort = 51820
PrivateKey = <SERVER_PRIVATE_KEY>
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o <PUBLIC_IFACE> -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o <PUBLIC_IFACE> -j MASQUERADE
 
[Peer]
PublicKey = <CLIENT_PUBLIC_KEY>
AllowedIPs = 10.8.0.2/32

Find the outbound interface to drop into <PUBLIC_IFACE> with:

ip -o -4 route show to default | awk '{print $5}'

Forwarding, firewall, and NAT

Open the listening port:

sudo ufw allow 51820/udp

Enable IP forwarding by adding this line to /etc/sysctl.conf:

net.ipv4.ip_forward = 1

Apply without rebooting:

sudo sysctl -p

The PostUp and PostDown lines in wg0.conf add and remove the NAT masquerade rule when the interface comes up or down. Without them, return traffic from the LAN never makes it back to the peer.

Bringing the tunnel up

wg-quick handles the interface, routing, and the PostUp/PostDown hooks in one command:

sudo wg-quick up wg0

For automatic startup after reboot, enable the systemd unit:

sudo systemctl enable --now wg-quick@wg0

Check status with:

sudo wg show

A recent latest handshake line confirms the tunnel is working. If it looks stale or empty, check the firewall, the keys on both sides, and the peer's AllowedIPs.

Adding and removing peers

Each peer needs its own keypair. Generate it on the client, then add the peer's public key to wg0.conf in a new [Peer] block with an AllowedIPs entry that assigns its tunnel IP.

Use /32 for a single device:

AllowedIPs = 10.8.0.3/32

That stops one peer from claiming addresses assigned to another. For split-tunnel access, list only the private subnets that should go through the tunnel, for example AllowedIPs = 10.8.0.0/24.

Apply config changes without dropping active sessions:

sudo wg syncconf wg0 <(wg-quick strip wg0)

Removing a peer works the same way. Delete its [Peer] block from wg0.conf and run syncconf again.

Troubleshooting

If a peer connects but can't reach anything on the other side, the cause is usually one of four things:

  • IP forwarding is off
  • The NAT masquerade rule is missing
  • The outbound interface in the NAT rule is wrong
  • AllowedIPs doesn't include the destination

Check forwarding:

cat /proc/sys/net/ipv4/ip_forward

Should return 1. If it returns 0, the sysctl change didn't apply or wasn't saved.

Check the NAT rule and outbound interface:

sudo iptables -t nat -L POSTROUTING
ip route get 1.1.1.1

The second command shows the actual outbound interface name, such as ens3, enp1s0, or eth0. That has to match the interface in the MASQUERADE rule.

If the handshake itself is missing, check that UDP 51820 is open at the firewall and at any upstream provider, and that both sides have the right public key for the other.

For peers behind residential or mobile NAT that drops idle UDP sessions, set PersistentKeepalive = 25 on the client.

Key rotation and pre-shared keys

For tunnels that stay up for months, rotate keys once a year or so. Generate a new keypair, update both ends, and apply with wg syncconf. Don't reuse a private key across two peers. That creates routing conflicts and breaks delivery between them.

For an extra layer on top of public-key auth, add a pre-shared key per peer:

wg genpsk

Add the result as PresharedKey = <PSK> in the [Peer] block on both sides. WireGuard mixes the PSK into the handshake, so an attacker who somehow compromises one of the asymmetric keys still can't decrypt traffic without it.

Useful day-to-day commands:

CommandPurpose
wg showPeers, handshakes, traffic counters
wg show wg0 transferByte counters for wg0
wg show all dumpMachine-parseable output for monitoring scripts
wg syncconf wg0 <(wg-quick strip wg0)Apply config changes without dropping sessions
wg genpskGenerate a pre-shared key

If you need a stable, publicly reachable host to terminate WireGuard tunnels and route private traffic into your infrastructure, take a look at FDC's unmetered VPS plans.

Blog

Featured this week

More articles
Digital eye strain: How to protect your vision in a screen-heavy world

Digital eye strain: How to protect your vision in a screen-heavy world

Staring at screens all day? Learn how to reduce digital eye strain with proven techniques and tools. This guide is essential for remote workers, developers, and anyone in tech.

4 min read - May 21, 2025

Why it's important to have a powerful and unmetered VPS

8 min read - May 9, 2025

More articles
background image

Have questions or need a custom solution?

icon

Flexible options

icon

Global reach

icon

Instant deployment

icon

Flexible options

icon

Global reach

icon

Instant deployment