The following templates can be used to secure servers with nftables.
Note: The below firewall will not have any updates made. Additional nftables templates which are actively used/developed are available in the wiki. Additional firewall templates and information (using eBPF, XDP, iptables) is also available in the wiki here.
Basic Usage
To load the firewall rules:
# Check the syntax of /etc/nftables.conf nftables -f /etc/nftables.conf -c # Apply the firewall rules if no errors nftables -f /etc/nftables.conf
Counters are used for traffic that is dropped; to get the counter statistics:
# Get all counters nft list counters # Show specific counter nft list counter inet filter input_icmpv4_ping
To list all rules:
# List all rules for all tables # This will also list any counters and IP's in sets nft list ruleset
Sets
These firewalls make use of sets to restrict groups of IP’s from services/all traffic.
The input_timeout_ipv4
and input_timeout_ipv6
sets are used to restrict all inbound IPv4 or IPv6 traffic from IP’s or networks. IP’s/networks added to these sets will timeout after 24 hours (by default). To add entries the add element command can be used:
# Block all inbound IPv4 traffic from these IP's/networks: # 192.0.2.1, 192.0.2.250 and 192.0.2.240/29 nft add element inet filter input_timeout_ipv4 '{ 192.0.2.1, 192.0.2.250 }' # Block all inbound IPv6 traffic from these IP's networks: # 2001:0db8::4, 2001:0db8:ffff::/48 nft add element inet filter input_timeout_ipv6 '{ 2001:0db8::4, 2001:0db8:ffff::/48 }'
Templates
Multiple templates are available below for different restrictions.
Relaxed Template
This template will permit HTTP, HTTPS and SSH traffic inbound (for both IPv4 and IPv6) from anywhere. Unmatched inbound traffic will be dropped. There are no outbound rules configured; all outbound traffic is permitted.
#!/usr/sbin/nft -f flush ruleset table inet filter { # IPv4 IP's listed in this set will have all inbound IPv4 traffic dropped for 24 hours # To add IP's to the set: # nft add element inet filter input_timeout_ipv4 '{ 192.0.2.1, 192.0.2.250 }' set input_timeout_ipv4 { type ipv4_addr flags timeout, interval timeout 1d } # IPv6 IP's listed in this set will have all inbound IPv6 traffic dropped for 24 hours # To add IP's to the set: # nft add element inet filter input_timeout_ipv6 '{ 2001:0db8::4 }' set input_timeout_ipv6 { type ipv6_addr flags timeout, interval timeout 1d } # Create the counters for below rules counter input_timeout_ipv4 {} counter input_timeout_ipv6 {} counter input_tcp_no_syn {} counter input_tcp_scan_1 {} counter input_tcp_scan_2 {} counter input_tcp_scan_3 {} counter input_tcp_scan_4 {} counter input_invalid_state {} counter input_icmpv6_required {} counter input_icmpv6_ping {} counter input_icmpv6_dropped {} counter input_icmpv4_required {} counter input_icmpv4_ping {} counter input_icmpv4_dropped {} counter input_traceroute {} counter input_policy {} chain forward { type filter hook forward priority 0; policy drop } chain input { type filter hook input priority 0; policy drop # Drop traffic early ip saddr @input_timeout_ipv4 counter name input_timeout_ipv4 drop comment "Early drop IPv4 traffic from the prefixes listed in input_timeout_ipv4" ip6 saddr @input_timeout_ipv6 counter name input_timeout_ipv6 drop comment "Early drop IPv6 traffic from the prefixes listed in input_timeout_ipv6" # Permit all established connections ct state established,related accept comment "Permit established/related connections" # Permit all loopback iif lo accept comment "Permit all traffic via loopback interface" # Drop TCP traffic with invalid flags tcp flags != syn ct state new log prefix "New TCP without SYN: " counter name input_tcp_no_syn drop comment "Drop new connections that do not have the SYN TCP flag set" tcp flags & (fin|syn) == (fin|syn) log prefix "Port scan 1: " counter name input_tcp_scan_1 drop comment "Drop common port scan traffic" tcp flags & (syn|rst) == (syn|rst) log prefix "Port scan 2: " counter name input_tcp_scan_2 drop comment "Drop common port scan traffic" tcp flags & (fin|syn|rst|psh|ack|urg) < (fin) log prefix "Port scan 3:" counter name input_tcp_scan_3 drop comment "Drop common port scan traffic" tcp flags & (fin|syn|rst|psh|ack|urg) == (fin|psh|urg) log prefix "Port scan 4:" name input_tcp_scan_4 counter drop comment "Drop common port scan traffic" # Drop invalid connection state traffic ct state invalid log flags all prefix "Invalid conntrack state: " counter name input_invalid_state drop comment "Drop traffic with invalid connection state" # Allow SSH, HTTP, HTTPS tcp dport { ssh, http, https } ct state new accept comment "Permit inbound TCP traffic to services hosted on this server" # Permit and rate limit required ICMPv6 types ip6 nexthdr icmpv6 icmpv6 type { destination-unreachable, ind-neighbor-advert, ind-neighbor-solicit, mld-listener-query, mld-listener-reduction, mld-listener-report, mld2-listener-report, nd-neighbor-advert, nd-neighbor-solicit, nd-router-advert, nd-router-solicit, packet-too-big, parameter-problem, time-exceeded } counter name input_icmpv6_required accept comment "Permit required ICMPv6 types without rate limit" ip6 nexthdr icmpv6 icmpv6 type { echo-reply, echo-request } limit rate 250/second counter name input_icmpv6_ping accept comment "Rate limit IPv4 echo (ping)" ip6 nexthdr icmpv6 log flags all prefix "Prohibited ICMPv6: " counter name input_icmpv6_dropped drop comment "Log and drop all other ICMPv6 types" # Permit and rate limit required ICMPv4 types ip protocol icmp icmp type { destination-unreachable, source-quench, time-exceeded, parameter-problem } counter name input_icmpv6_required accept comment "Permit required ICMPv4 types without rate limit" ip protocol icmp icmp type { echo-reply, echo-request } limit rate 250/second counter name input_icmpv4_ping accept comment "Rate limit IPv4 echo (ping)" ip protocol icmp log flags all prefix "Prohibited ICMPv4: " counter name input_icmpv4_dropped drop comment "Log and drop all other ICMPv4 types" # Permit and rate limit traceroute udp dport 33434-33524 limit rate 50/second counter name input_traceroute accept comment "Rate limit traceroute" # Drop unmatched traffic counter name input_policy log prefix "Default policy: " } chain output { type filter hook output priority 0; policy accept } }
Strict Template
This template will allow inbound HTTP, HTTPS and SSH – similar to the above relaxed template. How ever, this template will also restrict outbound traffic.
Outbound traffic will be limited to any HTTP/HTTPS destinations, any NTP destinations and DNS traffic to the Cloudflare and Google public resolvers.
#!/usr/sbin/nft -f flush ruleset table inet filter { # Set default policy for forward traffic to drop chain forward { type filter hook forward priority 0; policy drop } # Create the counters for input rules counter input_timeout_ipv4 {} counter input_timeout_ipv6 {} counter input_tcp_no_syn {} counter input_tcp_scan_1 {} counter input_tcp_scan_2 {} counter input_tcp_scan_3 {} counter input_tcp_scan_4 {} counter input_invalid_state {} counter input_icmpv6_required {} counter input_icmpv6_ping {} counter input_icmpv6_dropped {} counter input_icmpv4_required {} counter input_icmpv4_ping {} counter input_icmpv4_dropped {} counter input_traceroute {} counter input_policy_default {} # IPv4 IP's listed in this set will have all inbound IPv4 traffic dropped for 24 hours # To add IP's to the set: # nft add element inet filter input_timeout_ipv4 '{ 192.0.2.1, 192.0.2.250 }' set input_timeout_ipv4 { type ipv4_addr flags timeout, interval timeout 1d } # IPv6 IP's listed in this set will have all inbound IPv6 traffic dropped for 24 hours # To add IP's to the set: # nft add element inet filter input_timeout_ipv6 '{ 2001:0DB8::4 }' set input_timeout_ipv6 { type ipv6_addr flags timeout, interval timeout 1d } # Add input (inbound) rules chain input { type filter hook input priority 0; policy drop # Drop traffic early ip saddr @input_timeout_ipv4 counter name input_timeout_ipv4 drop comment "Early drop IPv4 traffic from the prefixes listed in input_timeout_ipv4" ip6 saddr @input_timeout_ipv6 counter name input_timeout_ipv6 drop comment "Early drop IPv6 traffic from the prefixes listed in input_timeout_ipv6" # Permit all established connections ct state established,related accept comment "Permit established/related connections" # Permit all loopback iif lo accept comment "Permit all traffic via loopback interface" # Drop TCP traffic with invalid flags tcp flags != syn ct state new log prefix "IN - New !SYN: " counter name input_tcp_no_syn drop comment "Drop new connections that do not have the SYN TCP flag set" tcp flags & (fin|syn) == (fin|syn) log prefix "IN - Scan 1: " counter name input_tcp_scan_1 drop comment "Drop common port scan traffic" tcp flags & (syn|rst) == (syn|rst) log prefix "IN - Scan 2: " counter name input_tcp_scan_2 drop comment "Drop common port scan traffic" tcp flags & (fin|syn|rst|psh|ack|urg) < (fin) log prefix "IN - Scan 3:" counter name input_tcp_scan_3 drop comment "Drop common port scan traffic" tcp flags & (fin|syn|rst|psh|ack|urg) == (fin|psh|urg) log prefix "IN - Scan 4:" counter name input_tcp_scan_4 drop comment "Drop common port scan traffic" # Drop invalid connection state traffic ct state invalid log flags all prefix "IN - Invalid: " counter name input_invalid_state drop comment "Drop traffic with invalid connection state" # Allow HTTP and HTTPS tcp dport { http, https } ct state new accept comment "Permit inbound HTTP and HTTPS" # Allow SSH tcp dport ssh ct state new accept comment "Permit inbound SSH" # Permit and rate limit required ICMPv6 types ip6 nexthdr icmpv6 icmpv6 type { destination-unreachable, ind-neighbor-advert, ind-neighbor-solicit, mld-listener-query, mld-listener-reduction, mld-listener-report, mld2-listener-report, nd-neighbor-advert, nd-neighbor-solicit, nd-router-advert, nd-router-solicit, packet-too-big, parameter-problem, time-exceeded } counter name input_icmpv6_required accept comment "Permit required ICMPv6 types without rate limit" ip6 nexthdr icmpv6 icmpv6 type { echo-reply, echo-request } limit rate 250/second counter name input_icmpv6_ping accept comment "Rate limit IPv4 echo (ping)" ip6 nexthdr icmpv6 log flags all prefix "IN - Prohibited ICMPv6: " counter name input_icmpv6_dropped drop comment "Log and drop all other ICMPv6 types" # Permit and rate limit required ICMPv4 types ip protocol icmp icmp type { destination-unreachable, source-quench, time-exceeded, parameter-problem } counter name input_icmpv6_required accept comment "Permit required ICMPv4 types without rate limit" ip protocol icmp icmp type { echo-reply, echo-request } limit rate 250/second counter name input_icmpv4_ping accept comment "Rate limit IPv4 echo (ping)" ip protocol icmp log flags all prefix "IN - Prohibited ICMPv4: " counter name input_icmpv4_dropped drop comment "Log and drop all other ICMPv4 types" # Permit and rate limit traceroute udp dport 33434-33524 limit rate 50/second counter name input_traceroute accept comment "Rate limit traceroute" # Log and count any unmatched traffic counter name input_policy_default log prefix "IN - Default: " } # Create the counters for output rules counter output_timeout_ipv4 {} counter output_timeout_ipv6 {} counter output_invalid_state {} counter output_icmpv6_required {} counter output_icmpv6_ping {} counter output_icmpv6_dropped {} counter output_icmpv4_required {} counter output_icmpv4_ping {} counter output_icmpv4_dropped {} counter output_traceroute {} counter output_policy_default {} # IPv4 IP's listed in this set will have all outbound IPv4 traffic dropped for 24 hours # To add IP's to the set: # nft add element inet filter output_timeout_ipv4 '{ 192.0.2.1, 192.0.2.250 }' set output_timeout_ipv4 { type ipv4_addr flags timeout, interval timeout 1d } # IPv6 IP's listed in this set will have all outbound IPv6 traffic dropped for 24 hours # To add IP's to the set: # nft add element inet filter output_timeout_ipv6 '{ 2001:0DB8::4 }' set output_timeout_ipv6 { type ipv6_addr flags timeout, interval timeout 1d } # List of IPv4 DNS servers that outbound queries are sent to set output_dns_ipv4 { type ipv4_addr elements = { 1.1.1.1, 1.0.0.1, 8.8.8.8, 8.8.4.4 } } # List of IPv4 DNS servers that outbound queries are sent to set output_dns_ipv6 { type ipv6_addr elements = { 2606:4700:4700::1111, 2606:4700:4700::1001, 2001:4860:4860::8888, 2001:4860:4860::8844 } } # Add output (outbound) rules chain output { type filter hook output priority 0; policy drop # Drop traffic early ip saddr @output_timeout_ipv4 counter name output_timeout_ipv4 drop comment "Early drop IPv4 traffic to the prefixes listed in output_timeout_ipv4" ip6 saddr @output_timeout_ipv6 counter name output_timeout_ipv6 drop comment "Early drop IPv6 traffic to the prefixes listed in output_timeout_ipv6" # Permit all established connections ct state established,related accept comment "Permit established/related connections" # Permit all loopback oif lo accept comment "Permit all traffic via loopback interface" # Drop invalid connection state traffic ct state invalid log flags all prefix "OUT - Invalid: " counter name output_invalid_state drop comment "Drop traffic with invalid connection state" # Allow HTTP and HTTPS tcp dport { http, https } ct state new accept comment "Permit outbound HTTP and HTTPS" # Allow IPv4 DNS queries to DNS servers ip daddr @output_dns_ipv4 udp dport domain accept comment "Permit outbound IPv4 UDP DNS" ip daddr @output_dns_ipv4 tcp dport domain accept comment "Permit outbound IPv4 TCP DNS" ip6 daddr @output_dns_ipv6 udp dport domain accept comment "Permit outbound IPv6 UDP DNS" ip6 daddr @output_dns_ipv6 tcp dport domain accept comment "Permit outbound IPv6 TCP DNS" # Allow outbound SMTP submission tcp dport 587 ct state new accept comment "Permit outbound SMTP submission traffic" # Allow outbound NTP udp dport ntp accept comment "Permit outbound NTP" # Permit and rate limit required ICMPv6 types ip6 nexthdr icmpv6 icmpv6 type { nd-neighbor-solicit, nd-neighbor-advert, nd-router-solicit, destination-unreachable, packet-too-big, time-exceeded, nd-router-advert, mld-listener-query, parameter-problem } counter name output_icmpv6_required accept comment "Permit required ICMPv6 types without rate limit" ip6 nexthdr icmpv6 icmpv6 type { echo-reply, echo-request } limit rate 250/second counter name output_icmpv6_ping accept comment "Rate limit IPv4 echo (ping)" ip6 nexthdr icmpv6 log flags all prefix "OUT - Prohibited ICMPv6: " counter name output_icmpv6_dropped drop comment "Log and drop all other ICMPv6 types" # Permit and rate limit required ICMPv4 types ip protocol icmp icmp type { destination-unreachable, source-quench, time-exceeded, parameter-problem } counter name output_icmpv6_required accept comment "Permit required ICMPv4 types without rate limit" ip protocol icmp icmp type { echo-reply, echo-request } limit rate 250/second counter name output_icmpv4_ping accept comment "Rate limit IPv4 echo (ping)" ip protocol icmp log flags all prefix "OUT - Prohibited ICMPv4: " counter name output_icmpv4_dropped drop comment "Log and drop all other ICMPv4 types" # Permit and rate limit traceroute udp dport 33434-33524 limit rate 50/second counter name output_traceroute accept comment "Rate limit traceroute" # Log and count any unmatched traffic counter name output_policy_default log prefix "OUT - Default: " } }