Skip to content
CitexNode
All guides

WireGuard VPN between VPS and PC

Generate keys, wg0.conf on both sides, firewall, and forwarding only if you want to reach the internet through it.

5 min read

WireGuard connects your PC and your VPS through an encrypted tunnel. You can then reach services on the server that should not be open to the internet (database, admin interfaces) via a private address.

Covers Debian 12 and 13, Ubuntu 22.04 and 24.04, AlmaLinux 9 and Rocky Linux 9 on the server. On the PC, use the official WireGuard app from https://www.wireguard.com/install/ (Windows, macOS, Linux, Android, iOS). Server commands run as root.

We use this small network:

DeviceTunnel address
VPS10.8.0.1
PC10.8.0.2

Install

Debian and Ubuntu:

bash
apt update
apt install -y wireguard-tools

AlmaLinux and Rocky Linux:

bash
dnf install -y wireguard-tools

The kernel module is already included on all these systems.

Generate keys

On the server:

bash
cd /etc/wireguard
umask 077
wg genkey | tee server.key | wg pubkey > server.pub
cat server.pub

server.key is secret and stays on the server. server.pub is the public key; the PC gets that one.

On the PC: in the WireGuard app, Add Tunnel → Add empty tunnel (Windows) or "Create from scratch". The app generates the private key itself and shows the public key. On Linux, use the same commands as on the server (client.key, client.pub).

Server: wg0.conf

Create /etc/wireguard/wg0.conf. PrivateKey is the content of server.key, PublicKey is the PC's public key:

ini
[Interface]
Address = 10.8.0.1/24
ListenPort = 51820
PrivateKey = CONTENT-OF-server.key

[Peer]
# My PC
PublicKey = PUBLIC-KEY-OF-THE-PC
AllowedIPs = 10.8.0.2/32

PC: tunnel configuration

In the app (or on Linux in /etc/wireguard/wg0.conf). The app has already filled in PrivateKey. Endpoint is your VPS's IPv4 from the dashboard (Network tab):

ini
[Interface]
PrivateKey = PRIVATE-KEY-OF-THE-PC
Address = 10.8.0.2/24

[Peer]
PublicKey = CONTENT-OF-server.pub
Endpoint = YOUR-SERVER-IP:51820
AllowedIPs = 10.8.0.0/24
PersistentKeepalive = 25

AllowedIPs = 10.8.0.0/24 means only traffic to the tunnel network goes through the tunnel; everything else goes straight to the internet as usual. PersistentKeepalive keeps the connection open when your PC sits behind a router with NAT.

Firewall and start

Open UDP 51820 on the server.

Debian and Ubuntu with ufw:

bash
ufw allow 51820/udp

AlmaLinux and Rocky Linux with firewalld:

bash
firewall-cmd --permanent --add-port=51820/udp
firewall-cmd --reload

Start the tunnel on the server and bring it up on boot:

bash
systemctl enable --now wg-quick@wg0

On the PC, click Activate in the app (Linux: wg-quick up wg0).

Check that it worked

On the server:

bash
wg show

The peer should show a latest handshake a few seconds ago and transfer data in both directions.

From the PC:

bash
ping 10.8.0.1

If the ping works, the tunnel is up. Services that listen only on 10.8.0.1 on the server can now only be reached through the tunnel.

Only if needed: route all traffic through the VPS

If you want your PC to reach the internet via the VPS (e.g. on public Wi-Fi), the server needs forwarding and NAT. For simple access to the server you do not need this; skip it then.

  1. Enable forwarding:

    bash
    echo 'net.ipv4.ip_forward = 1' > /etc/sysctl.d/99-wireguard.conf
    sysctl --system
  2. Find the name of the network interface the server uses for the internet (after dev):

    bash
    ip route show default
  3. Set up NAT.

    Debian and Ubuntu: add this under [Interface] in /etc/wireguard/wg0.conf, replacing eth0 with your interface name:

    ini
    PostUp = nft add table ip wg-nat; nft add chain ip wg-nat post '{ type nat hook postrouting priority 100; }'; nft add rule ip wg-nat post oifname "eth0" ip saddr 10.8.0.0/24 masquerade
    PostDown = nft delete table ip wg-nat

    If the nft command is missing, install it with apt install -y nftables.

    If you use ufw, also allow forwarding: ufw route allow in on wg0 out on eth0.

    AlmaLinux and Rocky Linux with firewalld:

    bash
    firewall-cmd --permanent --zone=public --add-masquerade
    firewall-cmd --permanent --zone=trusted --add-interface=wg0
    firewall-cmd --reload
  4. On the PC, set AllowedIPs = 0.0.0.0/0 and add a DNS server, e.g. DNS = 1.1.1.1 under [Interface].

  5. On the server run systemctl restart wg-quick@wg0, on the PC reactivate the tunnel.

Check: on the PC, a page like https://ifconfig.co now shows your VPS's IPv4.

Common errors

  • No handshake. UDP 51820 is closed, the server IP in Endpoint is wrong, or the public keys are swapped. Each side enters the public key of the other side under its peer.
  • Handshake yes, ping no. The addresses do not match AllowedIPs. The server needs 10.8.0.2/32 for the peer, the PC 10.8.0.0/24.
  • wg-quick reports "Line unrecognized". A typo in wg0.conf, often a missing =.
  • With 0.0.0.0/0 nothing reaches the internet. Forwarding or NAT is missing on the server, or the interface name in the PostUp line is wrong.
  • The tunnel is gone after a server reboot. You forgot systemctl enable wg-quick@wg0.

What next

  • Each additional device gets its own [Peer] block with its own address, e.g. 10.8.0.3/32.
  • Make the database reachable only through the tunnel: Set up MariaDB.

If you get stuck, open a ticket.