--- 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: `/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