← All projects

Getting started with pfSense: my home firewall setup

How I set up pfSense as my home firewall — VLANs, firewall rules, DNS over TLS, and why I landed on it over other options.


pfSense is a FreeBSD-based firewall and router platform that gives you enterprise-grade network control on commodity hardware. I ran it as a VM on Proxmox before moving to a UniFi Dream Machine. This writeup covers the full setup from installation through to a working multi-VLAN configuration with DNS over TLS.

Why pfSense

I evaluated OPNsense, pfSense, and a plain Linux iptables setup. pfSense won for three reasons: the volume of documentation available, the maturity of the package ecosystem, and the WebGUI which makes complex firewall rule management approachable without sacrificing depth.

Running pfSense in Proxmox

pfSense runs as a full VM rather than an LXC — it needs its own kernel for the FreeBSD network stack.

VM configuration:

CPU:    2 cores (KVM64)
RAM:    2048MB
Disk:   16GB (virtio-scsi)
NIC 1:  vtnet0 → vmbr0 (WAN — bridged to physical NIC)
NIC 2:  vtnet1 → vmbr1 (LAN bridge)

Download the pfSense CE ISO from netgate.com, attach it as a CD drive, and boot the VM. The installer is straightforward — accept defaults, choose the correct WAN and LAN interfaces when prompted.

Initial WebGUI setup

Once installed, pfSense is accessible at 192.168.1.1 from the LAN. The setup wizard runs on first login:

  • Set hostname and domain
  • Set upstream DNS servers (I use 1.1.1.1 and 9.9.9.9 initially, then switch to DNS over TLS)
  • Set timezone to Europe/London
  • Configure WAN (DHCP from ISP or static)
  • Set a strong admin password

VLAN configuration

pfSense handles VLAN tagging on the LAN interface. Navigate to Interfaces → Assignments → VLANs → Add:

VLAN 10 — DMZ
  Parent:   vtnet1
  VLAN tag: 10
  Desc:     DMZ

VLAN 20 — IoT
  Parent:   vtnet1
  VLAN tag: 20
  Desc:     IoT

VLAN 30 — Trusted
  Parent:   vtnet1
  VLAN tag: 30
  Desc:     Trusted LAN

Assign each VLAN as an interface under Interfaces → Assignments, then enable and configure each:

DMZ:     10.10.10.1/24
IoT:     10.20.20.1/24
Trusted: 192.168.1.1/24

Enable DHCP for each under Services → DHCP Server.

Firewall rules

Navigate to Firewall → Rules and configure per interface.

DMZ rules:

Allow DMZ → WAN (for outbound updates)
Block DMZ → Trusted LAN (isolation)
Block DMZ → IoT
Block DMZ → RFC1918 (catch-all private ranges)

IoT rules:

Allow IoT → WAN (internet access for devices)
Block IoT → Trusted LAN
Block IoT → DMZ

Trusted LAN rules:

Allow Trusted → any (full access)

The block rules must come before any allow rules — pfSense processes rules top to bottom and stops at the first match.

DNS over TLS

Navigate to Services → DNS Resolver → General Settings:

  • Enable DNS Resolver: ✅
  • DNSSEC: ✅
  • DNS over TLS: ✅

Under DNS over TLS Servers, add:

Server: 1.1.1.1  Port: 853  Hostname: cloudflare-dns.com
Server: 9.9.9.9  Port: 853  Hostname: dns.quad9.net

This encrypts all DNS queries leaving the network. Verify it’s working:

# From a client on the LAN
dig @192.168.1.1 example.com
# Should return results via the pfSense resolver

Split-horizon DNS

A useful feature of pfSense’s DNS resolver is host overrides — you can make internal services resolve differently internally than they do externally. Under Services → DNS Resolver → Host Overrides:

Host:    nas
Domain:  home.local
IP:      192.168.1.20
Desc:    Synology NAS internal resolution

Clients on the LAN can then reach nas.home.local which resolves to the internal IP, bypassing any external DNS.

Performance

Running on 2 cores and 2GB RAM, pfSense handles gigabit throughput without breaking a sweat. CPU usage sits at around 2-3% under normal load, spiking briefly during large file transfers. For a home lab it’s significantly over-specced.