Configure a Zero-Trust WireGuard VPN with Per-User Access and DNS Blocking on Linux

A basic VPN is easy to set up, but a modern network needs more than “connect and hope for the best.” A Zero-Trust WireGuard VPN is a practical way to give remote users access to only what they need, while keeping everything else blocked by default. In this tutorial you will build a WireGuard server on Linux, create per-user profiles, restrict each user to specific internal subnets, and add DNS-based blocking to reduce malware and ads on connected devices.

Prerequisites

You will need: (1) a Linux server with a public IP (Ubuntu/Debian examples are used), (2) root or sudo access, (3) a domain name (optional but useful), and (4) one or more internal networks to protect (for example, 10.10.0.0/16). You should also know which UDP port you want for WireGuard (the default is 51820/UDP).

Step 1: Install WireGuard

Update packages and install WireGuard:

Ubuntu/Debian:

sudo apt update && sudo apt install -y wireguard iptables-persistent

Enable IP forwarding so the server can route traffic between VPN and internal networks:

sudo sysctl -w net.ipv4.ip_forward=1

Make it persistent:

echo "net.ipv4.ip_forward=1" | sudo tee /etc/sysctl.d/99-wireguard.conf

Step 2: Generate Server Keys

WireGuard uses simple public/private keys. Create them with tight permissions:

umask 077

wg genkey | tee /etc/wireguard/server.key | wg pubkey > /etc/wireguard/server.pub

Read the public key (you will use it in client configs):

sudo cat /etc/wireguard/server.pub

Step 3: Create the WireGuard Interface (wg0)

Create /etc/wireguard/wg0.conf. In this example, the VPN network is 10.44.0.0/24 and the server is 10.44.0.1. Replace eth0 with your public interface name (check with ip a).

[Interface]
Address = 10.44.0.1/24
ListenPort = 51820
PrivateKey = (paste contents of /etc/wireguard/server.key)
SaveConfig = false

Now add firewall/NAT rules so VPN clients can reach internal networks (and optionally the internet). Add these lines under the interface section:

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

Start and enable the service:

sudo systemctl enable --now wg-quick@wg0

Verify:

sudo wg

Step 4: Add Per-User Keys and “Allow Only What’s Needed”

For Zero-Trust behavior, you should avoid giving every user full access to your entire internal network. WireGuard supports this with AllowedIPs per peer. Generate a key pair for a user (example: user “alice”):

umask 077
wg genkey | tee /etc/wireguard/alice.key | wg pubkey > /etc/wireguard/alice.pub

Decide what Alice is allowed to reach. Example: only a file server subnet 10.10.20.0/24 and the VPN IP for Alice (10.44.0.10/32). Add a peer block to /etc/wireguard/wg0.conf:

[Peer]
PublicKey = (paste contents of /etc/wireguard/alice.pub)
AllowedIPs = 10.44.0.10/32, 10.10.20.0/24
PersistentKeepalive = 25

Apply the changes by restarting WireGuard:

sudo systemctl restart wg-quick@wg0

This approach gives Alice an address on the VPN and only routes the required internal subnet through the tunnel. Everything else stays outside the VPN, reducing accidental exposure.

Step 5: Create a Secure Client Configuration

On the client side, create a config that uses Alice’s private key and the server’s public key. If your server public IP is 203.0.113.10 and the port is 51820, a minimal client config looks like this:

[Interface]
PrivateKey = (paste contents of /etc/wireguard/alice.key)
Address = 10.44.0.10/32
DNS = 10.44.0.1

[Peer]
PublicKey = (server public key)
Endpoint = 203.0.113.10:51820
AllowedIPs = 10.10.20.0/24
PersistentKeepalive = 25

Notice that the client’s AllowedIPs includes only the internal subnet she needs. That keeps her internet traffic off the VPN and limits risk if the client device is compromised.

Step 6: Add DNS Blocking (Optional but Recommended)

A simple way to reduce malicious domains is to run a lightweight DNS resolver with blocklists, such as Unbound plus a blocklist, or dnsmasq. A practical option on a small server is dnsmasq:

sudo apt install -y dnsmasq

Bind DNS to the WireGuard interface IP by editing /etc/dnsmasq.conf and adding:

listen-address=10.44.0.1
bind-interfaces

Then point clients to DNS = 10.44.0.1 (as shown earlier). For blocking, you can add entries to /etc/dnsmasq.d/blocked.conf like:

address=/example-bad-domain.com/0.0.0.0

Restart dnsmasq:

sudo systemctl restart dnsmasq

Step 7: Troubleshooting Checklist

If a client connects but cannot reach anything, check these items: (1) confirm the server is listening on UDP 51820 and the cloud firewall allows it; (2) verify AllowedIPs on both server and client match the intended access; (3) ensure IP forwarding is enabled; (4) confirm your PostUp NAT rule uses the correct public interface; and (5) run sudo wg and look for the latest handshake time and transfer counters.

With these steps, you get a modern WireGuard VPN that follows a Zero-Trust mindset: per-user identities, minimal network exposure, and optional DNS filtering for safer browsing on remote devices.

Popular Posts

Install Ollama and Open WebUI on Ubuntu 24.04 with NVIDIA GPU Acceleration (Step-by-Step)

Install a Local AI Chatbot on Ubuntu 24.04 with Ollama and Open WebUI (Step-by-Step)

Install Ollama + Open WebUI on Ubuntu 24.04 with NVIDIA GPU Acceleration (Step-by-Step)

Trending Now

Homogeneous Nucleation on Mars: A Textbook Process Finally Observed in Nature

By the end of this piece, you will understand what the Arsia Mons Elongated Cloud is, why it resisted explanation for several years after its first observation, and what the newly published model reveals about a physical process that has never been directly confirmed on any planet's atmosphere. The cloud that broke the model Every morning during Martian spring and summer, a thin, extremely long cloud forms near the Arsia Mons volcano and gradually elongates until it stretches to more than 1,000 miles before dissipating. The cycle then repeats for several months. The formation was first recorded by a probe in 2018, and from that point onward it became a persistent puzzle for atmospheric scientists working with Mars data. The cloud's geometry, its timing, and its seasonal recurrence all pointed to a real and reproducible physical process, yet no existing model could reproduce it. For a technical audience familiar with simulation work, the situation is analogous to a product...