Practical guide: set up a WireGuard road‑warrior VPN on Debian for secure remote access

Redes & Segurança · By · Published on · Updated on · 8 min read

Step-by-step: set up WireGuard road‑warrior VPN on Debian
Photo: Stefan Coders / Pexels

Step-by-step: set up a WireGuard road‑warrior VPN on Debian for secure remote access. This hands-on guide walks you from planning the subnet to validating connectivity: choose the VPN subnet, install packages, generate keys, create wg0.conf, enable IP forwarding and NAT, add peers, and run tests. Each step includes clear commands and troubleshooting tips.

Prerequisites and road‑warrior topology planning

You need an up-to-date Debian server, root (or sudo) access, and a UDP port open in the firewall. Ideally the server has a public IP. If it's behind CGNAT, the remote client will NOT be able to initiate the tunnel.

Decide in advance: VPN subnet, outbound interface, WireGuard port, client addresses, and routing policies.

If you're still choosing infrastructure, see a practical comparison of hosting options (compare VPS, shared hosting, and bare metal). Also review how to choose a Linux server distribution and how to choose the right VPS size.

  • Debian 11/12 server with sudo or root
  • UDP port (e.g., 51820) open externally
  • Outbound interface identified (e.g., eth0/ens3)
  • VPN subnet reserved and unused (e.g., 10.8.0.0/24)
  • Remote client(s) assigned unique /32 IPs on the VPN
Parameter Example
VPN subnet 10.8.0.0/24
Server IP (VPN) 10.8.0.1
Client 1 IP (VPN) 10.8.0.2/32
WireGuard port (UDP) 51820
Outbound interface eth0

1) Install WireGuard on Debian

Install the official packages. On modern kernels the WireGuard module is already included. Run the commands as root or with sudo. Then verify the module loaded correctly.

apt update
apt install -y wireguard wireguard-tools
modprobe wireguard || true
lsmod | grep wireguard || echo "wireguard embutido no kernel (ok)"

2) Generate and secure the server keys

Keys are the heart of the VPN. Generate the server keypair and restrict file permissions. Never share the private key. Keep the public key handy: clients will use it to authenticate the server.

umask 077
wg genkey | tee /etc/wireguard/server_private.key | wg pubkey > /etc/wireguard/server_public.key
echo "Chave pública do servidor:" && cat /etc/wireguard/server_public.key

3) Create /etc/wireguard/wg0.conf (server)

Create the wg0 interface with the VPN internal IP and the chosen UDP port. Use SaveConfig=true to persist changes made via wg/wg-quick. Replace the PrivateKey value with the actual content from the file generated in the previous step.

# /etc/wireguard/wg0.conf
[Interface]
Address = 10.8.0.1/24
ListenPort = 51820
PrivateKey = <conteudo de /etc/wireguard/server_private.key>
SaveConfig = true

4) Enable IP forwarding and configure NAT (internet access)

To let clients reach the internet via the server, enable IPv4 forwarding. Then apply NAT (masquerade) with nftables. This turns your server into a gateway—review your firewall policies accordingly.

If you prefer UFW, you can integrate the rules. See How to set up a firewall on Ubuntu with UFW for guidance.

# Habilitar roteamento IPv4 em tempo de execução e tornar permanente
sysctl -w net.ipv4.ip_forward=1
sed -i 's/^#\?net.ipv4.ip_forward=.*/net.ipv4.ip_forward=1/' /etc/sysctl.conf

# Instalar e habilitar nftables
apt install -y nftables
systemctl enable --now nftables

# Criar regra de NAT (ajuste a interface de saída, ex.: eth0)
cat >/etc/nftables.d/wireguard-nat.nft <<'EOF'
table ip wg {
  chain postrouting {
    type nat hook postrouting priority 100;
    oifname "eth0" ip saddr 10.8.0.0/24 counter masquerade
  }
}
EOF

# Incluir diretório customizado no nftables.conf (somente se ainda não incluído)
grep -q 'include "/etc/nftables.d/*.nft"' /etc/nftables.conf || \
  printf '\ninclude "/etc/nftables.d/*.nft"\n' >> /etc/nftables.conf

# Recarregar regras
nft -f /etc/nftables.conf
nft list ruleset | sed -n '1,120p'

5) Bring up WireGuard and validate the server

Enable the wg0 interface now and at boot. Then inspect the VPN state. Without peers you won't see handshakes yet. The interface should be UP and show the configured IP.

systemctl enable --now wg-quick@wg0
systemctl status wg-quick@wg0 --no-pager || true
wg show
ip a show wg0

6) Provision a client (road‑warrior) peer

Generate the keys on the client device when possible. Then build the client configuration and register the peer on the server. Exchange keys securely. Set the Endpoint to the server's public IP or DNS.

# No cliente (ou em estação segura), gerar chaves
umask 077
wg genkey | tee ~/client1_private.key | wg pubkey > ~/client1_public.key
echo "Pub do cliente:" && cat ~/client1_public.key

# Arquivo de configuração do cliente (ex.: client1.conf)
cat > ~/client1.conf <<'EOF'
[Interface]
PrivateKey = <client1_private_key>
Address = 10.8.0.2/32
DNS = 1.1.1.1

[Peer]
PublicKey = <server_public_key>
AllowedIPs = 0.0.0.0/0
Endpoint = <IP_ou_DNS_publico_servidor>:51820
PersistentKeepalive = 25
EOF

# No servidor: adicionar o peer ao wg0.conf e recarregar
# (cole a chave pública real do cliente em <client1_public_key>)
cat >>/etc/wireguard/wg0.conf <<'EOF'

[Peer]
PublicKey = <client1_public_key>
AllowedIPs = 10.8.0.2/32
EOF

# Sincronizar configuração sem derrubar a interface
wg syncconf wg0 <(wg-quick strip wg0)
wg show

7) Tests, MTU and common troubleshooting

Validate the connection by connecting the client and observing the handshake. Test ping and routing. If you see packet loss on mobile networks, adjust MTU—1420 is a common good starting point. Firewalls upstream can block UDP; check provider or appliance rules.

Done: the step-by-step WireGuard road‑warrior VPN setup on Debian is complete.

  • Check status: wg show (recent handshake, TX/RX bytes)
  • Ping the server VPN IP (10.8.0.1) and external hosts
  • Adjust MTU on the client: add MTU = 1420 under [Interface]
  • If the server is behind NAT, use PersistentKeepalive = 25
  • Confirm NAT: nft list ruleset should show masquerade on the correct oifname
  • DNS: if IPs work but names don't, review the client's DNS field
# No servidor
wg show

# No cliente
ping -c 3 10.8.0.1 || true
ping -c 3 1.1.1.1 || true

# Inspecionar NAT
nft list ruleset | grep -A3 'table ip wg' || true

Frequently asked questions

Which port should I use for WireGuard?

The common default is UDP 51820, but you may choose any UDP port that suits your environment. Whatever port you pick, open it in the server firewall and any cloud provider security groups, and ensure UDP is allowed through any upstream NAT or appliance. Changing the port can help avoid conflicts or simple scanning noise.

Can I have multiple clients (peers)?

Yes. Each client needs its own keypair and a unique /32 VPN address assigned from the VPN subnet. On the server, add a [Peer] block per client containing that client’s public key and its AllowedIPs. Exchange keys securely and verify each peer shows recent handshakes once connected.

Do I need DKMS on current Debian?

On recent Debian releases the WireGuard kernel module is already included, so installing the wireguard package and wireguard-tools is normally sufficient. You can optionally modprobe the module to check it loads, but DKMS is not required for typical modern Debian kernels that already ship WireGuard support.

How do I persist rules if I use iptables instead of nftables?

Debian’s modern default is nftables, but if you use iptables you can install iptables-nft and the netfilter-persistent package to save and restore rules at boot. netfilter-persistent captures the current ruleset and reloads it on startup; alternatively migrate rules to nftables, which the guide recommends for new setups.

How do I route only specific subnets through the VPN?

Create a split-tunnel by setting AllowedIPs on the client to only the networks you want routed via the VPN (for example the VPN subnet and specific remote subnets). Avoid using 0.0.0.0/0 if you don’t want full-tunnel routing. Verify routes and test connectivity after adjusting AllowedIPs to ensure only intended traffic goes through the tunnel.

How do I use the VPN with IPv6?

Assign an IPv6 ULA prefix (for example fd00:8::/64) to server and clients, enable IPv6 forwarding (net.ipv6.conf.all.forwarding=1), and include IPv6 prefixes in AllowedIPs. If you need IPv6 NAT, add appropriate NAT66 rules. Adjust firewall and routing to handle the IPv6 ranges you assign and test name and address resolution.

Want a security second opinion?

If you need rule reviews, firewall hardening, or reproducible playbooks for your WireGuard setup, we can discuss your architecture and next steps.

Discuss your setup

See also