#!/usr/sbin/nft -f # WireGuard VPN Firewall Rules # Purpose: Isolate admin services behind VPN, allow public access only to ports 80, 443, 22 # Generated by Ansible - DO NOT EDIT MANUALLY table inet wireguard_firewall { # Define sets for easy management set vpn_network { type ipv4_addr flags interval elements = { {{ wg_network }} } } set admin_service_ports { type inet_service elements = { 8080, # Traefik Dashboard 9090, # Prometheus 3001, # Grafana 9000, # Portainer 8001, # Redis Insight {% for port in additional_admin_ports | default([]) %} {{ port }}, # {{ port }} {% endfor %} } } set public_service_ports { type inet_service elements = { 80, # HTTP 443, # HTTPS 22, # SSH {% for port in additional_public_ports | default([]) %} {{ port }}, # {{ port }} {% endfor %} } } # Input chain - Handle incoming traffic chain input { type filter hook input priority filter; policy drop; # Allow established/related connections ct state established,related accept # Allow loopback iifname "lo" accept # Allow ICMP (ping) ip protocol icmp accept ip6 nexthdr icmpv6 accept # Allow SSH (public) tcp dport 22 accept # Allow WireGuard port (public) udp dport {{ wg_port | default(51820) }} accept comment "WireGuard VPN" # Allow public web services (HTTP/HTTPS) tcp dport @public_service_ports accept comment "Public services" # Allow VPN network to access admin services ip saddr @vpn_network tcp dport @admin_service_ports accept comment "VPN admin access" # Block public access to admin services tcp dport @admin_service_ports counter log prefix "BLOCKED_ADMIN_SERVICE: " drop # Log and drop all other traffic counter log prefix "BLOCKED_INPUT: " drop } # Forward chain - Handle routed traffic (VPN to services) chain forward { type filter hook forward priority filter; policy drop; # Allow established/related connections ct state established,related accept # Allow VPN clients to access local services iifname "wg0" ip saddr @vpn_network accept comment "VPN to services" # Allow return traffic to VPN clients oifname "wg0" ip daddr @vpn_network ct state established,related accept # Log and drop all other forwarded traffic counter log prefix "BLOCKED_FORWARD: " drop } # Output chain - Allow all outgoing traffic chain output { type filter hook output priority filter; policy accept; } # NAT chain - Masquerade VPN traffic to WAN chain postrouting { type nat hook postrouting priority srcnat; # Masquerade VPN traffic going to WAN oifname "{{ wan_interface }}" ip saddr @vpn_network masquerade comment "VPN NAT" } } # Optional: Rate limiting for VPN port (DDoS protection) {% if wg_enable_rate_limit | default(true) %} table inet wireguard_ratelimit { chain input { type filter hook input priority -10; # Rate limit WireGuard port: 10 connections per second per IP udp dport {{ wg_port | default(51820) }} \ meter vpn_ratelimit { ip saddr limit rate over 10/second } \ counter log prefix "VPN_RATELIMIT: " drop } } {% endif %}