<!--date=20250204 -->


<h1>Firewalling in 2025</h1>
<p>Firewalls haven't fundamentally changed in concept — you're still deciding what traffic to allow and what to drop. But where they run, how much they can see, and what the landscape looks like for self-hosted setups has evolved. This is a practical overview of what matters and what's actually new.</p>

<h2>The Core Concepts Haven't Changed</h2>
<p>At the core, a firewall is still a ruleset: match packets against criteria, decide pass or block. The criteria can be as simple as "drop everything on port 23" or as complex as "allow established connections from this subnet except for traffic matching these signatures." The model is the same one from the 90s.</p>

<table>
  <thead><tr><th>Type</th><th>Layer</th><th>What it sees</th><th>Character</th></tr></thead>
  <tbody>
    <tr><td>Packet filtering</td><td>3 / 4</td><td>IP, port, protocol</td><td>Fast, simple, blind to connection state</td></tr>
    <tr><td>Stateful filtering</td><td>3 / 4 + state</td><td>Connection state, sequence numbers</td><td>Standard for two decades; handles return traffic automatically</td></tr>
    <tr><td>Application layer (DPI)</td><td>7</td><td>Protocol content (HTTP, DNS, TLS)</td><td>Powerful, CPU-intensive; HTTPS largely defeats it without MITM</td></tr>
  </tbody>
</table>

<h2>The Tools That Actually Matter</h2>

<table>
  <thead><tr><th>Tool</th><th>Platform</th><th>Status in 2025</th></tr></thead>
  <tbody>
    <tr><td>OpenBSD pf</td><td>OpenBSD, FreeBSD</td><td>The standard for BSD. Clean syntax, tightly integrated. Best choice for BSD-based firewall/routers.</td></tr>
    <tr><td>nftables</td><td>Linux</td><td>The modern Linux kernel firewall, replacing iptables. Where new development happens. Use it for new Linux setups.</td></tr>
    <tr><td>iptables</td><td>Linux</td><td>Still works; still the default on older systems. Don't start new projects with it — nftables is the future.</td></tr>
    <tr><td>ufw</td><td>Ubuntu / Debian</td><td>User-friendly frontend for iptables/nftables. Good for simple setups; command-line focused.</td></tr>
    <tr><td>firewalld</td><td>Red Hat / Fedora / Rocky</td><td>More structured frontend; zones and services model. Better for complex rules than ufw.</td></tr>
    <tr><td>pfSense / OPNsense</td><td>Dedicated appliance</td><td>FreeBSD-based distributions with web UIs. Excellent for dedicated hardware or VMs acting as routers.</td></tr>
  </tbody>
</table>

<h2>The Cloud Complication</h2>
<p>If you run anything in AWS, GCP, or Azure, you deal with their security groups and network ACLs whether you want to or not. These are the firewall layer that lives outside your instance — traffic gets filtered before it ever reaches your server.</p>
<ul>
  <li><strong>Security groups</strong> (AWS) — stateful, per-instance rules. Traffic matching an outbound rule automatically allows the return.</li>
  <li><strong>Network ACLs</strong> (AWS) — stateless, per-subnet rules. You must explicitly allow return traffic in both directions.</li>
  <li><strong>Host firewall</strong> — iptables/nftables/ufw running inside the instance itself.</li>
</ul>
<p>The layered approach is good security practice. The problem is three layers of firewall rules in three different interfaces is an excellent way to spend an afternoon debugging why traffic that should work doesn't. Keep a diagram of which layer blocks what.</p>

<h2>What's Actually New</h2>

<h3>Encrypted Traffic Everywhere</h3>
<p>HTTPS everywhere means most content inspection is useless without TLS termination at the firewall — which introduces its own problems (certificate pinning breakage, new trust boundary, performance cost). The practical effect: application-layer firewalls are less useful for traffic to/from the open internet than they were in the HTTP era.</p>

<h3>Container and Kubernetes Networking</h3>
<p>Container networking (Docker, Kubernetes) operates at a different level — network policies applied at the pod level rather than the host level. Tools like Cilium (eBPF-based) and Calico implement microsegmentation within a cluster. If you're running containers at scale this matters significantly; for a single VPS running a few services, it's irrelevant.</p>

<h3>Dynamic Blocking Is More Important</h3>
<p>Automated scanning of the internet is constant and has increased. Whatever firewall you use, something should be watching logs and dynamically banning repeat offenders:</p>
<ul>
  <li><strong>pf</strong> — built-in with <code>overload</code> tables and <code>max-src-conn-rate</code></li>
  <li><strong>Linux</strong> — fail2ban or sshguard watching logs and adding iptables/nftables rules</li>
</ul>

<h2>What to Actually Run</h2>
<p>For a typical self-hosted server:</p>
<ol>
  <li>Pick pf (BSD) or ufw/nftables (Linux)</li>
  <li>Default deny — block all inbound, allow what you need explicitly</li>
  <li>Log blocked traffic on the external interface</li>
  <li>Run fail2ban or pf's overload tables for dynamic brute-force blocking</li>
  <li>Use ed25519 SSH keys, disable password auth, disable root login</li>
</ol>
<p>That covers 90% of what matters for a personal or small production server. The rest is tuning for specific threat models.</p>

<h2>References</h2>
<ul>
  <li><a href="https://www.openbsd.org/faq/pf/" target="_blank" rel="noopener">OpenBSD pf FAQ ↗</a></li>
  <li><a href="https://wiki.nftables.org" target="_blank" rel="noopener">nftables wiki ↗</a></li>
  <li><a href="https://www.fail2ban.org" target="_blank" rel="noopener">Fail2ban ↗</a></li>
</ul>
