nftables can be a powerful firewall for VPNs, but its flexibility can also lead to complex configurations.
Here’s a setup that allows WireGuard and OpenVPN traffic while protecting your system:
table ip filter {
chain input {
type filter hook input priority 0; policy drop;
# Allow established and related connections
ct state established,related accept
# Allow loopback traffic
iifname "lo" accept
# Allow ICMP
ip protocol icmp accept
# Allow SSH
tcp dport 22 accept
# Allow WireGuard (UDP port 51820)
udp dport 51820 accept
# Allow OpenVPN (UDP port 1194)
udp dport 1194 accept
# Drop invalid packets
ct state invalid drop
# Log and drop everything else
log prefix "nftables-dropped: " counter drop
}
chain output {
type filter hook output priority 0; policy accept;
}
chain forward {
type filter hook forward priority 0; policy drop;
}
}
This nftables configuration creates a basic IP filtering table. The input chain controls traffic coming into the server. The policy drop at the beginning means anything not explicitly allowed will be dropped.
Let’s break down what’s being allowed:
ct state established,related accept: This is crucial for any stateful firewall. It allows return traffic for connections that were initiated by the server or are related to existing connections. Without this, your VPN clients wouldn’t be able to send data back to you.iifname "lo" accept: Allows all traffic on the loopback interface (lo), which is essential for local processes to communicate.ip protocol icmp accept: Allows ICMP (Internet Control Message Protocol) packets, commonly used forpingand other network diagnostics.tcp dport 22 accept: Opens the port for SSH (Secure Shell) access, allowing you to manage the server remotely.udp dport 51820 accept: This is the default port for WireGuard. By allowing UDP traffic to this port, you enable WireGuard to establish its tunnels.udp dport 1194 accept: This is the default port for OpenVPN. Allowing UDP traffic here permits OpenVPN connections. You might need to adjust this if you use TCP for OpenVPN or a different port.ct state invalid drop: Drops any packets that are malformed or don’t belong to a recognized connection state, preventing certain types of attacks.log prefix "nftables-dropped: " counter drop: This is a good practice for debugging. It logs any packets that reach this point (meaning they weren’t explicitly accepted) to your system logs with a specific prefix, and counts them. This helps you identify what’s being blocked unexpectedly.
The output chain’s policy accept means that by default, traffic originating from your server can go anywhere. The forward chain’s policy drop is important if your server is acting as a router for VPN clients; it prevents unsolicited traffic from being forwarded between interfaces.
To apply these rules, you’d typically save them to a file (e.g., /etc/nftables.conf) and then load them with sudo nft -f /etc/nftables.conf.
Now, what if you want to restrict VPN clients to only access specific internal resources, or prevent them from accessing the internet through the server? That’s where more advanced nftables rules come in, often involving routing and NAT.
The next concept you’ll likely encounter is setting up Network Address Translation (NAT) for your VPN clients to access the internet, which involves the nat family of tables and prerouting and postrouting chains.