<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Security on Hamzah Khan — DevOps Engineer &amp; Tech Blog</title><link>https://www.hamzahkhan.com/tags/security/</link><description>Recent content in Security on Hamzah Khan — DevOps Engineer &amp; Tech Blog</description><generator>Hugo</generator><language>en</language><lastBuildDate>Wed, 02 Sep 2026 01:00:00 +0100</lastBuildDate><atom:link href="https://www.hamzahkhan.com/tags/security/index.xml" rel="self" type="application/rss+xml"/><item><title>VyOS Firewall Rules: A Real Zone-Based Config, Explained</title><link>https://www.hamzahkhan.com/vyos-firewall-rules/</link><pubDate>Wed, 02 Sep 2026 01:00:00 +0100</pubDate><guid>https://www.hamzahkhan.com/vyos-firewall-rules/</guid><description>&lt;p&gt;I&amp;rsquo;ve written before about specific things VyOS can do, including &lt;a href="https://www.hamzahkhan.com/vyos-ospf-wireguard" title="Site-to-Site VPN using Wireguard and OSPF on VyOS" &gt;site-to-site WireGuard over OSPF&lt;/a&gt;, &lt;a href="https://www.hamzahkhan.com/vyos-road-warrior-vpn" title="VyOS WireGuard VPN Server Setup" &gt;a road-warrior VPN&lt;/a&gt;, and &lt;a href="https://www.hamzahkhan.com/captive-dns-with-vyos" title="How to Redirect Hardcoded DNS with VyOS" &gt;redirecting captive DNS&lt;/a&gt;. I&amp;rsquo;ve never actually shown the VyOS firewall rules that sit in front of all of it. That&amp;rsquo;s the part that actually decides what gets in and what doesn&amp;rsquo;t, so it&amp;rsquo;s overdue.&lt;/p&gt;
&lt;p&gt;What follows is the firewall configuration pattern I run across my gateways. It is pulled directly from the routers, then generalised where something was specific to my network and wouldn&amp;rsquo;t mean anything to you. I&amp;rsquo;m also flagging a real syntax change in VyOS&amp;rsquo;s zone-based firewall that isn&amp;rsquo;t reflected in the current documentation as of writing, which I only found because one of my routers is on a newer release than the rest.&lt;/p&gt;</description><content:encoded>&lt;p&gt;I&amp;rsquo;ve written before about specific things VyOS can do, including &lt;a href="https://www.hamzahkhan.com/vyos-ospf-wireguard" title="Site-to-Site VPN using Wireguard and OSPF on VyOS" &gt;site-to-site WireGuard over OSPF&lt;/a&gt;, &lt;a href="https://www.hamzahkhan.com/vyos-road-warrior-vpn" title="VyOS WireGuard VPN Server Setup" &gt;a road-warrior VPN&lt;/a&gt;, and &lt;a href="https://www.hamzahkhan.com/captive-dns-with-vyos" title="How to Redirect Hardcoded DNS with VyOS" &gt;redirecting captive DNS&lt;/a&gt;. I&amp;rsquo;ve never actually shown the VyOS firewall rules that sit in front of all of it. That&amp;rsquo;s the part that actually decides what gets in and what doesn&amp;rsquo;t, so it&amp;rsquo;s overdue.&lt;/p&gt;
&lt;p&gt;What follows is the firewall configuration pattern I run across my gateways. It is pulled directly from the routers, then generalised where something was specific to my network and wouldn&amp;rsquo;t mean anything to you. I&amp;rsquo;m also flagging a real syntax change in VyOS&amp;rsquo;s zone-based firewall that isn&amp;rsquo;t reflected in the current documentation as of writing, which I only found because one of my routers is on a newer release than the rest.&lt;/p&gt;
&lt;h2 id="the-version-gap-that-started-this"&gt;
The version gap that started this
&lt;a class="heading-link" href="#the-version-gap-that-started-this"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;Most of my gateways run VyOS 1.4 (Sagitta), which is showing its age now that 1.5 (Circinus) is the LTS release. One router, though, is on a 2026.03 rolling build. When I went to compare firewall configs across the fleet to write this post, the zone configuration on the rolling-release box didn&amp;rsquo;t match what I had everywhere else, and it didn&amp;rsquo;t match the current docs either. More on that below, as it&amp;rsquo;s worth knowing about before you copy any of this.&lt;/p&gt;
&lt;h2 id="global-hardening-options"&gt;
Global hardening options
&lt;a class="heading-link" href="#global-hardening-options"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;Every router starts with the same baseline network hardening, independent of anything zone- or rule-specific:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall global-options all-ping &lt;span class="s1"&gt;&amp;#39;enable&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall global-options broadcast-ping &lt;span class="s1"&gt;&amp;#39;disable&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall global-options ip-src-route &lt;span class="s1"&gt;&amp;#39;disable&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall global-options ipv6-receive-redirects &lt;span class="s1"&gt;&amp;#39;disable&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall global-options ipv6-src-route &lt;span class="s1"&gt;&amp;#39;disable&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall global-options log-martians &lt;span class="s1"&gt;&amp;#39;enable&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall global-options receive-redirects &lt;span class="s1"&gt;&amp;#39;disable&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall global-options send-redirects &lt;span class="s1"&gt;&amp;#39;disable&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall global-options source-validation &lt;span class="s1"&gt;&amp;#39;disable&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall global-options syn-cookies &lt;span class="s1"&gt;&amp;#39;enable&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall global-options twa-hazards-protection &lt;span class="s1"&gt;&amp;#39;enable&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The two worth calling out: &lt;code&gt;syn-cookies&lt;/code&gt; gives you basic SYN-flood resistance for free, and &lt;code&gt;log-martians&lt;/code&gt; logs packets with impossible source/destination addresses, which is usually the first sign something&amp;rsquo;s misconfigured (or someone&amp;rsquo;s spoofing) rather than something malicious in itself.&lt;/p&gt;
&lt;h2 id="groups-dont-repeat-yourself-in-rules"&gt;
Groups: don&amp;rsquo;t repeat yourself in rules
&lt;a class="heading-link" href="#groups-dont-repeat-yourself-in-rules"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;Before the rules, the groups they reference. VyOS firewall groups let you define a set of addresses, networks, or interfaces once and reuse them across rules, so a change in one place propagates everywhere:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall group network-group internal-subnets network &lt;span class="s1"&gt;&amp;#39;10.254.88.0/21&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall group network-group internal-subnets network &lt;span class="s1"&gt;&amp;#39;10.254.112.0/21&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall group address-group dns-servers address &lt;span class="s1"&gt;&amp;#39;10.254.95.3&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall group address-group dns-servers address &lt;span class="s1"&gt;&amp;#39;10.254.95.4&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall group interface-group IG_VPN interface &lt;span class="s1"&gt;&amp;#39;wg0&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall group interface-group IG_VPN interface &lt;span class="s1"&gt;&amp;#39;wg1&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I also keep an empty &lt;code&gt;network-group&lt;/code&gt; reserved for a threat blocklist, populated by a scheduled job that pulls a public IP-reputation feed and rewrites the group&amp;rsquo;s members:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall group network-group threats-blocklist description &lt;span class="s1"&gt;&amp;#39;Threats Blocklist&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Referencing &lt;code&gt;threats-blocklist&lt;/code&gt; in a rule (see below) means the rule logic never has to change. Only the group&amp;rsquo;s contents do, on a schedule, outside the firewall config entirely.&lt;/p&gt;
&lt;h2 id="the-zone-model"&gt;
The zone model
&lt;a class="heading-link" href="#the-zone-model"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;Rather than writing input/output/forward rules per interface, I use VyOS&amp;rsquo;s zone-based firewall. Interfaces get assigned to a zone, and you write rules for zone-to-zone traffic rather than interface-to-interface. Mine breaks down as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;LOCAL&lt;/strong&gt;: the router itself (the &lt;code&gt;local-zone&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WAN&lt;/strong&gt;: the internet-facing interface&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;VPN&lt;/strong&gt;: WireGuard interfaces&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;INTERNAL&lt;/strong&gt;: the LAN side (everything behind the router on trusted internal segments)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="mermaid"&gt;flowchart LR
WAN((WAN)) &lt;--&gt; LOCAL((LOCAL))
VPN((VPN)) &lt;--&gt; LOCAL
WAN &lt;--&gt; VPN
INTERNAL((INTERNAL / LAN)) &lt;--&gt; LOCAL
INTERNAL &lt;--&gt; WAN
INTERNAL &lt;--&gt; VPN&lt;/pre&gt;
&lt;p&gt;Every zone pair that&amp;rsquo;s allowed to talk gets an explicit named ruleset, and every zone has a default-action of &lt;code&gt;drop&lt;/code&gt;. Nothing passes between zones unless a rule says so:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall zone LOCAL default-action &lt;span class="s1"&gt;&amp;#39;drop&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall zone LOCAL from WAN firewall name &lt;span class="s1"&gt;&amp;#39;WAN-LOCAL&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall zone LOCAL from VPN firewall name &lt;span class="s1"&gt;&amp;#39;VPN-LOCAL&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall zone LOCAL from INTERNAL firewall name &lt;span class="s1"&gt;&amp;#39;INTERNAL-LOCAL&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall zone LOCAL local-zone
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall zone WAN default-action &lt;span class="s1"&gt;&amp;#39;drop&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall zone WAN from LOCAL firewall name &lt;span class="s1"&gt;&amp;#39;LOCAL-WAN&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall zone WAN from VPN firewall name &lt;span class="s1"&gt;&amp;#39;VPN-WAN&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall zone WAN from INTERNAL firewall name &lt;span class="s1"&gt;&amp;#39;INTERNAL-WAN&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall zone WAN interface &lt;span class="s1"&gt;&amp;#39;eth0&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall zone VPN default-action &lt;span class="s1"&gt;&amp;#39;drop&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall zone VPN from LOCAL firewall name &lt;span class="s1"&gt;&amp;#39;LOCAL-VPN&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall zone VPN from WAN firewall name &lt;span class="s1"&gt;&amp;#39;WAN-VPN&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall zone VPN from INTERNAL firewall name &lt;span class="s1"&gt;&amp;#39;INTERNAL-VPN&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall zone VPN interface &lt;span class="s1"&gt;&amp;#39;wg0&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall zone VPN interface &lt;span class="s1"&gt;&amp;#39;wg1&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall zone INTERNAL default-action &lt;span class="s1"&gt;&amp;#39;drop&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall zone INTERNAL from LOCAL firewall name &lt;span class="s1"&gt;&amp;#39;LOCAL-INTERNAL&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall zone INTERNAL from WAN firewall name &lt;span class="s1"&gt;&amp;#39;WAN-INTERNAL&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall zone INTERNAL from VPN firewall name &lt;span class="s1"&gt;&amp;#39;VPN-INTERNAL&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall zone INTERNAL interface &lt;span class="s1"&gt;&amp;#39;eth1&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s four zones, so twelve possible directions of travel. However, only the ones you explicitly wire up with a &lt;code&gt;from&lt;/code&gt; clause are reachable at all; everything else hits each zone&amp;rsquo;s &lt;code&gt;default-action 'drop'&lt;/code&gt; with no rule to even evaluate.&lt;/p&gt;
&lt;p&gt;Most of these named rulesets (&lt;code&gt;LOCAL-WAN&lt;/code&gt;, &lt;code&gt;VPN-LOCAL&lt;/code&gt;, &lt;code&gt;LOCAL-VPN&lt;/code&gt;, &lt;code&gt;WAN-VPN&lt;/code&gt;, &lt;code&gt;LOCAL-INTERNAL&lt;/code&gt;, &lt;code&gt;INTERNAL-LOCAL&lt;/code&gt;, &lt;code&gt;INTERNAL-VPN&lt;/code&gt;, &lt;code&gt;VPN-INTERNAL&lt;/code&gt;, &lt;code&gt;INTERNAL-WAN&lt;/code&gt;) are intentionally boring. They default to &lt;code&gt;accept&lt;/code&gt; and only drop packets in an invalid connection-tracking state:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name LOCAL-WAN default-action &lt;span class="s1"&gt;&amp;#39;accept&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name LOCAL-WAN rule &lt;span class="m"&gt;10&lt;/span&gt; action &lt;span class="s1"&gt;&amp;#39;drop&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name LOCAL-WAN rule &lt;span class="m"&gt;10&lt;/span&gt; description &lt;span class="s1"&gt;&amp;#39;Drop Invalid State&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name LOCAL-WAN rule &lt;span class="m"&gt;10&lt;/span&gt; state &lt;span class="s1"&gt;&amp;#39;invalid&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Repeat that pattern for every zone pair where you trust the traffic direction but still want basic conntrack sanity. The two rulesets that actually do real work are &lt;code&gt;WAN-LOCAL&lt;/code&gt; (traffic from the internet to the router itself) and, if you segment your LAN into more and less trusted subnets, &lt;code&gt;WAN-INTERNAL&lt;/code&gt; (traffic from the internet trying to reach hosts behind the router). I&amp;rsquo;ll focus on &lt;code&gt;WAN-LOCAL&lt;/code&gt; below since it&amp;rsquo;s the one every VyOS router needs regardless of how you&amp;rsquo;ve split up your internal network.&lt;/p&gt;
&lt;h2 id="wan-local-the-ruleset-that-matters"&gt;
WAN-LOCAL: the ruleset that matters
&lt;a class="heading-link" href="#wan-local-the-ruleset-that-matters"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;This is default-drop with logging, and everything after that is an explicit allow:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL default-action &lt;span class="s1"&gt;&amp;#39;drop&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL default-log
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL description &lt;span class="s1"&gt;&amp;#39;Inbound from the Internet&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Allow ICMP (useful for diagnostics, low risk)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;10&lt;/span&gt; action &lt;span class="s1"&gt;&amp;#39;accept&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;10&lt;/span&gt; description &lt;span class="s1"&gt;&amp;#39;Allow Inbound ICMP&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;10&lt;/span&gt; protocol &lt;span class="s1"&gt;&amp;#39;icmp&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Established/related sessions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;15&lt;/span&gt; action &lt;span class="s1"&gt;&amp;#39;accept&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;15&lt;/span&gt; description &lt;span class="s1"&gt;&amp;#39;Allow Established Sessions&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;15&lt;/span&gt; protocol &lt;span class="s1"&gt;&amp;#39;all&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;15&lt;/span&gt; state &lt;span class="s1"&gt;&amp;#39;established&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;15&lt;/span&gt; state &lt;span class="s1"&gt;&amp;#39;related&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Invalid conntrack state (drop before it wastes any more rule evaluation)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;20&lt;/span&gt; action &lt;span class="s1"&gt;&amp;#39;drop&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;20&lt;/span&gt; description &lt;span class="s1"&gt;&amp;#39;Drop Invalid State&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;20&lt;/span&gt; protocol &lt;span class="s1"&gt;&amp;#39;all&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;20&lt;/span&gt; state &lt;span class="s1"&gt;&amp;#39;invalid&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Known-bad sources, from the scheduled blocklist group&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;30&lt;/span&gt; action &lt;span class="s1"&gt;&amp;#39;drop&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;30&lt;/span&gt; description &lt;span class="s1"&gt;&amp;#39;Drop Threats&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;30&lt;/span&gt; log
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;30&lt;/span&gt; &lt;span class="nb"&gt;source&lt;/span&gt; group network-group &lt;span class="s1"&gt;&amp;#39;threats-blocklist&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Noise that doesn&amp;#39;t deserve a place in the logs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;70&lt;/span&gt; action &lt;span class="s1"&gt;&amp;#39;drop&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;70&lt;/span&gt; description &lt;span class="s1"&gt;&amp;#39;Drop NetBIOS Name Service Packets&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;70&lt;/span&gt; destination port &lt;span class="s1"&gt;&amp;#39;137&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;70&lt;/span&gt; protocol &lt;span class="s1"&gt;&amp;#39;udp&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;75&lt;/span&gt; action &lt;span class="s1"&gt;&amp;#39;drop&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;75&lt;/span&gt; description &lt;span class="s1"&gt;&amp;#39;Drop NetBIOS Datagram Service Packets&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;75&lt;/span&gt; destination port &lt;span class="s1"&gt;&amp;#39;138&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;75&lt;/span&gt; protocol &lt;span class="s1"&gt;&amp;#39;udp&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;80&lt;/span&gt; action &lt;span class="s1"&gt;&amp;#39;drop&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;80&lt;/span&gt; description &lt;span class="s1"&gt;&amp;#39;Drop Telnet Noise&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;80&lt;/span&gt; destination port &lt;span class="s1"&gt;&amp;#39;23&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;80&lt;/span&gt; protocol &lt;span class="s1"&gt;&amp;#39;tcp&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# The actual allow-list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;1000&lt;/span&gt; action &lt;span class="s1"&gt;&amp;#39;accept&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;1000&lt;/span&gt; description &lt;span class="s1"&gt;&amp;#39;Allow SSH&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;1000&lt;/span&gt; destination port &lt;span class="s1"&gt;&amp;#39;22&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;1000&lt;/span&gt; protocol &lt;span class="s1"&gt;&amp;#39;tcp&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;1010&lt;/span&gt; action &lt;span class="s1"&gt;&amp;#39;accept&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;1010&lt;/span&gt; description &lt;span class="s1"&gt;&amp;#39;Allow HTTP&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;1010&lt;/span&gt; destination port &lt;span class="s1"&gt;&amp;#39;80&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;1010&lt;/span&gt; protocol &lt;span class="s1"&gt;&amp;#39;tcp&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;1011&lt;/span&gt; action &lt;span class="s1"&gt;&amp;#39;accept&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;1011&lt;/span&gt; description &lt;span class="s1"&gt;&amp;#39;Allow HTTPS&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;1011&lt;/span&gt; destination port &lt;span class="s1"&gt;&amp;#39;443&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;1011&lt;/span&gt; protocol &lt;span class="s1"&gt;&amp;#39;tcp&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;1012&lt;/span&gt; action &lt;span class="s1"&gt;&amp;#39;accept&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;1012&lt;/span&gt; description &lt;span class="s1"&gt;&amp;#39;Allow Mail Submission&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;1012&lt;/span&gt; destination port &lt;span class="s1"&gt;&amp;#39;587&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;1012&lt;/span&gt; protocol &lt;span class="s1"&gt;&amp;#39;tcp&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;1013&lt;/span&gt; action &lt;span class="s1"&gt;&amp;#39;accept&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;1013&lt;/span&gt; description &lt;span class="s1"&gt;&amp;#39;Allow Mail IMAP&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;1013&lt;/span&gt; destination port &lt;span class="s1"&gt;&amp;#39;143&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;1013&lt;/span&gt; protocol &lt;span class="s1"&gt;&amp;#39;tcp&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A few decisions worth explaining rather than just showing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Rule numbering leaves gaps deliberately.&lt;/strong&gt; 10, 15, 20, 30, 70, 75, 80, then a jump to 1000+ for the actual service allow-list. That gap exists so I can insert a new noise-drop or hardening rule later without renumbering everything downstream.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The noise drops (70/75/80) aren&amp;rsquo;t security controls.&lt;/strong&gt; NetBIOS and Telnet probes get dropped by the default-deny anyway. Giving them their own silent-drop rules just keeps &lt;code&gt;default-log&lt;/code&gt; from filling up with the same handful of scanner signatures every day.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WireGuard&amp;rsquo;s listening ports get their own accept rules&lt;/strong&gt;, same pattern as 1000+, just on UDP instead of TCP. I&amp;rsquo;ve left them out above since the exact ports are covered in my &lt;a href="https://www.hamzahkhan.com/vyos-road-warrior-vpn" title="VyOS WireGuard VPN Server Setup" &gt;road-warrior VPN post&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you&amp;rsquo;re running services behind more than one public IP on the same WAN interface, you can scope any of these rules to a specific destination address rather than &amp;ldquo;any address on this interface&amp;rdquo;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall ipv4 name WAN-LOCAL rule &lt;span class="m"&gt;1000&lt;/span&gt; destination address &lt;span class="s1"&gt;&amp;#39;203.0.113.10/32&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s the difference between &amp;ldquo;SSH is open on this router&amp;rdquo; and &amp;ldquo;SSH is open on this router, but only if you&amp;rsquo;re hitting this specific IP&amp;rdquo;. This is useful once you&amp;rsquo;ve got more than one service or more than one public IP to manage on the same box.&lt;/p&gt;
&lt;h2 id="the-syntax-change-the-docs-dont-mention-yet"&gt;
The syntax change the docs don&amp;rsquo;t mention yet
&lt;a class="heading-link" href="#the-syntax-change-the-docs-dont-mention-yet"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s the discrepancy that started this post. On my 1.4 (Sagitta) routers, zone membership is a flat command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall zone VPN interface &lt;span class="s1"&gt;&amp;#39;wg0&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;On the router running the 2026.03 rolling build, the exact same logical configuration renders as:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; firewall zone VPN member interface &lt;span class="s1"&gt;&amp;#39;wg0&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I checked this two ways: reading the raw config tree on the router, and running &lt;code&gt;show configuration commands&lt;/code&gt; interactively to get the canonical set-command form. Both agree that &lt;code&gt;member&lt;/code&gt; is real, not a display quirk. I also checked the current published documentation (both the &lt;code&gt;latest&lt;/code&gt; and &lt;code&gt;rolling&lt;/code&gt; branches on docs.vyos.io) and, as of writing, neither mentions &lt;code&gt;member&lt;/code&gt; at all. They still document the flat &lt;code&gt;set firewall zone &amp;lt;name&amp;gt; interface &amp;lt;interface&amp;gt;&lt;/code&gt; form.&lt;/p&gt;
&lt;p&gt;The explanation turned up in VyOS&amp;rsquo;s own development tracker: &lt;a href="https://vyos.dev/T6841" class="external-link" target="_blank" rel="noopener"&gt;T6841&lt;/a&gt;, &amp;ldquo;Separate interface and VRF options in firewall zone configuration.&amp;rdquo; It landed in 1.5 (Circinus) and the rolling release, and restructures zone membership so a zone can be tied to a VRF as well as a plain interface. This needs its own node in the config tree rather than overloading &lt;code&gt;interface&lt;/code&gt;. Migration scripts handle the rewrite automatically when you upgrade a router in place. What they don&amp;rsquo;t handle is any Ansible playbook, template, or copy-pasted &lt;code&gt;set&lt;/code&gt; command you&amp;rsquo;re maintaining outside the router. Those will silently target the old schema and either no-op or throw a parse error, depending on how your tooling handles unknown paths.&lt;/p&gt;
&lt;p&gt;If you manage more than one VyOS box and they&amp;rsquo;re not all on the same release, don&amp;rsquo;t assume config is portable between them. Pull &lt;code&gt;show configuration commands&lt;/code&gt; from the actual router before you template anything, rather than trusting docs or an older box&amp;rsquo;s config as ground truth. This is exactly the kind of gap where the official reference lags the shipped software, since VyOS&amp;rsquo;s docs and rolling builds are versioned separately.&lt;/p&gt;
&lt;h2 id="adapting-these-vyos-firewall-rules-for-your-own-network"&gt;
Adapting these VyOS firewall rules for your own network
&lt;a class="heading-link" href="#adapting-these-vyos-firewall-rules-for-your-own-network"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;None of the above will work by copy-pasting as-is. It shouldn&amp;rsquo;t, since it&amp;rsquo;s tied to my addressing and my services. To adapt it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Swap &lt;code&gt;10.254.88.0/21&lt;/code&gt; and friends for your own internal ranges in the &lt;code&gt;network-group&lt;/code&gt; definitions.&lt;/li&gt;
&lt;li&gt;Decide what actually needs a WAN-LOCAL allow rule. If you&amp;rsquo;re not running SMTP or IMAP publicly, drop rules 1012 and 1013 entirely. Every open port is something you have to keep patched.&lt;/li&gt;
&lt;li&gt;If you don&amp;rsquo;t have a threat-intelligence feed populating a blocklist group, that rule is inert but harmless; either wire one up or remove it.&lt;/li&gt;
&lt;li&gt;Start every new zone-pair ruleset with &lt;code&gt;default-action accept&lt;/code&gt; plus the invalid-state drop, and only tighten to &lt;code&gt;default-action drop&lt;/code&gt; for zones actually facing untrusted networks. Default-accept everywhere defeats the purpose of zones in the first place.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="further-reading"&gt;
Further reading
&lt;a class="heading-link" href="#further-reading"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;This sits alongside the rest of my VyOS series: &lt;a href="https://www.hamzahkhan.com/vyos-ospf-wireguard" &gt;site-to-site WireGuard with OSPF&lt;/a&gt;, &lt;a href="https://www.hamzahkhan.com/vyos-road-warrior-vpn" &gt;the road-warrior VPN setup&lt;/a&gt;, and &lt;a href="https://www.hamzahkhan.com/captive-dns-with-vyos" &gt;redirecting hardcoded DNS&lt;/a&gt;. If you&amp;rsquo;re running VyOS at a scale where firewall drift between routers on different releases is becoming an operational risk rather than a curiosity, that&amp;rsquo;s exactly the kind of platform work I do at &lt;a href="https://www.intahnetsolutions.co.uk/services/site-reliability-engineering/" class="external-link" target="_blank" rel="noopener"&gt;Intahnet Solutions&lt;/a&gt;. More on my background is available at &lt;a href="https://www.hamzahkhan.com/hamzah-khan/" &gt;hamzahkhan.com/hamzah-khan&lt;/a&gt;.&lt;/p&gt;</content:encoded></item></channel></rss>