---
title: OpnSense
description: Grimoire Firewall Configuration
published: true
date: 2026-02-23T21:31:26.008Z
tags: 
editor: markdown
dateCreated: 2026-02-23T21:31:15.244Z
---

# OPNsense Firewall

**Host:** OPNsense.localdomain
**Timezone:** America/Chicago
**Documented:** February 23, 2026
**Status:** Active — AT&T migration in progress

---

## Overview

The network perimeter is protected by an OPNsense firewall running on dedicated hardware with four physical Intel i226-V NICs (igc0–igc3). The firewall operates in a dual-WAN configuration during the transition from the legacy ISP to AT&T fiber, with AT&T becoming the permanent primary WAN. CrowdSec threat intelligence, GeoIP blocking, and Spamhaus DROP/EDROP lists provide layered perimeter security.

---

## Hardware & System

| Parameter | Value |
|---|---|
| Hostname | OPNsense |
| Domain | localdomain |
| Timezone | America/Chicago |
| Language | en_US |
| NAT Outbound Mode | Hybrid |
| System DNS | 8.8.8.8 (Google) — see DNS notes |
| DNS Allow Override | Enabled |
| SSH | Enabled (port 22) |
| Console Menu | Disabled (hardened) |

> ⚠ **DNS Note:** The system upstream DNS is set to 8.8.8.8. If dnscrypt-proxy or Unbound is configured, this should be updated to point to localhost or the internal DNS resolver (192.168.5.7). Review before enabling encrypted DNS.

---

## Network Interfaces

| Interface | Label | Physical NIC | IP Address | Role |
|---|---|---|---|---|
| wan | WAN | igc0 | 24.249.193.114/28 | Legacy primary WAN — being retired |
| opt1 | ATT | igc1 | 107.133.34.145/28 | New primary WAN — AT&T fiber |
| lan | LAN | igc3 | 192.168.3.4/29 | Internal LAN management segment |
| opt3 | OPT3 | igc2 | DHCP | Unassigned — spare interface |
| opt2 / wg1 | WG1 | wg1 (virtual) | WireGuard tunnel | WireGuard VPN interface |
| openvpn | OpenVPN | virtual | Tunnel only | OpenVPN (server + client configured) |
| lo0 | Loopback | lo0 | 127.0.0.1/8 | System loopback |

> ⚠ **OPT3 (igc2)** is on DHCP and currently unassigned. Disable this interface or assign it a role to reduce unnecessary attack surface.

---

## Gateways & Routing

### Active Gateways

| Gateway Name | Interface | IP | Role |
|---|---|---|---|
| WAN_DefRoute | wan (igc0) | 24.249.193.114 | Legacy default route — being retired |
| ATT | opt1 (igc1) | 107.133.34.145 | AT&T — becoming primary |
| LAN_GWv4 | lan (igc3) | 192.168.3.4 | LAN gateway |

### NAT Outbound Rules

Outbound NAT runs in **Hybrid** mode — automatic rules supplemented by manual overrides below.

| Interface | Source | NAT Target | Purpose |
|---|---|---|---|
| opt1 (ATT) | ATT_Out_1 group | opt1ip | Dad's Laptop + 192.168.5.128/25 out ATT |
| wan | MailCow_Ngnx (192.168.5.16) | 24.249.193.115 | Mail server — dedicated WAN IP |
| wan | PNCHarris_Internal | wanip | Internal subnets egress |
| wan | WireGuard (opt2) | — | WireGuard outbound NAT |

> ✓ The mail server already has a dedicated outbound IP (24.249.193.115) on WAN. This pattern should be replicated on ATT using a dedicated virtual IP from the static block.

---

## Firewall Aliases

### Host Aliases

| Alias | IP Address | Used For |
|---|---|---|
| caddy | 192.168.5.10 | Caddy reverse proxy |
| MailCow_Ngnx | 192.168.5.16 | MailCow nginx container |
| JellyFin_Host | 192.168.5.18 | Jellyfin media server |
| ISPConfig_Host | 192.168.4.11 | ISPConfig control panel |
| Dads_Laptop | 192.168.5.176 | Routed out ATT interface |

### Network Aliases

| Alias | Value | Used For |
|---|---|---|
| PNCHarris_Internal | 192.168.5.0/25, 192.168.3.0/24 | Primary internal subnets |
| Subnet_5_128_Mask_25 | 192.168.5.128/25 | Upper half of 192.168.5.x |
| ATT_Out_1 | Dads_Laptop + Subnet_5_128_Mask_25 | Traffic routed out ATT interface |
| Family_Subnet | (empty) | Defined but unpopulated |

### Port Aliases

| Alias | Ports | Used For |
|---|---|---|
| Web_Services | 80, 443 | HTTP/HTTPS |
| MailCow | 25, 110, 143, 465, 587, 993, 995, 4190 | Full MailCow mail protocol suite |
| ISPConfig | 25, 53, 143, 465, 587, 993, 995, 8080 | ISPConfig mail + DNS + admin |
| JellyFin_Port | 8096, 7096 | Jellyfin HTTP + HTTPS |
| Plex_Port_2 | (empty) | Defined but unpopulated |

### Security & Threat Intelligence Aliases

| Alias | Type | Source | Status |
|---|---|---|---|
| SpamHaus_Drop | URL Table | https://www.spamhaus.org/drop/drop.txt | ⚠ Rule DISABLED |
| Spamhaus_edrop | URL Table | https://www.spamhaus.org/drop/edrop.txt | ⚠ Rule DISABLED |
| Blocked_Countries | GeoIP | 70 countries — see GeoIP section | ⚠ Rule DISABLED |
| crowdsec_blacklists | External | CrowdSec IPv4 decisions | ✓ Active |
| crowdsec6_blacklists | External | CrowdSec IPv6 decisions | ✓ Active |
| crowdsec_blocklists | External | CrowdSec IPv4 (duplicate) | ✓ Active |
| crowdsec6_blocklists | External | CrowdSec IPv6 decisions (duplicate) | ✓ Active |

> ⚠ **Critical:** Spamhaus DROP, Spamhaus EDROP, and GeoIP country blocking are all defined and populated but their firewall rules are **disabled**. These are not currently being enforced. Re-enable these rules as an immediate priority.

> ⚠ There are duplicate CrowdSec alias pairs (`crowdsec_blacklists` and `crowdsec_blocklists` both handle IPv4). Review and consolidate to avoid confusion.

---

## Firewall Rules

### WAN Rules

| Action | Protocol | Source | Destination | Port(s) | Enabled | Description |
|---|---|---|---|---|---|---|
| BLOCK | Any | SpamHaus_Drop | Any | Any | ❌ No | Block Spamhaus DROP list |
| BLOCK | Any | Spamhaus_edrop | Any | Any | ❌ No | Block Spamhaus EDROP list |
| BLOCK | Any | Blocked_Countries | Any | Any | ❌ No | GeoIP country block |
| PASS | TCP | Any | MailCow_Ngnx | MailCow ports | ✓ Yes | Inbound mail |
| PASS | TCP | Any | JellyFin_Host | 8096, 7096 | ✓ Yes | Jellyfin access |
| PASS | UDP | Any | WAN IP | 51820 | ✓ Yes | WireGuard VPN ingress |
| PASS | TCP | Any | MailCow_Ngnx | 80, 443 | ✓ Yes | MailCow webmail |
| PASS | TCP | Any | caddy (192.168.5.10) | 80, 443 | ✓ Yes | Caddy reverse proxy |

> ⚠ All three block rules at the top of the WAN ruleset are disabled. The firewall is currently not enforcing Spamhaus or GeoIP blocking despite the aliases being populated.

### LAN Rules

| Action | Protocol | Source | Destination | Description |
|---|---|---|---|---|
| PASS | Any | ATT_Out_1 group | Any | Dad's Laptop + upper subnet out ATT |
| PASS | Any | LAN subnet | Any | Default allow LAN to any |
| PASS | Any | PNCHarris_Internal | Any | Internal subnets to any |
| PASS | Any | LAN subnet | Any | Default allow LAN IPv6 to any |
| PASS | TCP | PNCHarris_Internal | ISPConfig_Host:ISPConfig | LAN → ISPConfig redirect |
| PASS | TCP | PNCHarris_Internal | ISPConfig_Host:80/443 | LAN → ISPConfig web redirect |
| PASS | TCP | PNCHarris_Internal | caddy:80/443 | LAN → Caddy redirect |
| PASS | TCP | PNCHarris_Internal | MailCow_Ngnx:MailCow | LAN → MailCow redirect |

### WireGuard Interface Rules

| Action | Protocol | Source | Destination | Description |
|---|---|---|---|---|
| PASS | Any | Any | Any | Allow all from WireGuard peers — unrestricted |

> ⚠ The WireGuard interface allows all traffic from all peers with no restrictions. Consider scoping rules per peer as needs are better understood — some remote sites may only need access to specific services.

---

## NAT Port Forwards

### WAN Inbound

| Protocol | Public Port(s) | Internal Target | Internal Port(s) | Service |
|---|---|---|---|---|
| TCP | MailCow ports | 192.168.5.16 (MailCow_Ngnx) | MailCow ports | Mail (SMTP/IMAP/POP3/Sieve) |
| TCP | 80, 443 | 192.168.5.16 (MailCow_Ngnx) | 80, 443 | MailCow webmail |
| TCP | 8096, 7096 | 192.168.5.18 (JellyFin_Host) | 8096, 7096 | Jellyfin |
| TCP | 80, 443 | 192.168.5.10 (caddy) | 80, 443 | Caddy (all web services) |

### LAN Hairpin (Internal Redirect)

| Protocol | Port(s) | Internal Target | Description |
|---|---|---|---|
| TCP | MailCow ports | 192.168.5.16 | Internal mail access |
| TCP | 80, 443 | 192.168.5.10 (caddy) | Internal web via Caddy |
| TCP | ISPConfig ports | 192.168.4.11 | Internal ISPConfig access |
| TCP | 80, 443 | 192.168.4.11 | Internal ISPConfig web |

---

## VPN

### WireGuard

**Server: pncharris**

| Parameter | Value |
|---|---|
| Tunnel Address | 192.168.32.1/24 |
| Listen Port | 51820 (UDP) |
| DNS for Peers | 192.168.5.7 (internal DNS) |
| Interface | wg1 (OPT2) |
| Status | Enabled |

**Peers**

| Peer | Tunnel IP | Status | Notes |
|---|---|---|---|
| Obie | 192.168.32.2/32 | ✓ Enabled | |
| pncfishandmore | 192.168.32.3/32 | ✓ Enabled | Business location |
| GLNet (1) | 192.168.32.4/32 | ✓ Enabled | GL.iNet travel router |
| PortaPotty | 192.168.32.5/32 | ✓ Enabled | Remote site |
| GLNet (2) | 192.168.32.6/32 | ✓ Enabled | Second GL.iNet device |

> ✓ WireGuard peers use the internal DNS server (192.168.5.7) — internal hostnames resolve correctly over VPN.

### OpenVPN

An OpenVPN server and client are configured but details were not populated in the backup. Verify status in **VPN → OpenVPN** in the OPNsense UI.

---

## Security Features

### CrowdSec

CrowdSec is installed and fully operational at the firewall level.

| Parameter | Value |
|---|---|
| Agent | Enabled |
| Local API (LAPI) | Enabled — 127.0.0.1:8080 |
| Firewall Bouncer | Enabled |
| Rules | Enabled with logging |
| Firewall Bouncer Verbose | Disabled |
| Manual LAPI Config | Disabled (auto) |

CrowdSec decisions are fed into two alias pairs used in firewall rules:
- `crowdsec_blacklists` / `crowdsec6_blacklists` — IPv4 and IPv6 block lists
- `crowdsec_blocklists` / `crowdsec6_blocklists` — duplicate set (consolidate)

### GeoIP Blocking

GeoIP uses the MaxMind GeoLite2 database with a configured license key. **The blocking rule is currently disabled** — the alias is populated but not enforced.

**70 countries are blocked across four regions:**

| Region | Countries |
|---|---|
| Africa (49) | AO, BF, BI, BJ, BW, CD, CF, CG, CI, CM, DJ, DZ, EG, EH, ER, ET, GA, GH, GM, GN, GQ, GW, KE, LR, LS, LY, MA, ML, MR, MW, MZ, NA, NE, NG, RW, SD, SL, SN, SO, SS, ST, SZ, TD, TG, TN, TZ, UG, ZA, ZM, ZW |
| Middle East / Asia (12) | AF, BN, BT, CN, IQ, IR, KG, KP, KW, PH, QA, SA |
| Eastern Europe (4) | BG, RS, RU, RO |
| Latin America (4) | BR, EC, GT, HN |

### Spamhaus Blocklists

Both lists are configured as URL table aliases that auto-refresh, but **both blocking rules are currently disabled.**

| List | URL | Update |
|---|---|---|
| Spamhaus DROP | https://www.spamhaus.org/drop/drop.txt | Auto (URL table) |
| Spamhaus EDROP | https://www.spamhaus.org/drop/edrop.txt | Auto (URL table) |

---

## Internal Network Layout

### Known Subnets

| Subnet | Alias | Purpose |
|---|---|---|
| 192.168.3.0/24 | PNCHarris_Internal | LAN management segment |
| 192.168.5.0/25 | PNCHarris_Internal | Primary server subnet |
| 192.168.5.128/25 | Subnet_5_128_Mask_25 | Secondary server subnet / ATT routing |
| 192.168.32.0/24 | — | WireGuard tunnel network |

### Key Internal Hosts

| Hostname / Alias | IP | Role |
|---|---|---|
| caddy | 192.168.5.10 | Caddy reverse proxy (all web services) |
| MailCow_Ngnx | 192.168.5.16 | MailCow nginx container |
| JellyFin_Host | 192.168.5.18 | Jellyfin media server |
| ISPConfig_Host | 192.168.4.11 | ISPConfig control panel |
| Dads_Laptop | 192.168.5.176 | Routed via ATT interface |
| Internal DNS | 192.168.5.7 | DNS server (served to WireGuard peers) |

### DHCP

DHCP on the LAN interface (192.168.3.0/24) is currently **disabled**. No KEA or ISC DHCP ranges are active on the firewall. Devices likely use static IPs or a separate DHCP server downstream.

---

## Installed Plugins & Services

The following OPNsense components are present in the configuration:

| Plugin / Service | Status |
|---|---|
| WireGuard | ✓ Active — 1 server, 5 peers |
| CrowdSec | ✓ Active — agent + bouncer + LAPI |
| OpenVPN | Configured — verify in UI |
| IPsec / Swanctl | Present — verify in UI |
| Unbound Plus | Present — verify DNS configuration |
| Kea DHCP | Present — not active on LAN |
| DHCP Relay | Present |
| Netflow | Present |
| IDS/IPS (Suricata) | ❌ Not configured — see hardening plan |
| Proxy | Present — not actively used |
| Traffic Shaper | Present |
| Monit | Present |
| SNMP | Present |
| Syslog | Not configured — see hardening plan |
| Git Backup | Not installed — see hardening plan |

---

## AT&T Migration & Static IP Plan

### Current AT&T Interface

**Interface:** opt1 (igc1)
**Current IP:** 107.133.34.145/28
**Block:** /28 — up to 14 usable addresses, 5 static IPs allocated for use

### Recommended Static IP Allocation

| IP Slot | Dedicated To | Justification |
|---|---|---|
| IP 1 | **Mail (MailCow)** | Dedicated mail IP protects sender reputation. Never share with web services. Only ports 25/465/587/993/995/4190 NAT to 192.168.5.16. |
| IP 2 | **Web / Caddy** | All reverse-proxied services via Caddy. Keeps web and mail reputation independent. Replace current WAN NAT for ports 80/443 → 192.168.5.10. |
| IP 3 | **WireGuard VPN** | Dedicated IP for UDP/51820 only. Cleaner peer configs, stable endpoint, easy to firewall tightly — that IP accepts nothing else. |
| IP 4 | **Spare / Jellyfin** | Hold in reserve. Best candidate: dedicated Jellyfin IP (currently on WAN with ports 8096/7096). Media servers benefit from a clean IP separate from your main web presence. |
| IP 5 | **Admin / Out-of-band** | A locked-down IP for emergency remote OPNsense access. Firewall tightly — accept only from WireGuard peers or specific trusted source IPs. Never advertise publicly. |

### Implementation Steps

**Step 1 — Add Virtual IPs**

In OPNsense: **Firewall → Virtual IPs → Add**

For each additional static IP (IPs 1–5 excluding the interface IP):
- Type: `IP Alias`
- Interface: `ATT (opt1)`
- Address: `<static IP>/28`
- Description: e.g. `ATT_Mail`, `ATT_Web`, `ATT_WireGuard`

**Step 2 — Create NAT Rules Per Virtual IP**

In **Firewall → NAT → Port Forward**, create new rules on the ATT interface using the virtual IPs as the destination. Example for mail:

```
Interface:       ATT (opt1)
Protocol:        TCP
Destination:     ATT_Mail virtual IP
Destination Port: MailCow alias
Redirect Target: 192.168.5.16 (MailCow_Ngnx)
Redirect Port:   MailCow alias
```

Repeat for web (→ caddy 192.168.5.10) and WireGuard (UDP/51820).

**Step 3 — Update Outbound NAT**

Add manual outbound NAT rules so that each internal service exits through its dedicated virtual IP:

```
Interface:  ATT (opt1)
Source:     192.168.5.16 (MailCow_Ngnx)
Target:     ATT_Mail virtual IP

Interface:  ATT (opt1)
Source:     192.168.5.10 (caddy)
Target:     ATT_Web virtual IP
```

**Step 4 — Migrate WireGuard Endpoint**

Update peer configs to point to the ATT_WireGuard virtual IP on port 51820. Move the WAN WireGuard rule to ATT interface. Update DNS records if you have a hostname for the WireGuard endpoint.

**Step 5 — Update Firewall Block Rules**

Re-enable the Spamhaus and GeoIP block rules on the ATT interface. Apply them to the ATT WAN rules the same way they are (currently disabled) on WAN.

**Step 6 — DNS Updates**

Update all public DNS records to point to the new ATT static IPs:
- `mail.*` domains → ATT_Mail IP
- `*.netgrimoire.com`, `*.wasted-bandwidth.net`, etc. → ATT_Web IP
- WireGuard endpoint hostname → ATT_WireGuard IP

**Step 7 — Retire WAN (igc0)**

Once all services are verified on ATT, disable WAN NAT rules, remove port forward rules on WAN, and eventually disable the interface.

---

## Hardening Plan

The following items are recommended improvements, ordered by priority.

### Priority 1 — Re-enable Disabled Security Rules (Immediate)

All three security block rules on the WAN interface are currently disabled. These should be re-enabled immediately as they represent threat intelligence you have already configured but are not using.

1. Navigate to **Firewall → Rules → WAN**
2. Find rules: `Block DROP`, `Block EDROP`, and the GeoIP block rule
3. Click the enable toggle on each rule
4. Click **Apply Changes**

Repeat on the ATT interface once migrated.

### Priority 2 — Suricata IDS/IPS

Suricata is built into OPNsense but not yet configured. This is the most significant security gap — without it, there is no deep packet inspection or content-based threat detection.

**Setup steps:**

1. Go to **Services → Intrusion Detection → Administration**
2. Enable IDS/IPS, set interface to **ATT** (and WAN while active)
3. Set mode to **IPS** (inline blocking, not just alerting)
4. Under **Download**, enable the following rulesets:
   - `ET Open` — Proofpoint Emerging Threats (free, comprehensive)
   - `Abuse.ch SSL Blacklist` — malicious SSL certificate detection
   - `Feodo Tracker` — botnet C2 blocking
5. Under **Policies**, set default action to `drop` for high-severity rules
6. Click **Download & Update Rules**, then **Apply**

> ✓ Suricata complements CrowdSec well. CrowdSec handles IP reputation; Suricata handles traffic content inspection. They do not overlap.

### Priority 3 — Additional Blocklists

Add these URL table aliases to supplement Spamhaus DROP/EDROP:

| List | URL | Purpose |
|---|---|---|
| Feodo Tracker | https://feodotracker.abuse.ch/downloads/ipblocklist.txt | Botnet C2 IPs |
| Abuse.ch SSLBL | https://sslbl.abuse.ch/blacklist/sslipblacklist.txt | Malicious SSL IPs |
| Emerging Threats | https://rules.emergingthreats.net/fwrules/emerging-Block-IPs.txt | ET block list |

For each: **Firewall → Aliases → Add**, type `URL Table`, set refresh to 1 day. Then add a WAN block rule using each alias as the source.

### Priority 4 — dnscrypt-proxy (Encrypted DNS)

Encrypts DNS queries leaving the firewall and adds DNS-level malware/tracking blocklists.

1. Go to **System → Firmware → Plugins**, install `os-dnscrypt-proxy`
2. Navigate to **Services → DNSCrypt-Proxy**
3. Enable, set listen port to `5353`
4. Select resolvers: `cloudflare`, `quad9-dnscrypt-ip4-nofilter-pri` (or similar)
5. Enable DNSSEC validation
6. Update **System → Settings → General** — set DNS server to `127.0.0.1:5353`
7. Disable `DNS Allow Override` so the ISP cannot push DNS changes

### Priority 5 — os-git-backup

Automatically commits every OPNsense config change to a Git repository. Invaluable for auditing changes after an incident and for rapid recovery.

1. Go to **System → Firmware → Plugins**, install `os-git-backup`
2. Navigate to **System → Configuration → Git Backup**
3. Configure a Forgejo repository on Netgrimoire as the remote
4. Set SSH key for authentication
5. Enable automatic backup on config change

### Priority 6 — Syslog to Graylog

Syslog is not currently configured. Sending firewall logs to Graylog (already running at `http://graylog:9000`) enables centralized log analysis and alerting.

1. Go to **System → Settings → Logging → Remote**
2. Add a syslog destination: `graylog:514` (UDP) or use GELF input on Graylog
3. Enable logging for: Firewall, DHCP, VPN, Authentication, CrowdSec

---

## Known Issues & Action Items

| Item | Priority | Notes |
|---|---|---|
| Spamhaus DROP rule disabled | 🔴 High | Re-enable in Firewall → Rules → WAN |
| Spamhaus EDROP rule disabled | 🔴 High | Re-enable in Firewall → Rules → WAN |
| GeoIP block rule disabled | 🔴 High | Re-enable in Firewall → Rules → WAN |
| Suricata not configured | 🔴 High | Most significant security gap — configure with ET Open rules |
| Duplicate CrowdSec aliases | 🟡 Medium | crowdsec_blacklists and crowdsec_blocklists both do IPv4 — consolidate |
| WireGuard rule too permissive | 🟡 Medium | Allow-all from peers — scope per peer when needs are known |
| OPT3 interface unassigned | 🟡 Medium | Disable or assign a role |
| System DNS points to Google | 🟡 Medium | Should point to internal resolver or localhost after dnscrypt-proxy setup |
| No syslog configured | 🟡 Medium | Forward to Graylog for centralized logging |
| os-git-backup not installed | 🟡 Medium | Install for config change auditing |
| OpenVPN config unpopulated | 🟢 Low | Verify status — backup shows server+client but no details |
| ATT migration incomplete | 🟢 Low | In progress — see migration plan above |
| Family_Subnet alias empty | 🟢 Low | Populate or remove |
| Plex_Port_2 alias empty | 🟢 Low | Populate or remove |
| DHCP disabled on LAN | 🟢 Info | Intentional if using static IPs — verify |

---

## Related Documentation

- [Caddy Reverse Proxy](./caddy-reverse-proxy) — services exposed through the firewall
- [MailCow Mail Server](./mailcow) — mail server behind the firewall, dedicated WAN IP
- [WireGuard VPN](./wireguard) — peer configuration and access
- [Graylog](./graylog) — target for firewall syslog
- [CrowdSec](./crowdsec) — threat intelligence integration
