Torii: Network & Security Architecture

Torii is the OPNsense firewall running my homelab. This page is a reference, not a diary entry - what zones exist, what's listening where, and what's still broken. It's the page I check when I've forgotten what I built. If you want the story of how Claude got a way into this firewall in the first place, that's a separate post - this page covers what an audit through that connection actually found.

Last reviewed 3.8.2026

1. Interfaces

Eight zones hang off Torii. Everything below is drawn roughly the way I'd sketch it on a whiteboard - one firewall, a handful of interfaces underneath it, each with its own job.

Torii OPNsense firewall

Mgmt

10.250.250.0/24

Management network. GUI/SSH admin access to Torii itself.

Clients

10.10.10.0/24

General client devices.

Servers

10.20.20.0/24

Internal application and server hosts.

DMZ

10.30.30.0/24

Isolated. Firewall-blocked from reaching every other internal zone.

VPN

10.100.100.0/24

WireGuard road-warrior interface. Remote admin access.

WireGuard (Group)

no IP

Meta-interface grouping WireGuard-type interfaces for firewall rule targeting.

PrivateWAN

public Hetzner IP

Primary internet uplink.

PublicWAN

public Hetzner IP

Secondary public-facing uplink.

Solid borders are ordinary internal zones. The dashed boxes are the two WAN uplinks, both public Hetzner addresses I'm not going to publish here. The dotted box is WireGuard's group interface, which doesn't get an IP of its own, it just exists so firewall rules can target "all WireGuard interfaces" in one shot. DMZ gets the amber border because it's the one zone that's deliberately fenced off from all the others.

2. Services

What actually runs on top of that interface layout, and where.

Unbound DNS resolver

Scope tightened today

Runs on: Mgmt, Clients, Servers, DMZ, VPN

Resolves DNS for every internal zone. As of today it's restricted to those internal interfaces only. It used to also answer on both WAN interfaces, which is a textbook open-resolver exposure. More on that in the audit section below.

DHCP

Active

Runs on: per-interface

Mostly dynamic leases. A handful of critical hosts still need static reservations instead of hoping they keep the same address forever.

HAProxy reverse proxy

Disabled

Runs on: Torii

Six backends defined - Kazan, Torii, Shima, Wazuh, Hal, Blackhole - all pointing at zero live servers. Genuinely mid-build or mid-decommission, I haven't decided which yet.

Wazuh SIEM

Active

Runs on: Servers zone

Agents enroll in from DMZ over specific ports. Already covered in depth in the docker-wazuh blog series, so I won't re-explain it here.

WireGuard VPN

Active

Runs on: VPN interface

Remote access into Mgmt, Servers, and DMZ for admin work. Covered in the VPN setup entry - the interface has since moved onto Torii itself as part of the mTLS migration, but the idea is the same.

ACME / Let's Encrypt

Active

Runs on: Torii

Auto-renewing certificates for the mukokura.com and luke.yt domains.

3. Today's audit and fixes

Today I had Claude run six parallel read-only audit agents against Torii's config - one each for firewall rules, NAT, DNS, DHCP, general system health, and HAProxy - and go hunting for whatever got left half-configured back when this was first set up. Everything was read-only, so worst case was a wrong report, not a broken firewall. Turned out there was plenty to find.

Found and fixed the same day

A "temporary" rule that never left

First thing that jumped out: a rule on the WireGuard interface labeled something like "TROUBLESHOOTING TO REVIEW" that allowed any protocol to any destination. It sat above every other, more specific rule on that interface, and in firewall terms the rule on top wins. Every carefully scoped rule underneath it was dead weight, silently overridden by something I'd apparently written for a five-minute debugging session and then forgot existed. A classic temporary fix that outlived its purpose. Disabled it.

SSH open to the whole internet

The SSH admin port was reachable from any source instead of being scoped to the VPN like it should have been. Restricted the source to the VPN subnet, then verified it externally - tried reaching the port from outside that subnet and got nothing back, which is exactly what you want to see.

An open DNS resolver on both WAN interfaces

Unbound was answering DNS queries on both public WAN interfaces, not just the internal zones. That one's genuinely bad - open resolvers get abused for DNS amplification attacks, so anyone on the internet could have been sending Torii queries and getting answers back. This one didn't get fixed through the automation though. The read-only SSH account behind it has no sudo, so there was no safe way to push a raw config edit through that path. Fixed it by hand in the GUI instead, then verified it by running external DNS queries against both public IPs and confirming neither one answered anymore.

Worth being honest about one more thing: one of the audit agents also reported a "mystery unidentified network," like it had stumbled onto something suspicious. It hadn't. It just had the interface-to-subnet mapping wrong, and the mystery network was the Mgmt zone under its real subnet the whole time. Good reminder that an AI-generated audit finding is a lead, not a verdict. It's worth a skeptical second look before you trust it, whether that second look comes from a human or another AI.

4. Still on the list

Not everything got fixed today. Here's what's still open, roughly in the order I care about it:

Next session is probably Monit and the backup situation, since "no alerting" plus "one backup, over a year old" is exactly the kind of combination that turns a small problem into a very bad week.