Disclaimer and Warning

The information provided in this article is for educational and informational purposes only. It is offered without any warranty—express or implied—regarding its accuracy, reliability, or fitness for a particular purpose.

You are solely responsible for any changes you make to your system. Misconfiguring firewall rules, DNS settings, or system services may lead to loss of internet access, broken services, or other unintended consequences.

Before proceeding:

  • Back up your current configuration and any important data.
  • Test changes cautiously, preferably on a non-critical system.
  • Expect trial and error, especially if your system setup differs from the examples provided.

By using the instructions in this article, you agree that the author shall not be held liable for any damage, data loss, security breaches, or connectivity issues that may arise.

Proceed at your own risk.


In an era of mass surveillance and increasingly sophisticated tracking, using a VPN is no longer just for privacy advocates or hackers—it’s basic digital hygiene. But merely connecting to a VPN isn’t enough. A misconfigured system can still leak DNS requests or route sensitive traffic outside the encrypted tunnel. This guide will walk you through how to configure a leak-proof, DNS-hardened VPN setup on Ubuntu or Debian using UFW (Uncomplicated Firewall).

Objective

The aim is simple: force all internet traffic through the VPN and prevent even a single packet from escaping through your physical network interface when the VPN is disconnected. This requires:

  • A strict firewall configuration (UFW)
  • DNS leak prevention
  • Disabling system services that override your settings

Step 1: Reset the Firewall

Before anything else, clean the slate.

bashCopyEditsudo ufw reset
sudo ufw default deny incoming
sudo ufw default deny outgoing
sudo ufw default deny routed

This ensures nothing moves in or out of your machine unless explicitly allowed.


Step 2: Allow Only VPN Traffic

Start by allowing only essential traffic.

bashCopyEdit# Allow loopback interface for internal services
sudo ufw allow in
on lo
sudo ufw allow out on lo

# Allow outgoing traffic to VPN server (adjust port/protocol as needed)
sudo ufw allow out to any port 443 proto udp

# Allow traffic only on the VPN interface
sudo ufw allow in
on tun0
sudo ufw allow out on tun0

# Block outgoing traffic on your physical NIC (replace with your actual interface, e.g., enp2s0)
sudo ufw deny out on enp2s0

# Enable the firewall
sudo ufw enable

Once this is in place, the system won’t connect to the internet unless the VPN is active.


Step 3: Confirm VPN Routing

Make sure your VPN is up and that the tun0 interface exists.

bashCopyEditip a show tun0

Now check if you're routing traffic through the VPN:

bashCopyEditcurl ifconfig.me

This IP should match your VPN, not your ISP.


Step 4: Prevent DNS Leaks

Leaking DNS queries can expose your activity, even if your traffic is tunneled. Let’s plug that hole.

bashCopyEdit# Check current DNS resolver
resolvectl status

If you see a local IP (like 192.168.0.1), that's your router—and it shouldn't be there.

bashCopyEdit# Block local DNS entirely
sudo ufw deny out to 192.168.0.1 port 53

# Allow DNS only via VPN
sudo ufw allow out on tun0 to 1.1.1.1 port 53
sudo ufw allow out on tun0 to 1.0.0.1 port 53
sudo ufw allow out on tun0 to any port 53


Step 5: Override systemd-resolved

Even with UFW set, systemd-resolved can override your DNS and break the setup. Kill it completely.

bashCopyEdit# Stop and disable the DNS resolver
sudo systemctl disable
--now systemd-resolved

# Remove symlink and set your DNS manually
sudo rm
-f /etc/resolv.conf
echo -e "nameserver 1.1.1.1\nnameserver 1.0.0.1" | sudo tee /etc/resolv.conf

# Make it immutable
sudo chattr +i /etc/resolv.conf

# Restart network services
sudo systemctl restart NetworkManager

This locks DNS settings to Cloudflare and prevents changes by any automated service.


Step 6: Reboot and Test

Now reboot:

bashCopyEditsudo reboot

After rebooting, verify:

bashCopyEdit# Should show VPN IP
curl ifconfig.me

# Should use Cloudflare or VPN DNS
nslookup google.com

# Should not show router IP as DNS
resolvectl status


Conclusion

You now have a secure, airtight VPN setup:

  • All traffic routed through tun0 (VPN tunnel)
  • No fallback to your physical interface if the VPN drops
  • DNS queries go only to trusted servers
  • Even systemd can’t override your choices

In short: no leaks, no exceptions. Mission accomplished.


om tat sat