Linux

Wireguard Setup on Debian 13

February 20, 2026 Rich 5 min read

Clean, minimal, self-hosted WireGuard setup with:

  • Full tunnel support
  • NAT for internet access
  • Multi-user capability
  • Per-user access control via firewall

0. Assumptions

  • Public interface: eth0
  • VPN subnet: 10.10.10.0/24
  • Server is publicly reachable

Replace eth0 with your real interface name if needed, such as ens18ens3, or enp1s0.

1. Install WireGuard

apt update
apt install wireguard

2. Enable IP Forwarding

sysctl -w net.ipv4.ip_forward=1

Persist it:

echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
sysctl -p

3. Generate Keys

cd /etc/wireguard

wg genkey | tee server.key | wg pubkey > server.pub
wg genkey | tee client.key | wg pubkey > client.pub

chmod 600 *.key

4. Server Configuration

Create:

nano /etc/wireguard/wg0.conf
[Interface]
Address = 10.10.10.1/24
PrivateKey = <contents of server.key>
ListenPort = 51820

# NAT + forwarding
PostUp = iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT
PostUp = iptables -A FORWARD -o wg0 -j ACCEPT

PostDown = iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT
PostDown = iptables -D FORWARD -o wg0 -j ACCEPT

[Peer]
PublicKey = <contents of client.pub>
AllowedIPs = 10.10.10.2/32

Notes:

  • Address = 10.10.10.1/24 is the server’s VPN IP.
  • AllowedIPs = 10.10.10.2/32 means that client owns only 10.10.10.2.
  • Do not reuse keys between devices.

5. Start WireGuard

wg-quick up wg0
systemctl enable wg-quick@wg0

Check status:

wg show
ip addr show wg0

6. Client Configuration

Use this on Windows, Linux, or macOS:

[Interface]
Address = 10.10.10.2/24
PrivateKey = <contents of client.key>
DNS = 1.1.1.1

[Peer]
PublicKey = <contents of server.pub>
Endpoint = YOUR_SERVER_IP:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25

Notes:

  • AllowedIPs = 0.0.0.0/0 sends all client traffic through the VPN.
  • If you only want access to specific private networks, replace 0.0.0.0/0 with those subnets.

Example split tunnel:

AllowedIPs = 10.10.10.0/24, 192.168.50.0/24

7. Open Firewall Port

If using UFW:

ufw allow 51820/udp

Or raw iptables:

iptables -A INPUT -p udp --dport 51820 -j ACCEPT

8. Test Connection

From the client:

curl ip.me

Expected result:

  • If full tunnel is enabled, this should show the server’s public IP.

Also test:

ping 10.10.10.1

9. Add Additional Users

Generate new keys:

wg genkey | tee user2.key | wg pubkey > user2.pub
chmod 600 user2.key

Add to server config:

[Peer]
PublicKey = <contents of user2.pub>
AllowedIPs = 10.10.10.3/32

Apply changes:

wg syncconf wg0 <(wg-quick strip wg0)

Client config example for user2:

[Interface]
Address = 10.10.10.3/24
PrivateKey = <contents of user2.key>
DNS = 1.1.1.1

[Peer]
PublicKey = <contents of server.pub>
Endpoint = YOUR_SERVER_IP:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25

10. Access Control and Network Design

WireGuard handles authentication by key.

WireGuard does not decide what a connected peer is allowed to reach.
That is handled by your firewall, typically with iptables or nftables.

Think of it like this:

  • WireGuard key + peer IP = identity
  • Firewall rules = authorization

Important

The examples below use:

  • 10.10.10.2 = full access user
  • 10.10.10.3 = restricted user
  • 10.10.10.4 = internet-only user

Adjust these to your actual peer IP assignments.

Scenario A: Public server only, no private networks behind it

This is the simplest case.

The server only has:

  • eth0 facing the internet
  • wg0 for VPN clients

There is no LAN behind the server. You just want clients to:

  • connect to the server
  • route internet traffic through it
  • maybe reach services running on the server itself

Full tunnel user

iptables -A FORWARD -i wg0 -s 10.10.10.2 -o eth0 -j ACCEPT
iptables -A FORWARD -o wg0 -d 10.10.10.2 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

Internet-only restricted user

iptables -A FORWARD -i wg0 -s 10.10.10.4 -o eth0 -j ACCEPT
iptables -A FORWARD -o wg0 -d 10.10.10.4 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -i wg0 -s 10.10.10.4 -j DROP

That last rule says:

  • allow that peer out to the internet
  • drop any other forwarded access attempt

If the user also needs to reach services hosted directly on the VPN server itself, that is controlled by INPUT rules, not FORWARD.

Example: allow SSH from one VPN peer to the server:

iptables -A INPUT -i wg0 -s 10.10.10.3 -p tcp --dport 22 -j ACCEPT

Example: block all other VPN clients from SSH to the server:

iptables -A INPUT -i wg0 -p tcp --dport 22 -j DROP

Scenario B: Server has private networks behind it

Use this if the Debian server can route to private networks such as:

  • 192.168.1.0/24
  • 10.0.0.0/24
  • 172.16.50.0/24

In this case, your VPN clients can be selectively allowed to those networks.

Full access user to all routed private networks

iptables -A FORWARD -i wg0 -s 10.10.10.2 -j ACCEPT

That is broad. It allows that peer to anything the server can route to.

Restricted user to a single host

Example: only allow 10.10.10.3 to reach 192.168.1.50

iptables -A FORWARD -i wg0 -s 10.10.10.3 -d 192.168.1.50 -j ACCEPT
iptables -A FORWARD -i wg0 -s 10.10.10.3 -j DROP

Restricted user to a whole subnet

Example: only allow 10.10.10.3 to reach 192.168.1.0/24

iptables -A FORWARD -i wg0 -s 10.10.10.3 -d 192.168.1.0/24 -j ACCEPT
iptables -A FORWARD -i wg0 -s 10.10.10.3 -j DROP

Internet plus one private subnet

Example: allow 10.10.10.3 to:

  • use the server as an internet gateway
  • access 192.168.1.0/24
  • nothing else
iptables -A FORWARD -i wg0 -s 10.10.10.3 -d 192.168.1.0/24 -j ACCEPT
iptables -A FORWARD -i wg0 -s 10.10.10.3 -o eth0 -j ACCEPT
iptables -A FORWARD -o wg0 -d 10.10.10.3 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -i wg0 -s 10.10.10.3 -j DROP

Client-side route restriction

You should also tighten the client config.

If a peer should only reach one private subnet, do not send all traffic through the tunnel.

Example client config:

AllowedIPs = 10.10.10.0/24, 192.168.1.0/24

That gives split-tunnel access only to:

  • the VPN subnet
  • the private subnet behind the server

11. Remove or Revoke Access

Remove a peer immediately:

wg set wg0 peer <public_key> remove

Or edit wg0.conf and reload:

wg syncconf wg0 <(wg-quick strip wg0)

12. Common Issues

  • IP forwarding not enabled
  • Wrong public interface name
  • Firewall blocking UDP 51820
  • NAT rule missing
  • Server not publicly reachable
  • Client AllowedIPs too broad or too narrow
  • Client clock wildly wrong
  • Forgot PersistentKeepalive = 25 for clients behind NAT

13. Key Concepts

  • Each peer should have its own keypair
  • No passwords or usernames in WireGuard
  • One device should not share another device’s key
  • VPN peer IPs should be treated like identities
  • Firewall rules decide what each peer can reach

This walkthrough uses iptables because it is straightforward and familiar.

For a cleaner long-term setup on Debian 13, consider moving the policy to nftables, especially if you will have:

  • multiple users
  • different access classes
  • persistent firewall rules you want managed sanely

Leave a comment