When services run on more than one server — an app server in one location, a database or backup server in another — they should talk over an encrypted private link, not the open internet. A WireGuard tunnel gives each server a private address on a shared network, so you can firewall databases to the tunnel only.

This guide connects two servers, then shows how to route whole subnets (for example, an office network).

The plan

Server A (app) Server B (database)
Public IP 203.0.113.10 198.51.100.20
Tunnel IP 10.10.0.1 10.10.0.2
WireGuard port 51820/udp 51820/udp

1. Install and create keys (both servers)

apt install -y wireguard
cd /etc/wireguard && umask 077
wg genkey | tee private.key | wg pubkey > public.key
cat public.key      # copy to the other server's config

2. Configure Server A

/etc/wireguard/wg0.conf:

[Interface]
Address = 10.10.0.1/24
ListenPort = 51820
PrivateKey = <A private key>

[Peer]
PublicKey = <B public key>
Endpoint = 198.51.100.20:51820
AllowedIPs = 10.10.0.2/32
PersistentKeepalive = 25

3. Configure Server B

[Interface]
Address = 10.10.0.2/24
ListenPort = 51820
PrivateKey = <B private key>

[Peer]
PublicKey = <A public key>
Endpoint = 203.0.113.10:51820
AllowedIPs = 10.10.0.1/32
PersistentKeepalive = 25

4. Firewall and start (both servers)

Allow WireGuard only from the other server:

ufw allow from 198.51.100.20 to any port 51820 proto udp   # on A
ufw allow from 203.0.113.10 to any port 51820 proto udp    # on B
systemctl enable --now wg-quick@wg0

Test:

ping -c3 10.10.0.2     # from A
wg show                # latest handshake should be recent

5. Use the tunnel

On Server B, make the database listen on the tunnel address only and allow the app server through the tunnel:

# MariaDB: /etc/mysql/mariadb.conf.d/50-server.cnf
bind-address = 10.10.0.2
ufw allow in on wg0 from 10.10.0.1 to any port 3306 proto tcp

The application on Server A connects to 10.10.0.2:3306. Traffic is encrypted end to end and the database isn’t reachable from the internet.

6. Routing whole subnets (site-to-site)

To connect an office network 192.168.10.0/24 (behind a Linux router or a firewall that supports WireGuard) to a VPS:

  • On the VPS peer entry for the office, set AllowedIPs = 10.10.0.3/32, 192.168.10.0/24.
  • On the office router, set the VPS peer’s AllowedIPs = 10.10.0.0/24 (plus any VPS-side subnets).
  • Enable forwarding on the office router (net.ipv4.ip_forward=1) and make sure office machines route 10.10.0.0/24 via the router.

AllowedIPs acts as both an access list and a routing table: traffic to those addresses goes into the tunnel, and only packets from those addresses are accepted from that peer.

7. More than two servers

For three or more servers, either:

  • Full mesh — each server has every other as a peer (simple for a handful of servers), or
  • Hub and spoke — all servers connect to one hub that forwards between them (simpler config, one extra hop).

Tools like Netbird, Headscale (Tailscale-compatible) or Nebula automate meshes if you have many machines.

8. Monitor the tunnel

wg show wg0 latest-handshakes

A handshake older than ~3 minutes with keepalive enabled means the link is down. Add a simple check to your monitoring that pings the peer’s tunnel IP.

Latency tip

Tunnel latency equals the network latency between locations. For a database link, keep servers in the same region where possible — for example two USA VPS servers in the same city — and use cross-region tunnels for backups and replication.

Related: personal VPN on a VPS, WireGuard vs OpenVPN and encrypting VPS traffic.

  • VPN
  • WireGuard
  • Networking