Building a Proper Firewall: pfSense on Bare Metal

June 20, 2021 / 11 min read / - views​

Why bother? Home networks aren’t “simple” anymore

Between work laptops, smart TVs, DoorBird cameras, Zigbee hubs, a NAS you swear you’ll back up, and a couple of dev boxes, your home network looks like a small office. A flat LAN with one consumer router isn’t good enough. You want:

  • Blast‑proof internet for work calls
  • Isolation for untrusted gadgets
  • Clean observability when things misbehave
  • Reasonable performance without a rack of jet engines

pfSense on bare metal ticks those boxes: stable FreeBSD base, excellent firewalling (pf), first‑class VLANs, solid packages (ntopng, softflowd, Suricata), and grown‑up features without vendor lock‑in.

This guide walks you through a real, repeatable setup: hardware choices, install, a sane VLAN design, segmentation rules, traffic analysis, and optional extras like VPN and IDS. It’s written from the perspective of someone who’s done this too many times, broken it a few, and learned the sharp edges so you don’t.


Target topology (the north star)

We’ll build a hub‑and‑spoke design around pfSense. One trunk to a managed switch, SSIDs mapped to VLANs on the AP, and strict east‑west rules.

               ┌───────────────────────── Internet (ISP) ─────────────────────────┐
                                   │
                                 [ONT/Modem]
                                   │ (WAN)
                                [ pfSense Box ]
                                   │ (LAN parent, 802.1Q trunk)
                               [Managed Switch]
         ┌───────────────┬───────────────┬──────────────┬───────────────┬───────────────┐
         │               │               │              │               │               │
       VLAN10         VLAN20          VLAN30         VLAN40          VLAN50          VLAN60
       Users          IoT             Guest          Work            Servers         Cameras
       192.168.10.0   192.168.20.0    192.168.30.0   192.168.40.0    192.168.50.0    192.168.60.0
         │               │               │              │               │               │
     PCs/Consoles   TV, bulbs,      SSID Guest    Dev laptops,     NAS, HA,        NVR/PoE cams
                     speakers                         lab VMs       homelab

                              VLAN99: Management 192.168.99.0/24
                              (switch/AP mgmt + pfSense GUI)

VLAN plan (copy/paste table)

vlans:
  - id: 99   # Management
    cidr: 192.168.99.0/24
    gateway: 192.168.99.1
    purpose: switch/AP management, pfSense GUI, SSH
  - id: 10   # Users
    cidr: 192.168.10.0/24
    gateway: 192.168.10.1
    purpose: laptops, desktops, consoles
  - id: 20   # IoT
    cidr: 192.168.20.0/24
    gateway: 192.168.20.1
    purpose: smart TVs, bulbs, assistants
  - id: 30   # Guest
    cidr: 192.168.30.0/24
    gateway: 192.168.30.1
    purpose: internet‑only guest Wi‑Fi
  - id: 40   # Work
    cidr: 192.168.40.0/24
    gateway: 192.168.40.1
    purpose: company devices, dev boxes
  - id: 50   # Servers
    cidr: 192.168.50.0/24
    gateway: 192.168.50.1
    purpose: NAS, Home Assistant, Docker/VM hosts
  - id: 60   # Cameras
    cidr: 192.168.60.0/24
    gateway: 192.168.60.1
    purpose: PoE cams, NVR

Hardware that won’t make you cry

CPU: Modern low‑power x86 is fine (Intel N100/N305, i3/i5 T‑series). If you want heavy VPN/IDS, aim higher.

NICs: Prioritise Intel i210/i211/i350/i225‑V (rev 3+) or i226. Quad‑port i350 cards are excellent. Avoid cheap Realtek for serious work.

RAM/Storage: 8 GB RAM and a small SSD (32–128 GB) is plenty. Prefer SSD over USB sticks. Use a UPS.

Switch/AP: Managed switch with 802.1Q VLANs and an AP that supports multiple SSIDs mapped to VLANs (UniFi, Omada, Aruba Instant On, MikroTik, etc.).

Cooling/Noise: Fanless mini‑PCs are perfect. If you rack it, pick quiet fans.

Personal note: I’ve had the best luck with fanless N100 boxes with 4× i226 ports for sub‑gigabit links, and an old Xeon + i350 quad‑NIC when I needed >1 Gbit of WireGuard/IPsec plus Suricata.


Install pfSense on bare metal

  1. Download the amd64 memstick installer and write it to a USB drive.
  2. Boot target box, use UEFI if available.
  3. Filesystem: ZFS mirror if you have two SSDs, otherwise UFS or single‑disk ZFS is fine.
  4. Assign WAN and LAN at the console. Keep LAN as a dedicated port for now; we’ll convert it to a VLAN trunk after initial setup.

First‑boot hygiene

  • Change the admin password.
  • System → Advanced → Admin Access: enable HTTPS, set a unique TCP port, and restrict GUI to Management VLAN once it exists.
  • System → Advanced → Networking: tick the offload checkboxes to disable hardware checksum/TSO/LRO. It avoids driver quirks.
  • Enable SSH key auth if you’ll use the shell.
  • Set correct time zone and NTP servers.
  • On WAN, enable block bogons and block RFC1918.

Create VLAN interfaces in pfSense

We’ll trunk VLANs on the physical LAN NIC.

  1. Interfaces → Assignments → VLANs → Add:

    • Parent interface: your LAN NIC (e.g. igc0)
    • VLAN tags: 99, 10, 20, 30, 40, 50, 60
  2. Interfaces → Assignments → Add each VLAN as an interface.

  3. For each interface, Enable, give it a name, and set a static IPv4 like 192.168.<vlan>.1/24.

  4. Services → DHCP Server → per‑VLAN:

    • Specify pools (e.g. 192.168.10.50–199)
    • DNS server: use pfSense interface IP (or point to your internal DNS if you run one)
    • Static mappings for critical hosts
  5. Services → DNS Resolver (Unbound):

    • Enable per‑VLAN access lists.
    • Optionally enable DNS over TLS upstreams, but still force clients to use your pfSense as resolver.

Anti‑lockout rule: pfSense adds this on the default LAN. Once Management VLAN is live and you’ve allowed GUI there, move admin off “LAN,” and you can disable the anti‑lockout on the old LAN to avoid surprises.


Configure the switch and AP

Switch:

  • Set the port to pfSense as a trunk carrying VLANs 10,20,30,40,50,60,99.
  • Put your management device ports (switch web UI, AP management) as access VLAN 99.
  • Workstation ports: access VLAN 10 or 40 depending on device.
  • NAS/servers: access VLAN 50.
  • Cameras: access VLAN 60. If you use PoE, keep them on a separate physical PoE switch uplinked via the trunk.

AP:

  • SSID “Home” → VLAN 10
  • SSID “Guest” → VLAN 30 with client isolation and rate limits
  • Optional SSID “Work” → VLAN 40
  • AP management IP on VLAN 99

Firewall rules that actually segment

pf rules are evaluated top‑down, first match wins on each interface. Default stance: everything is blocked unless explicitly allowed. Start minimalist and add exceptions with Aliases for maintainability.

Create Aliases

Firewall → Aliases:

hosts:
  - name: ALIAS_HA
    addrs: 192.168.50.10       # Home Assistant
  - name: ALIAS_NAS
    addrs: 192.168.50.20
  - name: ALIAS_MGMT
    addrs: 192.168.99.0/24
ports:
  - name: PORTS_DNS
    ports: [53, 853]
  - name: PORTS_HA
    ports: [8123]
  - name: PORTS_NTP
    ports: [123]
networks:
  - name: NETS_RFC1918
    nets: [10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16]

Per‑VLAN rules

VLAN10 Users:

  1. Block to RFC1918 on other VLANs except WAN: VLAN10 net → NETS_RFC1918 Block
  2. Allow DNS to pfSense: VLAN10 net → This Firewall (VLAN10 address) PORTS_DNS Pass
  3. Allow NTP to pfSense: VLAN10 net → This Firewall PORTS_NTP Pass
  4. Force DNS: block outbound 53/853 to any not pfSense, then add a NAT Port Forward redirecting 53/853 to the interface IP.
  5. Internet: VLAN10 net → any (not RFC1918) Pass

VLAN20 IoT:

  1. Block to private nets: VLAN20 net → NETS_RFC1918 Block
  2. Allow DNS/NTP to pfSense as above.
  3. Allow limited access to Home Assistant: VLAN20 net → ALIAS_HA PORTS_HA Pass
  4. Internet only otherwise.

VLAN30 Guest:

  • Only DNS/NTP to pfSense, and VLAN30 net → any (not RFC1918) Pass. Enable client isolation on the AP.

VLAN40 Work:

  • Same as Users but optionally allow to Servers VLAN for Git, package mirrors, etc. Use specific rules by port and alias.

VLAN50 Servers:

  • Default Block outbound except updates, NTP, DNS. Create explicit rules for backups, package repos, and management from VLAN99.

VLAN60 Cameras:

  • Block everything except to NVR and to internet destinations the vendor requires. Favour on‑prem NVRs and block cloud domains at DNS.

Tip: keep no inter‑VLAN allow rules on user/IoT networks. If you must poke a hole, target a single host and port. Your future self will thank you.


NAT and outbound

  • Firewall → NAT → Outbound: keep Automatic unless you need policy‑based routing or multiple WANs.
  • UPnP: avoid it. If you must, scope it to a single VLAN and specific clients.

DNS policy (the quiet security win)

  • Run Unbound on pfSense and enforce it with the “Force DNS” pattern above.
  • Block DoH/DoT to the public internet using a list of known resolvers if you want strict control.
  • Per‑VLAN DNS overrides: point IoT/Guest at pfSense; point Servers at an internal resolver if you run one.
  • mDNS/Chromecast across VLANs: install Avahi package and selectively reflect between IoT ↔ Users.

Smart queues: fix bufferbloat

If your upstream buffers are bad, QoS matters more than raw throughput.

  1. Firewall → Traffic Shaper → Limiters.
  2. Create Upload and Download limiters with FQ‑CoDel.
  3. Set bandwidth a touch below your real line rate (e.g. 900/900 for a 1 Gbit symmetric link).
  4. On your per‑VLAN rules that go to the internet, set In/Out queues to these limiters.

Result: latency under load stays sane for calls and gaming.


Traffic analysis that doesn’t nuke performance

Two practical options:

Option A: NetFlow/IPFIX with ntopng (lightweight, scalable)

  • Install softflowd on pfSense and export from WAN and selected VLANs to a collector (can be ntopng on a separate box or even the pfSense itself if CPU headroom exists).
  • Install ntopng and point it at the flow feed. You’ll get top talkers, apps, hosts, and historical graphs with low overhead.

Option B: Inline packet analytics (heavier)

  • Enable pfSense Packet Capture on demand for deep dives.
  • For long‑term full‑packet capture or Zeek, mirror switch ports to a separate sensor (old NUC or Pi 5) instead of burdening the firewall.

Rule of thumb: keep the firewall’s job to filtering and routing. Offload heavy analytics to a collector.


Optional: IDS/IPS with Suricata

  • Install Suricata package.
  • Start with alert‑only on WAN and one high‑risk VLAN (IoT). Use ETOpen or similar rulesets.
  • Once noise is under control, consider inline IPS (netmap) on that VLAN. Keep it off latency‑sensitive networks unless you’ve got CPU to spare.
  • Maintain a suppression list for false positives. Never “enable all rules.”

VPN: remote access the right way

  • WireGuard for road‑warrior access is straightforward and fast. Put the WG interface in the firewall group and create a rule set that only allows hitting Management and Servers. No blanket access to Users/IoT.
  • Site‑to‑site: WireGuard or IPsec. Route only what you need. Document it.

Performance tuning checklist

  • System → Advanced → Networking: keep offloads disabled; use PowerD hiadaptive.
  • Prefer Intel NICs with multiple queues for higher throughput.
  • PPPoE? Set MTU/MSS clamping appropriately (e.g. 1492/1452 typical) on WAN.
  • Enable DNS Resolver in forward or recursive mode based on needs; keep one job per box.
  • If you push multi‑gig, consider 2.5G/10G NICs and a switch that can keep up.

Backups, monitoring, and notes to future‑you

  • Backups: take a config backup after every major change. Store it off‑device. If you’re on the commercial build, the cloud backup feature is handy; otherwise download the XML.
  • Monitoring: enable Telemetry/Telegraf exporter and ship metrics to InfluxDB + Grafana, or rely on RRD for basics.
  • Docs: keep a NETMAP.md with VLAN IDs, subnets, trunk ports, and why each rule exists. Future‑you will buy you a coffee.

Common pitfalls (and the fixes)

  • Locked yourself out of the GUI: connect to the console, assign a laptop to the Management VLAN, or temporarily allow from a workstation VLAN. Worst case, reset the filter or anti‑lockout at the console menu.
  • DHCP not working on a VLAN: check the switch port is access on the correct VLAN and that DHCP is enabled on the matching pfSense interface.
  • Double NAT with ISP routers: put the ISP CPE in bridge/DMZ mode or use pfSense’s WAN in a DMZ with static port NAT where needed.
  • mDNS/Chromecast not crossing VLANs: install Avahi and explicitly reflect between the two relevant VLANs.
  • Slow internet under load: implement the FQ‑CoDel limiters. It fixes more “Wi‑Fi is laggy” complaints than any other single change.

Example: minimal ruleset snapshot

Here’s a compact representation of the intent using pseudo‑pf:

# VLAN20 (IoT)
block quick from 192.168.20.0/24 to <NETS_RFC1918>
pass  quick from 192.168.20.0/24 to (self) port {53,853,123}
pass  quick from 192.168.20.0/24 to 192.168.50.10 port 8123
pass  quick from 192.168.20.0/24 to !<NETS_RFC1918>

# VLAN30 (Guest)
block quick from 192.168.30.0/24 to <NETS_RFC1918>
pass  quick from 192.168.30.0/24 to (self) port {53,853,123}
pass  quick from 192.168.30.0/24 to !<NETS_RFC1918>

# VLAN10/40 similar pattern with tighter inter‑VLAN exceptions

The bottom line

A proper firewall isn’t about shiny dashboards. It’s about intent, isolation, and boring reliability. pfSense on bare metal gives you the primitives to build that. Start with clear VLANs, be strict with east‑west traffic, keep DNS under your control, and measure what’s happening. Everything else is iterative polish.

If you implement the layout above, you’ll have a network that behaves like a tidy small office: fast, observable, and resilient. Which is exactly what a modern home needs.