From 05bee8946dd96c327312c584b090d80103bf6ed9 Mon Sep 17 00:00:00 2001 From: rich Date: Sun, 29 Mar 2026 09:40:48 -0400 Subject: [PATCH] --- notes/linux/wireguard.mdwn | 413 ++++++++++++++++++++++++++++++++++++- 1 file changed, 412 insertions(+), 1 deletion(-) diff --git a/notes/linux/wireguard.mdwn b/notes/linux/wireguard.mdwn index e25c2a6..625872d 100644 --- a/notes/linux/wireguard.mdwn +++ b/notes/linux/wireguard.mdwn @@ -1 +1,412 @@ -# Wireguard on Debian +# WireGuard VPN Setup on Debian 13 + +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 `ens18`, `ens3`, 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 = +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 = +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 = +DNS = 1.1.1.1 + +[Peer] +PublicKey = +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 = +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 = +DNS = 1.1.1.1 + +[Peer] +PublicKey = +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 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 + +--- + +## 14. Recommended Next Step + +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 + +--- -- 2.47.3