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.

How to Set Up WireGuard VPN on Ubuntu Server 24.04 (Secure Remote Access in 15 Minutes)

Why WireGuard is a smart VPN choice in 2026

WireGuard is a modern VPN that focuses on speed, simplicity, and strong security. Compared to traditional VPN stacks, it uses fewer lines of code, performs well on low-cost VPS servers, and is easy to troubleshoot. This tutorial shows how to install and configure WireGuard on Ubuntu Server 24.04 so you can safely access your home or office network, manage servers remotely, and protect traffic on public Wi‑Fi.

What you need before starting

You will need: (1) an Ubuntu Server 24.04 machine with root or sudo access, (2) a public IP address or a router that can forward ports to the VPN server, and (3) a client device (Linux, Windows, macOS, Android, or iOS). If your server is behind NAT (common at home), you must forward a UDP port from your router to the server’s local IP.

Step 1: Update the server and install WireGuard

Start by updating packages and installing WireGuard and the helper tools. On Ubuntu 24.04, WireGuard is included in the standard repositories.

Run:

sudo apt update && sudo apt -y upgrade
sudo apt -y install wireguard

Step 2: Generate server keys (securely)

WireGuard uses public/private key pairs. Keep private keys secret and never paste them into tickets or chat. Create a dedicated directory and lock down permissions.

sudo -i
umask 077
mkdir -p /etc/wireguard
cd /etc/wireguard
wg genkey | tee server.key | wg pubkey > server.pub

You can view the public key with cat /etc/wireguard/server.pub. Avoid printing the private key unless absolutely necessary.

Step 3: Create the WireGuard server configuration

WireGuard’s default interface name is commonly wg0. Pick a private VPN subnet that does not conflict with your LAN. In this example, the VPN network is 10.10.10.0/24, and the server’s VPN IP is 10.10.10.1.

Create the config file:

nano /etc/wireguard/wg0.conf

Paste and adjust the following:

[Interface]
Address = 10.10.10.1/24
ListenPort = 51820
PrivateKey = YOUR_SERVER_PRIVATE_KEY

# Enable NAT so VPN clients can reach the internet (optional but common)
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

Replace YOUR_SERVER_PRIVATE_KEY with the content of /etc/wireguard/server.key. Also verify the server’s main network interface name. On many systems it is eth0, but it might be ens3, enp0s3, or similar. Check with ip a and update the PostUp/PostDown lines accordingly.

Step 4: Enable IP forwarding

If you want VPN clients to reach other networks (like the internet or your LAN), enable IP forwarding.

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

Step 5: Create a client profile and add it to the server

Now generate keys for one client (repeat for each device). This example creates a client named laptop1 with VPN IP 10.10.10.2.

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

Edit the server config and add a peer section at the bottom:

nano /etc/wireguard/wg0.conf

[Peer]
PublicKey = CLIENT_PUBLIC_KEY
AllowedIPs = 10.10.10.2/32

Replace CLIENT_PUBLIC_KEY with the content of laptop1.pub.

Step 6: Start WireGuard and enable it on boot

Bring up the VPN interface and ensure it starts automatically after reboots.

sudo systemctl enable --now wg-quick@wg0
sudo wg show

The wg show output is your first checkpoint. If the service fails, run sudo systemctl status wg-quick@wg0 to see exactly what went wrong (wrong interface name, missing key, or syntax issues are the usual suspects).

Step 7: Build the client configuration

Create a WireGuard client config file on your client device (or generate it on the server and copy it securely). You will need the server’s public key, the client’s private key, and your server’s public IP or DNS name.

Client config example:

[Interface]
Address = 10.10.10.2/32
PrivateKey = CLIENT_PRIVATE_KEY
DNS = 1.1.1.1

[Peer]
PublicKey = SERVER_PUBLIC_KEY
Endpoint = YOUR_SERVER_PUBLIC_IP:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25

If you only want access to your private networks (and not route all traffic through the VPN), change AllowedIPs to your LAN subnet, for example 192.168.1.0/24, and keep 10.10.10.0/24 as needed. The PersistentKeepalive value helps mobile clients stay connected behind NAT.

Troubleshooting tips that save time

If the VPN connects but you cannot reach anything, check these items in order: (1) confirm UDP port 51820 is open/forwarded to the server, (2) verify your PostUp interface name matches the real outbound interface, (3) confirm IP forwarding is enabled, and (4) make sure the client’s AllowedIPs matches the routing you expect. Also review your firewall rules. On Ubuntu, you may need to allow the UDP port: sudo ufw allow 51820/udp. Finally, re-check keys; one incorrect character in a key line will prevent a proper handshake.

Next steps (best practices)

Once your first client works, add additional peers one at a time and assign each a unique VPN IP. Use a DNS name for the server if your IP changes often. Keep your system updated and consider restricting management access (SSH) to VPN-only for stronger security. WireGuard is lightweight enough to run on a small VPS, making it a practical “always-on” remote access solution for admins and power users.

How to Deploy a Secure WireGuard VPN Server on Ubuntu 24.04 (With Client Setup)

Why WireGuard and Why Now?

WireGuard has become one of the most practical VPN technologies for modern networks because it is fast, lightweight, and easier to audit than older VPN stacks. For remote work, home labs, or small business admin access, a WireGuard server on Ubuntu 24.04 is a clean way to reach internal services without exposing them directly to the internet. This tutorial walks through a secure, real-world setup: server installation, firewall and forwarding, client configuration, and a few troubleshooting checks.

What You Need Before You Start

You will need an Ubuntu 24.04 server with root or sudo access, a public IPv4 address (or port-forwarding from your router), and a client device (Windows, macOS, Linux, Android, or iOS). Make sure you know your server’s public IP or DNS name. In this guide, we’ll use a private VPN subnet of 10.10.10.0/24 and the server will be 10.10.10.1.

Step 1: Install WireGuard on Ubuntu 24.04

Update packages and install WireGuard and basic firewall tooling:

Commands:
sudo apt update
sudo apt install -y wireguard ufw

Step 2: Generate Server Keys

WireGuard uses public key cryptography. Generate a private/public key pair for the server and protect the private key permissions:

Commands:
sudo umask 077
wg genkey | sudo tee /etc/wireguard/server.key | wg pubkey | sudo tee /etc/wireguard/server.pub

View the public key (you’ll share this with clients):

Command:
sudo cat /etc/wireguard/server.pub

Step 3: Create the WireGuard Interface Configuration

Create /etc/wireguard/wg0.conf. Replace YOUR_SERVER_PRIVATE_KEY with the contents of /etc/wireguard/server.key. If your server’s network interface is not eth0, replace it accordingly (common alternatives are ens3, enp1s0, etc.).

Command:
sudo nano /etc/wireguard/wg0.conf

Example wg0.conf:
[Interface]
Address = 10.10.10.1/24
ListenPort = 51820
PrivateKey = YOUR_SERVER_PRIVATE_KEY

PostUp = ufw route allow in on wg0 out on eth0; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = ufw route delete allow in on wg0 out on eth0; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

This configuration enables NAT so VPN clients can reach the internet or other networks through the server. If you only want access to internal resources and do not need internet tunneling, you can skip the NAT portion and route traffic differently, but NAT is the most common starter setup.

Step 4: Enable IP Forwarding

To route packets between the VPN interface and your main network interface, enable IPv4 forwarding:

Commands:
echo 'net.ipv4.ip_forward=1' | sudo tee /etc/sysctl.d/99-wireguard-forward.conf
sudo sysctl --system

Step 5: Configure the Firewall (UFW)

Allow the WireGuard UDP port and enable the firewall:

Commands:
sudo ufw allow 51820/udp
sudo ufw allow OpenSSH
sudo ufw enable
sudo ufw status

If SSH is not already allowed and you are connected remotely, ensure OpenSSH is permitted before enabling UFW to avoid locking yourself out.

Step 6: Start and Enable the WireGuard Service

Bring up the interface and configure it to start at boot:

Commands:
sudo systemctl enable --now wg-quick@wg0
sudo wg show

The wg show output is your first verification point. At this stage you will not see peers yet, which is normal.

Step 7: Create a Client (Peer) Configuration

On your client device (or on the server if you prefer and then copy files securely), generate client keys. On Linux, you can run:

Commands (client side):
umask 077
wg genkey | tee client1.key | wg pubkey | tee client1.pub

Now add the client as a peer on the server by editing /etc/wireguard/wg0.conf and appending a [Peer] block. Replace CLIENT1_PUBLIC_KEY with the contents of client1.pub:

Server wg0.conf (append):
[Peer]
PublicKey = CLIENT1_PUBLIC_KEY
AllowedIPs = 10.10.10.2/32

Restart WireGuard to apply changes:

Command:
sudo systemctl restart wg-quick@wg0

Step 8: Build the Client VPN Profile

Create a client configuration file (for example client1.conf) and import it into the WireGuard app (Windows/macOS) or WireGuard mobile app (Android/iOS). Replace placeholders with your real values:

Example client1.conf:
[Interface]
PrivateKey = CLIENT1_PRIVATE_KEY
Address = 10.10.10.2/32
DNS = 1.1.1.1

[Peer]
PublicKey = SERVER_PUBLIC_KEY
Endpoint = YOUR_SERVER_PUBLIC_IP_OR_DNS:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25

If you only want access to your internal network and not full tunneling, replace AllowedIPs = 0.0.0.0/0 with only the networks you want to reach (for example 192.168.1.0/24 and 10.10.10.0/24). Keeping AllowedIPs tight is a simple way to reduce risk and avoid routing surprises.

Step 9: Verify the Connection and Troubleshoot

After activating the tunnel on the client, run these checks on the server:

Commands:
sudo wg show
sudo ss -lunp | grep 51820

In wg show, look for a recent latest handshake time and increasing transfer counters. If the handshake never happens, confirm UDP port 51820 is reachable from the internet (cloud security group, router port-forwarding, ISP restrictions). If handshake works but you cannot browse, re-check NAT rules, IP forwarding, and the client’s AllowedIPs. Also confirm your main interface name is correct in the PostUp/PostDown rules.

Security Tips for a Cleaner VPN Deployment

Keep your server updated, use SSH keys instead of passwords, and consider installing Fail2ban for SSH hardening. For WireGuard itself, the strongest control is peer management: only add the peers you need, assign each peer a single /32 address, and remove peers immediately when a device is lost or a user no longer needs access. WireGuard is simple by design, so good operational habits make the biggest difference.

Once this is working, you can expand the setup by adding more peers, routing to additional internal subnets, or placing WireGuard behind a firewall appliance. But even as-is, this Ubuntu 24.04 WireGuard server provides a modern, reliable VPN foundation for secure remote access.

3.

Install and Use Tailscale on Linux for a Secure Mesh VPN (Zero-Config Remote Access)

Why Tailscale is a smart VPN choice in 2026

Remote work and mixed networks are now normal: laptops on coffee shop Wi‑Fi, servers in a data center, and a home lab behind ISP NAT. Traditional VPN setups can be slow to deploy and painful to maintain (port forwarding, firewall rules, IPsec complexity). Tailscale is a modern mesh VPN built on WireGuard that focuses on easy connectivity, strong encryption, and sensible access controls. In this tutorial you will install Tailscale on Linux, connect devices into a private network, and harden access using ACLs, MagicDNS, and subnet routing.

What you will build

By the end, you will have a working mesh VPN where your Linux machine can securely reach other devices using stable hostnames, even if both ends are behind NAT. You will also learn two advanced features that are extremely useful in real environments: subnet routes (to reach an entire LAN) and exit nodes (to route internet traffic securely through a trusted device).

Prerequisites

You need one Linux system (Ubuntu/Debian, Fedora, or similar), a Tailscale account (free tiers are available), and sudo/root access. If you plan to use subnet routing or exit nodes, you will need at least two devices in the same tailnet. This guide uses command-line steps so you can repeat them on servers without a desktop.

Step 1: Install Tailscale on Linux

On Ubuntu/Debian, the quickest method is to use Tailscale’s repository so updates arrive via your package manager. Run the following commands:

Ubuntu/Debian
curl -fsSL https://tailscale.com/install.sh | sh

On Fedora, you can use dnf:

Fedora
sudo dnf install -y tailscale
sudo systemctl enable --now tailscaled

Verify the daemon is running:

systemctl status tailscaled

Step 2: Authenticate and bring the interface up

Start Tailscale and authenticate the device into your tailnet. On a server without a browser, the command prints a login URL you can open from another device:

sudo tailscale up

After login, check your assigned Tailscale IP and status:

tailscale status
tailscale ip -4

At this point you should already be able to ping another enrolled device using its Tailscale IP. If ICMP is blocked by local firewall rules, test with SSH instead.

Step 3: Enable MagicDNS (easy hostnames)

One of the most practical improvements is MagicDNS, which lets you reach devices by name rather than memorizing IPs. Open the Tailscale admin console, go to DNS settings, and enable MagicDNS. Within a minute, you should be able to resolve peers using names like server1 or server1.your-tailnet.ts.net (the exact domain depends on your tailnet).

Test resolution from Linux:

getent hosts server1

Step 4: Create basic ACLs (least privilege access)

A common mistake is leaving a VPN “flat,” where any device can reach any other device. Tailscale supports ACLs to restrict traffic by user, group, device tags, protocol, and port. In the admin console, open ACLs and start from a minimal policy: allow your admins to access SSH (port 22) on servers, and deny everything else by default.

A simple example concept (you will adjust names to match your environment) is: admins can reach tagged servers on SSH, and developers can only reach specific services. After applying, confirm from a non-admin account that SSH is blocked and from an admin account that it works. This is a huge security win for helpdesk and IT operations.

Step 5 (Advanced): Advertise a subnet route to reach an entire LAN

Subnet routing is perfect when you want to access devices that cannot run Tailscale (printers, NAS, hypervisors, IoT, lab switches). Choose one Linux box inside the LAN to act as a router. Then advertise the network range. Example for a home lab subnet 192.168.10.0/24:

sudo tailscale up --advertise-routes=192.168.10.0/24

Approve the route in the admin console (it will show as “pending”). Once approved, other tailnet devices should be able to reach 192.168.10.x addresses through the router. If it fails, check Linux IP forwarding:

sudo sysctl -w net.ipv4.ip_forward=1

Also review firewall rules (ufw/firewalld/nftables). You are not “opening ports to the internet,” but you still need to allow forwarding inside the host.

Step 6 (Advanced): Configure an exit node for secure browsing

An exit node routes your internet traffic through a trusted device (for example, a VPS or a server at home). On the device that will serve as the exit node, run:

sudo tailscale up --advertise-exit-node

Approve it in the admin console. On a client device that should use the exit node:

sudo tailscale up --exit-node=<exit-node-name-or-ip> --exit-node-allow-lan-access

The optional --exit-node-allow-lan-access flag is useful when you want to keep access to your local network while sending internet traffic through the exit node.

Troubleshooting tips

If connectivity is inconsistent, first run tailscale ping <peer> to see whether a direct path is possible or if it is relayed. Relaying is still encrypted and safe, but it can be slower. If you cannot reach a peer by name, re-check MagicDNS, then test with the Tailscale IP. On servers, verify that local firewall policies are not blocking the required ports (especially when using subnet routing). Finally, confirm your ACL policy is not accidentally denying the service you are testing.

Conclusion

With Tailscale on Linux, you can build a secure mesh VPN in minutes and then layer on serious controls like ACLs, MagicDNS, subnet routing, and exit nodes. This approach scales cleanly from a single admin managing a home lab to a helpdesk team supporting remote endpoints, without the usual VPN headaches.

Configure Windows Server 2022 as a Secure WireGuard VPN Gateway (with NAT and Firewall Rules)

Why WireGuard on Windows Server?

WireGuard is a modern VPN protocol known for strong cryptography, fast performance, and a simple configuration model. While it is often associated with Linux, it also works well on Windows Server 2022—especially for small and mid-sized organizations that need secure remote access to internal resources without deploying a complex VPN appliance.

In this tutorial, you will set up Windows Server 2022 as a WireGuard VPN gateway, enable NAT so VPN clients can reach your internal LAN, and lock down access with Windows Firewall. The end result is a clean, maintainable remote access VPN you can scale as needed.

Prerequisites

Server requirements: Windows Server 2022 (Desktop Experience is easier for first-time setup), local admin privileges, and a static internal IP address. If you want clients to connect from the internet, you also need a public IP or port-forwarding on your edge router.

Network plan: Choose a dedicated VPN subnet that does not overlap your LAN. Example used below: VPN subnet 10.30.0.0/24, WireGuard server VPN IP 10.30.0.1, LAN subnet 192.168.10.0/24.

Step 1: Install WireGuard for Windows

Download and install WireGuard for Windows from the official site (wireguard.com). After installation, open the WireGuard application. On Windows Server, it’s best to run it interactively first to confirm the tunnel comes up correctly, and later decide whether you want it to run at startup.

In WireGuard, click Add Tunnel and choose Add empty tunnel. WireGuard will generate a key pair automatically. Keep the generated PrivateKey on the server confidential.

Step 2: Create the Server Tunnel Configuration

Paste a server configuration similar to the following. Replace placeholders with your own values. If you don’t know your public endpoint yet, you can still configure it now and update later.

Example server config (wg0):

[Interface]
Address = 10.30.0.1/24
ListenPort = 51820
PrivateKey = SERVER_PRIVATE_KEY

At this stage, do not add peers yet. Save the tunnel as something recognizable like WG-RemoteAccess.

Step 3: Enable IP Forwarding on Windows Server

To route traffic between the VPN interface and the LAN, Windows must forward IP packets. On Windows Server, this is typically controlled via registry settings.

Open PowerShell as Administrator and run:

reg add HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters /v IPEnableRouter /t REG_DWORD /d 1 /f

Reboot the server or restart the Routing service (a reboot is the simplest way to ensure it takes effect).

Step 4: Configure NAT (So VPN Clients Can Reach the LAN)

If your LAN routers do not have a route back to the VPN subnet, NAT is the quickest reliable approach: internal systems see the VPN traffic as coming from the server’s LAN IP, and replies return without adding static routes everywhere.

Open PowerShell as Administrator and identify the WireGuard adapter name:

Get-NetAdapter

Then configure NAT. This example NATs any VPN client traffic sourced from 10.30.0.0/24:

New-NetNat -Name "WG-NAT" -InternalIPInterfaceAddressPrefix 10.30.0.0/24

This is simple and effective for remote access. In larger environments, you may prefer proper routing instead of NAT, but NAT keeps the rollout fast and reduces dependencies.

Step 5: Open the WireGuard UDP Port in Windows Firewall

WireGuard uses UDP. If the server is internet-facing (or receiving port-forwarded traffic), allow inbound UDP on your chosen port (default 51820).

Run in an elevated PowerShell:

New-NetFirewallRule -DisplayName "WireGuard UDP 51820" -Direction Inbound -Protocol UDP -LocalPort 51820 -Action Allow

If your server has multiple network profiles, consider scoping the rule to the correct interface or remote IP ranges for extra security.

Step 6: Add a Client Peer (Laptop Example)

On the client device, install WireGuard and create a new tunnel. WireGuard will generate a public/private key pair for the client. You will copy the client’s PublicKey into the server config as a peer.

Server-side peer entry:

[Peer]
PublicKey = CLIENT_PUBLIC_KEY
AllowedIPs = 10.30.0.2/32

Now configure the client tunnel like this (replace values accordingly):

Client config:

[Interface]
Address = 10.30.0.2/24
PrivateKey = CLIENT_PRIVATE_KEY
DNS = 192.168.10.10

[Peer]
PublicKey = SERVER_PUBLIC_KEY
Endpoint = vpn.yourdomain.com:51820
AllowedIPs = 192.168.10.0/24, 10.30.0.0/24
PersistentKeepalive = 25

The AllowedIPs line determines what routes go through the tunnel. The example routes only your internal LAN and the VPN subnet, not all internet traffic. If you want a full-tunnel VPN, you would use 0.0.0.0/0 (and optionally ::/0 for IPv6), but that changes your security and bandwidth planning.

Step 7: Test Connectivity and Troubleshoot

Bring up the tunnel on the server and the client. On the client, confirm you have a 10.30.0.2 address and then test:

Ping 10.30.0.1 (WireGuard server VPN IP) and then ping 192.168.10.10 (an internal host). If the VPN connects but LAN access fails, verify NAT exists (Get-NetNat) and check that Windows Firewall on the target LAN host allows the traffic.

If the client can’t handshake at all, confirm UDP/51820 is reachable from the internet (router port-forwarding, upstream firewall rules, and correct endpoint DNS). Also ensure the server’s WireGuard tunnel is active and listening on the expected port.

Hardening Tips (Recommended)

For better security, limit inbound firewall rules to known remote IP ranges if possible, and keep peer definitions tight (use /32 for individual client addresses). Avoid reusing client IPs, and document which user/device owns each peer. Finally, keep Windows Server patched and consider running WireGuard on a dedicated VM if the server also hosts critical roles.

With these steps, you now have a lean WireGuard VPN gateway on Windows Server 2022 that supports secure remote access and can be expanded by adding more peers as your team grows.

Set Up WireGuard VPN on Ubuntu Server 24.04 with Split Tunneling and QR Codes

Why WireGuard in 2025?

WireGuard is a modern VPN that focuses on speed, clean configuration, and strong cryptography. Compared to older VPN stacks, it is lightweight and easier to audit, which is why it has become a default choice for many admins who need secure remote access without complex tooling. In this tutorial, you will install WireGuard on Ubuntu Server 24.04, create a client profile, enable split tunneling (route only private subnets through the VPN), and generate a QR code for quick setup on mobile devices.

What You Need

Before you start, prepare: (1) an Ubuntu Server 24.04 VPS or on-prem server with root or sudo access, (2) UDP port 51820 allowed on your firewall/security group, (3) a public IP address or a DNS name, and (4) one client device (Windows, macOS, Linux, Android, or iOS). The steps below assume your server has a network interface like eth0. If your interface is different (for example, ens3), adjust the commands accordingly.

Step 1: Install WireGuard Tools

Update your package index and install WireGuard plus a QR utility. The qrencode tool is optional, but it makes mobile onboarding dramatically faster.

Commands:

sudo apt update
sudo apt install -y wireguard qrencode

Step 2: Enable IP Forwarding (Required for Routing)

If you want VPN clients to reach your internal networks (or the internet through the server), IP forwarding must be enabled. For split tunneling to private subnets, forwarding is still required so the server can route traffic between the VPN interface and your LAN/WAN interface.

Commands:

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

Step 3: Generate Server Keys

WireGuard uses public/private key pairs. Keep private keys secret. We will store them in the WireGuard directory with strict permissions.

Commands:

sudo install -m 700 -d /etc/wireguard
cd /etc/wireguard
umask 077
wg genkey | sudo tee server.key | wg pubkey | sudo tee server.pub

Step 4: Create the Server Configuration (wg0.conf)

We will create a VPN subnet, for example 10.10.10.0/24. The server will use 10.10.10.1. For split tunneling, clients will only route specific private subnets through the tunnel, such as 192.168.1.0/24 and 10.0.0.0/8. If you also want full-tunnel later, you can expand the AllowedIPs on the client side.

Create /etc/wireguard/wg0.conf:

sudo nano /etc/wireguard/wg0.conf

Paste and adjust:

[Interface]
Address = 10.10.10.1/24
ListenPort = 51820
PrivateKey = (paste contents of /etc/wireguard/server.key)
# Replace eth0 with your public interface
PostUp = ufw route allow in on wg0 out on eth0; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = ufw route delete allow in on wg0 out on eth0; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

Step 5: Allow UDP 51820 in the Firewall

If you use UFW, allow WireGuard’s UDP port. If your hosting provider has an external firewall/security group, open the same port there as well.

Commands:

sudo ufw allow 51820/udp
sudo ufw enable
sudo ufw status

Step 6: Create a Client Profile (Keys + Peer Entry)

Now generate a client key pair, assign an IP like 10.10.10.2, and add the client as a peer in the server config. This example is for one client called laptop1. Repeat the pattern for more users (use a new key pair and a new IP each time).

Commands:

cd /etc/wireguard
umask 077
wg genkey | sudo tee laptop1.key | wg pubkey | sudo tee laptop1.pub

Edit the server config and append a peer block:

sudo nano /etc/wireguard/wg0.conf

Add at the end:

[Peer]
PublicKey = (paste contents of /etc/wireguard/laptop1.pub)
AllowedIPs = 10.10.10.2/32

Step 7: Start WireGuard and Enable It on Boot

Bring up the interface and make sure it persists after reboots. Then confirm WireGuard is listening.

Commands:

sudo systemctl enable --now wg-quick@wg0
sudo wg show
sudo ss -lunp | grep 51820

Step 8: Build the Client Configuration (Split Tunnel)

Create a local file on your admin machine, or generate it on the server and copy it securely. Replace YOUR_SERVER_PUBLIC_IP with your server’s public IP (or DNS name). For split tunneling, set AllowedIPs to only the networks you want routed through the VPN, plus the WireGuard subnet if you want client-to-client visibility.

Example client config (laptop1.conf):

[Interface]
PrivateKey = (paste contents of /etc/wireguard/laptop1.key)
Address = 10.10.10.2/32
DNS = 1.1.1.1

[Peer]
PublicKey = (paste contents of /etc/wireguard/server.pub)
Endpoint = YOUR_SERVER_PUBLIC_IP:51820
AllowedIPs = 10.10.10.0/24, 192.168.1.0/24, 10.0.0.0/8
PersistentKeepalive = 25

Step 9: Generate a QR Code for Mobile Clients

On Android and iOS, the official WireGuard app can import from a QR code. This avoids typos in keys and endpoints. Run qrencode against the client configuration file and scan it in the app.

Commands:

qrencode -t ansiutf8 < laptop1.conf

Troubleshooting Tips

If the tunnel connects but you cannot reach private subnets, check routing on the server and confirm that the destination network knows how to return traffic to 10.10.10.0/24 (either via the WireGuard server as a gateway or via NAT). If handshakes never appear in wg show, verify UDP 51820 is open, confirm your Endpoint is correct, and ensure your server’s clock is accurate (NTP issues can sometimes cause confusing behavior). Finally, if you run another firewall besides UFW, make sure it is not blocking forwarding between wg0 and your outbound interface.

Next Steps

Once your first client works, add more peers and give each one a unique VPN IP. For better security hygiene, keep peer access tight by limiting AllowedIPs to only the subnets each user needs. If you want to manage many devices, consider storing configs in a password manager and rotating keys on a schedule, especially for contractors or short-term users.

How to Deploy a Zero‑Trust WireGuard VPN with Tailscale on Ubuntu Server (2025 Guide)

Overview

This step-by-step guide shows how to deploy a zero-trust VPN using Tailscale (built on WireGuard) on Ubuntu Server. You will install the Tailscale client, log in with SSO, enable secure SSH, configure access control lists (ACLs), expose a private subnet, and optionally offer an exit node. The result is a modern, fast, and secure VPN with minimal maintenance and strong identity-based access controls—perfect for homelabs and production servers in 2025.

Why Tailscale (WireGuard) for Zero Trust

Tailscale uses the WireGuard protocol for speed and strong cryptography while removing the operational pain of traditional VPNs. Devices authenticate using your identity provider (Google, Microsoft, Okta, GitHub, and others) and connect peer-to-peer where possible. You gain per-device keys, automatic NAT traversal, policy-based access (ACLs), MagicDNS, and optional Tailscale SSH that replaces inbound firewall holes.

Prerequisites

You need an Ubuntu Server 22.04 or 24.04 host with sudo access. Ensure outbound HTTPS (TCP 443) and UDP 41641 are allowed. No inbound ports are strictly required. Have a browser handy to authenticate to your identity provider or prepare a reusable auth key from the Tailscale admin console for headless systems.

Install Tailscale on Ubuntu

Run these commands to add the official repository and install Tailscale. The snippet auto-detects your Ubuntu codename:

curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/$(. /etc/os-release; echo $VERSION_CODENAME).noarmor.gpg | sudo tee /usr/share/keyrings/tailscale-archive-keyring.gpg >/dev/null

curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/$(. /etc/os-release; echo $VERSION_CODENAME).tailscale-keyring.list | sudo tee /etc/apt/sources.list.d/tailscale.list

sudo apt-get update && sudo apt-get install -y tailscale

Authenticate and bring the node online

For interactive login, start Tailscale and enable Tailscale SSH. This avoids exposing port 22 to the internet and lets you restrict SSH via ACLs:

sudo tailscale up --ssh --operator=$USER --accept-dns=true --accept-routes=true --advertise-tags=tag:server

If the server is headless, generate an auth key in the Tailscale admin console (preferably tagged and reusable or ephemeral) and run:

sudo tailscale up --ssh --authkey=tskey-******** --advertise-tags=tag:server

Verify connectivity with tailscale status, view the device IPs via tailscale ip -4, and test pings to another node using tailscale ping <device-or-name>.

Enable zero-trust access controls (ACLs)

Open the Tailscale admin console and switch to the ACLs page. Keep policies simple and human-readable. Example: allow your admin group to SSH to servers and let developers access staging web ports:

{
  "groups": { "group:admins": ["[email protected]"], "group:devs": ["[email protected]"] },
  "tagOwners": { "tag:server": ["group:admins"] },
  "acls": [
    { "action": "accept", "users": ["group:admins"], "ports": ["tag:server:22,2222"] },
    { "action": "accept", "users": ["group:devs"], "ports": ["tag:server:80,443,8080"] }
  ],
  "ssh": [
    { "action": "check", "src": ["group:admins"], "dst": ["tag:server"], "users": ["root", "ubuntu"] }
  ]
}

This policy makes tag:server devices manageable by admins, grants controlled port access, and restricts Tailscale SSH to authorized identities. Commit and save to enforce instantly.

Expose your LAN with a Subnet Router (optional)

If the Ubuntu host can reach a private LAN (e.g., 192.168.10.0/24), you can advertise that subnet to Tailscale peers without opening your firewall. First, enable IP forwarding:

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

echo 'net.ipv6.conf.all.forwarding=1' | sudo tee -a /etc/sysctl.d/99-tailscale.conf

sudo sysctl --system

Now advertise the subnet routes:

sudo tailscale up --advertise-routes=192.168.10.0/24 --accept-routes=true

Approve the routes in the admin console. For UFW, permit forwarding within the LAN and from the Tailscale interface (typically tailscale0):

sudo ufw route allow in on tailscale0 out on eth0 to 192.168.10.0/24

sudo ufw reload

Set up an Exit Node (optional)

An exit node lets approved devices send all internet traffic through your Ubuntu server. This is useful for securing devices on public Wi‑Fi or egressing from a fixed IP. Enable it on the server:

sudo tailscale up --advertise-exit-node=true

In the admin console, allow the exit node and then, from a client, choose “Use exit node”. Optionally permit local LAN access while using the exit node by enabling “Allow LAN access” on the client.

Security hardening and best practices

Restrict who can reach what by tags and groups; avoid broad *:* policies. Prefer Tailscale SSH over public SSH. Disable password auth in OpenSSH (sudoedit /etc/ssh/sshd_config, set PasswordAuthentication no) and restart SSH. Keep the system current and enable unattended upgrades:

sudo apt-get install -y unattended-upgrades

sudo dpkg-reconfigure --priority=low unattended-upgrades

If you use UFW, you generally do not need to open inbound ports for Tailscale. Traffic arrives over the encrypted tunnel and is handled by tailscaled. For large fleets, use ephemeral auth keys for CI/CD runners (--ephemeral) and shorter key lifetimes. Consider using device posture checks and auto-approvers in ACLs where appropriate.

Troubleshooting quick checks

Run sudo tailscale bugreport to gather diagnostics if needed. Use tailscale netcheck to verify NAT traversal, tailscale status to view peers, and tailscale ping to test reachability. If subnets are not reachable, confirm routes are approved and that IP forwarding and UFW rules allow routed traffic. If speeds seem low, ensure direct connections are established (not relayed) and verify that CPU scaling or virtualization offloads are not limiting WireGuard throughput on the server.

What you achieved

You installed a production-ready, zero-trust WireGuard VPN with Tailscale on Ubuntu, authenticated it with SSO, enabled Tailscale SSH, enforced fine-grained ACLs, and optionally provided subnet routing and exit-node functionality. This approach is simpler, faster, and safer than legacy site-to-site or username/password VPNs, and it scales from a single VPS to a multi-site enterprise network with minimal toil.

How to Build a Zero-Config Mesh VPN with Tailscale for Secure Remote Access

Overview

Tired of port forwarding, dynamic DNS, and brittle VPN configs? Tailscale gives you a zero-config mesh VPN built on WireGuard, letting your devices talk to each other securely from anywhere. In this step-by-step guide, you will install Tailscale on Linux, Windows, and macOS, enable MagicDNS, set up an exit node, publish LAN subnets, and lock everything down with access controls. By the end, you will have a private, encrypted network for your home lab or remote team that takes minutes to deploy and scales without hassle.

Prerequisites

You need a Tailscale account (Google, Microsoft, GitHub, or email sign-in), admin access to your devices, and a stable internet connection. For subnet routing and exit nodes, a Linux or always-on device is recommended. Enable multi-factor authentication in your identity provider for best security.

Step 1: Create Your Tailnet

Go to the Tailscale website and sign in to create your tailnet. This is your private network. Open the Admin Console and confirm your tailnet name. Under Settings, enable device approvals if you want manual approval before new devices join. This is useful for production and shared environments.

Step 2: Install Tailscale

Linux (Debian/Ubuntu)
Run:
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up
When prompted, sign in to link the device. If your distro uses a service, ensure tailscaled is running.

Linux (Fedora/RHEL derivatives)
Install and start:
sudo dnf install tailscale -y
sudo systemctl enable --now tailscaled
sudo tailscale up

Windows
Download the Windows client from Tailscale, install it, and sign in. The client will assign a 100.x Tailscale IP and show your hostname in the Admin Console.

macOS
Install the app from the Mac App Store or from Tailscale’s website. Sign in to connect the Mac to your tailnet.

iOS/Android
Install the mobile app and sign in. You can toggle the VPN on/off and optionally route all traffic through an exit node.

Step 3: Turn On MagicDNS (Human-Friendly Names)

In the Admin Console, open Settings → DNS and enable MagicDNS. This lets you reach devices by name, for example builder.tailnet-name.ts.net, instead of by 100.x IPs. Keep “Override local DNS” enabled on clients so name resolution just works across platforms.

Step 4: Enable Tailscale SSH (Passwordless, Keyless)

In Settings → Tailscale SSH, enable it for your tailnet. On servers, run:
sudo tailscale up --ssh
You can now SSH between devices using identity-based auth, e.g.:
ssh ubuntu@server-name
Access is controlled by the tailnet policy (ACLs) rather than managing per-host SSH keys.

Step 5: Use an Exit Node (Full-Tunnel Internet)

An exit node routes all internet traffic from a device through a trusted peer (great for coffee shops and travel). On the machine that will be the exit node, run:
sudo tailscale up --advertise-exit-node
In the Admin Console, approve the exit node. On the client, open the Tailscale app and choose “Use exit node” → select your device. Optionally enable “Allow LAN access” to still reach your local network while tunneling the internet.

Step 6: Publish Your LAN with a Subnet Router

A subnet router lets remote devices reach a private LAN (e.g., 192.168.1.0/24) through Tailscale. On a Linux host connected to that LAN, enable IP forwarding:
sudo sysctl -w net.ipv4.ip_forward=1
sudo sysctl -w net.ipv6.conf.all.forwarding=1
Persist these settings in /etc/sysctl.d/99-tailscale.conf. Then advertise routes:
sudo tailscale up --advertise-routes=192.168.1.0/24
In the Admin Console → Machines, approve the advertised routes. Clients can now access printers, NAS devices, and servers on that LAN using IP or hostnames (with your DNS). If needed, add --snat=false to preserve client IPs for upstream firewall logs.

Step 7: Lock It Down with ACLs and Tags

Open the Admin Console → Access Controls and edit the policy. Use groups and tags to define who can reach what. Example: allow helpdesk to RDP to Windows servers, and engineers to SSH into Linux hosts. A minimal snippet could look like:
{ "groups": { "group:helpdesk": ["[email protected]"] }, "tagOwners": { "tag:server": ["group:helpdesk", "group:eng"] }, "acls": [ { "action": "accept", "src": ["group:helpdesk"], "dst": ["tag:server:3389"] }, { "action": "accept", "src": ["group:eng"], "dst": ["tag:server:22"] } ] }
Apply tags on devices by running:
sudo tailscale up --advertise-tags=tag:server
Only tagged and authorized devices will accept those connections.

Step 8: Headless and Auto-Join with Auth Keys

For servers and containers, create a reusable or short-lived auth key in the Admin Console → Keys. On the device, run:
sudo tailscale up --authkey=tskey-abcdef --hostname=ci-runner-01 --advertise-tags=tag:server
Use ephemeral keys for throwaway CI agents, and rotate long-lived keys on a schedule. You can also inject TS_AUTHKEY as an environment variable in Docker or systemd units.

Step 9: Troubleshooting Essentials

If a device looks offline, first check the local service:
sudo systemctl status tailscaled (Linux). Then test reachability:
tailscale status
tailscale ping device-name
tailscale netcheck
Ensure outbound UDP 41641 is open; Tailscale falls back to relays (DERP) if direct NAT traversal fails. On Linux firewalls, allow UDP/41641 and established/related traffic. If routes are not working, confirm “Accept routes” is enabled and IP forwarding is on. For deep diagnostics, run tailscale bugreport and review logs in the Admin Console.

Security Best Practices

Require SSO and MFA for all users. Enable device approval and machine key expiry. Use groups and tags to enforce least privilege in ACLs. Restrict exit node usage to trusted admins. Regularly prune unused devices, rotate auth keys, and audit connections in the logs. Avoid exposing services publicly; instead, use MagicDNS, Tailscale SSH, or consider Tailscale Funnel selectively with HTTPS for public endpoints.

What You Can Do Next

With your mesh VPN live, map drives to a NAS over the tailnet, RDP into Windows servers from anywhere, tunnel VS Code SSH to a remote lab, or back up endpoints securely to a central repository. Tailscale scales from a weekend project to a production-ready fabric without the usual VPN pain. Most changes are policy-driven, so you can iterate quickly and keep operations clean.

Popular Posts

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

Install Ollama + 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)

Trending Now

Recovering from Btrfs Boot Failures Using GUI Tools on Fedora

By the end of this guide the reader will be able to identify a Btrfs‑based Fedora installation, boot from a live USB, list and restore snapshots using the graphical utilities btrfs‑assistant and snapper, and verify that the system returns to a functional state without resorting to the command line. Understanding the Btrfs Layout Used by Fedora Fedora Workstation and Fedora KDE install the root filesystem as a single Btrfs partition that contains two default sub‑volumes. One sub‑volume holds the traditional “/” hierarchy, while the second is dedicated to /var/lib/machines . The latter exists to keep container images out of snapshot operations; it remains empty on systems that do not run virtual machines. Because Btrfs stores data in sub‑volumes rather than separate partitions, a snapshot captures the state of an entire sub‑volume at a point in time. The installer (Anaconda) automatically registers these sub‑volumes with the snapper service. Snapper maintains a series of read‑only ...