Networking advanced ⏱ 90 minutes

OPNsense: Enterprise Firewall for Your Homelab

Open-source firewall with IDS/IPS, VPN, and traffic shaping. Complete network security platform.

By homelabbing.io • 2025-12-16
#opnsense#firewall#router#security#ids

Introduction

OPNsense is a powerful, open-source firewall and routing platform based on FreeBSD. It provides enterprise-grade security features including intrusion detection/prevention (IDS/IPS), VPN capabilities, high-availability clustering, and advanced traffic shaping - all through an intuitive web interface. This comprehensive guide will help you deploy and configure OPNsense as the security cornerstone of your homelab.

What You’ll Learn

  • Installing OPNsense on bare metal and virtual machines
  • Configuring firewall rules and network segmentation
  • Setting up multiple VPN types (WireGuard, OpenVPN, IPsec)
  • Implementing IDS/IPS with Suricata
  • Deploying HAProxy for load balancing and SSL termination
  • Advanced traffic shaping and QoS
  • High availability and failover configurations
  • Monitoring and logging best practices
  • AI-powered security automation
  • Troubleshooting common issues

Why OPNsense?

Modern Architecture: Unlike its predecessor pfSense, OPNsense uses a modern codebase with inline patching, regular updates, and a commitment to open-source principles.

Enterprise Features: IDS/IPS, web filtering, two-factor authentication, high availability, VLAN management, and advanced routing - features typically found in commercial firewalls.

Active Development: Bi-weekly updates ensure the latest security patches and features. The development team is responsive and community-focused.

Hardware Flexibility: Runs on minimal hardware (2GB RAM) to enterprise servers. Virtual machine support makes testing and deployment easy.

Extensive Plugin Ecosystem: Add functionality with plugins: HAProxy, Nginx, Let’s Encrypt, Wireguard, Zenarmor (formerly Sensei), and many more.

Prerequisites

Hardware Requirements (Minimum):

  • CPU: 64-bit dual-core (Intel/AMD)
  • RAM: 2GB minimum (4GB+ recommended)
  • Storage: 40GB minimum (SSD recommended)
  • Network: 2x Gigabit NICs minimum (more for VLANs)

Recommended Specifications:

  • CPU: Quad-core Intel/AMD (AES-NI for VPN acceleration)
  • RAM: 8GB+ for IDS/IPS and plugins
  • Storage: 120GB+ SSD
  • Network: 4+ Gigabit NICs (dedicated interfaces per function)

Knowledge Requirements:

  • Advanced networking concepts (VLANs, routing, NAT)
  • Firewall rule logic and security principles
  • Basic FreeBSD/Unix command line
  • Understanding of network protocols (TCP/IP, DNS, DHCP)

Infrastructure:

  • Dedicated hardware or VM host
  • Network diagram and IP addressing scheme
  • Access to managed switch (for VLANs)
  • Modem/upstream internet connection

Time Commitment:

  • Initial installation: 30-45 minutes
  • Basic configuration: 1-2 hours
  • Advanced features: 4-8 hours
  • Ongoing maintenance: 30 minutes weekly

Understanding OPNsense Architecture

Network Design Fundamentals

Interface Types:

  1. WAN (Wide Area Network)

    • Internet-facing interface
    • Typically DHCP or static public IP
    • Ingress filtering and threat blocking
  2. LAN (Local Area Network)

    • Internal trusted network
    • DHCP server for clients
    • Default gateway for local devices
  3. DMZ (Demilitarized Zone)

    • Semi-trusted network for public services
    • Isolated from LAN for security
    • Web servers, mail servers, etc.
  4. OPT (Optional Interfaces)

    • Guest WiFi network
    • IoT devices
    • Management network
    • VPN clients

Example Network Topology:

Internet (WAN)
    ↓
OPNsense Firewall
    ├── LAN (192.168.1.0/24) - Trusted devices
    ├── DMZ (192.168.10.0/24) - Public services
    ├── IoT (192.168.20.0/24) - Smart home devices
    ├── Guest (192.168.30.0/24) - Guest WiFi
    └── VPN (10.0.0.0/24) - Remote access

Security Zones

Organize networks into security zones:

Zone: TRUSTED (LAN)

  • Full internet access
  • Access to internal services
  • Strict egress monitoring

Zone: DMZ

  • Limited outbound (specific ports)
  • No access to LAN
  • Publicly accessible services

Zone: UNTRUSTED (Guest, IoT)

  • Internet only
  • No LAN/DMZ access
  • Minimal privileges

Zone: MANAGEMENT

  • Administrative access only
  • No internet access
  • Isolated from all zones

Installation Guide

Method 1: Bare Metal Installation

Step 1: Download OPNsense ISO

# From https://opnsense.org/download/
# Choose architecture: amd64 (Intel/AMD 64-bit)
# Image type: dvd (full installer)

# Verify checksum
sha256sum OPNsense-*.iso
# Compare with published hash

Step 2: Create Bootable USB

# Linux
sudo dd if=OPNsense-*.iso of=/dev/sdX bs=4M status=progress
sync

# Windows - use Rufus or Etcher
# macOS
sudo dd if=OPNsense-*.iso of=/dev/diskX bs=1m

Step 3: Boot and Install

  1. Boot from USB drive
  2. Login: installer / opnsense
  3. Select “Install (UFS)”
  4. Choose target drive
  5. Swap partition: 2GB (or match RAM)
  6. Confirm installation
  7. Wait for completion (~10 minutes)
  8. Reboot and remove USB

Step 4: Initial Configuration

  1. Assign interfaces:

    • WAN: First NIC (typically em0 or igb0)
    • LAN: Second NIC
    • OPT: Additional NICs
  2. Set LAN IP:

    • Default: 192.168.1.1/24
    • Or custom: 192.168.10.1/24
  3. Enable DHCP on LAN (recommended)

  4. Set admin password

Step 5: Access Web Interface

Navigate to: https://192.168.1.1 (or your LAN IP)
Username: root
Password: opnsense (or what you set)

Method 2: Virtual Machine Installation

Proxmox VE:

# Upload OPNsense ISO to Proxmox
# Create VM:
VM ID: 100
Name: OPNsense-Firewall
OS: Other
ISO: OPNsense-*.iso

# Hardware:
CPU: 2 cores (4+ recommended)
RAM: 4096 MB (8192+ for IDS/IPS)
Network:
  - net0: vmbr0 (WAN)
  - net1: vmbr1 (LAN)
  - net2+: Additional interfaces

Storage: 40GB (virtio-scsi, SSD-backed)

# Advanced:
BIOS: OVMF (UEFI)
Machine: q35
CPU Type: host

# Start VM and proceed with installation

VMware ESXi:

Create New VM:
- Name: OPNsense
- Guest OS: FreeBSD 13 (64-bit)
- CPU: 2+ vCPUs
- RAM: 4+ GB
- Disk: 40GB (thin provisioned)
- Network Adapters: 2+ (each on separate portgroup)

Boot from ISO and install

VirtualBox:

Create VM:
- Type: BSD
- Version: FreeBSD (64-bit)
- RAM: 4096 MB
- Disk: 40 GB VDI

Settings:
- System → Enable EFI
- Network → Adapter 1: Bridged (WAN)
- Network → Adapter 2: Internal Network (LAN)
- Network → Adapter 3+: Additional networks

Attach ISO and install

Important VM Considerations:

  • Disable hardware checksum offloading if experiencing issues:

    System → Settings → Tunables
    Add: hw.igb.enable_aim = 0
    Add: hw.em.enable_aim = 0
  • Enable promiscuous mode on WAN adapter if using VLANs

Method 3: Cloud/Dedicated Server

Hetzner Cloud, Vultr, DigitalOcean:

# OPNsense doesn't have official cloud images
# Alternative: Install via recovery mode

1. Boot into rescue/recovery system
2. Download OPNsense installer script:
   curl -O https://raw.githubusercontent.com/opnsense/update/master/bootstrap/opnsense-bootstrap.sh

3. Run installer:
   sh ./opnsense-bootstrap.sh

4. Reboot into OPNsense

5. Configure via serial console or VNC

Initial Configuration Wizard

After first login, the Setup Wizard guides you through essential configuration.

Step 1: General Information

  • Hostname: opnsense
  • Domain: localdomain (or your domain)
  • Primary DNS: 1.1.1.1
  • Secondary DNS: 8.8.8.8

Step 2: Time Server

  • Timezone: Select your timezone
  • Time server: pool.ntp.org

Step 3: Configure WAN Interface

  • IPv4 Configuration Type: DHCP (or Static)
  • If Static:
    • IP Address: Your public IP
    • Subnet: /24 or appropriate
    • Gateway: ISP gateway IP
  • IPv6: DHCP6, SLAAC, or Static
  • Block RFC1918 Private Networks: Checked (security)
  • Block bogon networks: Checked (security)

Step 4: Configure LAN Interface

  • IP Address: 192.168.1.1 (or your choice)
  • Subnet Mask: 24 (255.255.255.0)

Step 5: Set Root Password

  • Choose strong password
  • Consider password manager
  • Enable 2FA later

Step 6: Reload Configuration

  • Review settings
  • Click “Reload”
  • Wait for services to restart

Post-Wizard Configuration:

System → Settings → Administration
- Protocol: HTTPS
- SSL Certificate: Generate self-signed (or use Let's Encrypt later)
- TCP Port: 443 (or custom for security)
- Session Timeout: 4 hours
- Console Menu: Keep enabled
- Secure Shell:
  - Enable: Yes
  - Login Group: admins
  - Password Authentication: Yes (disable after SSH key setup)
  - Permit Root Login: No

Firewall Rules Configuration

Understanding Firewall Rule Processing

Rule Evaluation Order:

  1. Rules processed top to bottom
  2. First match wins (stops processing)
  3. Default deny at end (implicit)

Rule Direction:

  • Interface-based: Rules applied on interface where traffic enters
  • Example: Traffic from LAN to WAN = rule on LAN interface

States:

  • OPNsense uses stateful firewall
  • Return traffic automatically allowed
  • Only create rules for initial connection direction

Basic Firewall Rules

LAN Interface Rules (Allow Internet):

Firewall → Rules → LAN → Add

1. Allow LAN to Internet
   Action: Pass
   Interface: LAN
   Protocol: any
   Source: LAN net
   Destination: any
   Description: Allow LAN to Internet

2. Block LAN to OPNsense Web GUI from specific IPs (optional)
   Action: Block
   Interface: LAN
   Protocol: TCP
   Source: LAN net
   Destination: LAN address
   Destination Port: 443
   Description: Block untrusted LAN devices from admin

WAN Interface Rules (Default Deny):

Default: Block all inbound
Only add rules for specific services:

1. Allow WAN HTTPS (if hosting web services)
   Action: Pass
   Interface: WAN
   Protocol: TCP
   Source: any
   Destination: WAN address
   Destination Port: 443
   Description: Allow HTTPS to web server

2. Allow OpenVPN
   Action: Pass
   Interface: WAN
   Protocol: UDP
   Source: any
   Destination: WAN address
   Destination Port: 1194
   Description: Allow OpenVPN connections

DMZ Rules (Restricted):

1. Allow DMZ outbound (specific ports only)
   Action: Pass
   Interface: DMZ
   Protocol: TCP
   Source: DMZ net
   Destination: any
   Destination Port: 80,443 (HTTP/HTTPS only)

2. Block DMZ to LAN
   Action: Block
   Interface: DMZ
   Protocol: any
   Source: DMZ net
   Destination: LAN net

Advanced Firewall Rules

Port Forward (NAT + Firewall Rule):

Firewall → NAT → Port Forward → Add

1. Web Server Port Forward
   Interface: WAN
   Protocol: TCP
   Source: any
   Destination: WAN address
   Destination Port: 80, 443
   Redirect Target IP: 192.168.10.10 (DMZ web server)
   Redirect Target Port: 80, 443
   Description: Forward HTTP/HTTPS to web server
   NAT Reflection: Enable
   Associated Filter Rule: Add associated filter rule

Outbound NAT (Manual):

Firewall → NAT → Outbound

Mode: Hybrid or Manual

1. LAN Outbound NAT
   Interface: WAN
   Source: 192.168.1.0/24
   Translation: Interface address
   Description: LAN to Internet NAT

2. DMZ Outbound NAT (different public IP if available)
   Interface: WAN
   Source: 192.168.10.0/24
   Translation: Alias_DMZ_Public_IP

Time-Based Rules:

1. Block social media during work hours
   Action: Block
   Interface: LAN
   Protocol: TCP
   Source: LAN net
   Destination: Alias_Social_Media_IPs
   Destination Port: 443
   Schedule: WorkHours (Mon-Fri 9AM-5PM)

GeoIP Blocking:

1. Block countries
   Action: Block
   Interface: WAN
   Protocol: any
   Source: GeoIP_China, GeoIP_Russia (example)
   Destination: any
   Description: Block traffic from specific countries

Prerequisites: Install GeoIP database
System → Settings → Miscellaneous → GeoIP Settings

VPN Configuration

WireGuard VPN Setup

Installation:

System → Firmware → Plugins
Search: os-wireguard
Install os-wireguard

Configuration:

VPN → WireGuard → Instances → Add

Instance Name: wg0
Public Key: (generated automatically)
Private Key: (generated automatically)
Listen Port: 51820
Tunnel Address: 10.0.0.1/24
Peers: (add after server config)

Apply

Add Peer (Client):

VPN → WireGuard → Peers → Add

Name: laptop-client
Public Key: <client_public_key>
Allowed IPs: 10.0.0.2/32
Endpoint: (leave blank for road warrior)
Persistent Keepalive: 25

Apply

Firewall Rules:

1. Allow WireGuard on WAN
   Interface: WAN
   Protocol: UDP
   Destination Port: 51820
   Action: Pass

2. Allow WireGuard clients to LAN
   Interface: WireGuard
   Source: 10.0.0.0/24
   Destination: LAN net
   Action: Pass

Client Configuration:

[Interface]
PrivateKey = <client_private_key>
Address = 10.0.0.2/24
DNS = 192.168.1.1

[Peer]
PublicKey = <server_public_key>
Endpoint = vpn.example.com:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25

OpenVPN Setup

Server Configuration:

VPN → OpenVPN → Servers → Add

Server Mode: Remote Access (SSL/TLS + User Auth)
Protocol: UDP
Device Mode: tun
Interface: WAN
Local Port: 1194
TLS Configuration: ✓ Use a TLS Key
Peer Certificate Authority: Create new CA
Server Certificate: Create new cert
DH Parameters: 2048 bit
Encryption Algorithm: AES-256-GCM
Auth Digest Algorithm: SHA256
Tunnel Network: 10.0.1.0/24
Local Network: 192.168.1.0/24
Concurrent Connections: 10
Compression: Enabled (LZ4)
Dynamic IP: ✓ Allow clients to use dynamic IPs
Topology: Subnet
DNS Servers: 192.168.1.1

Save

Firewall Rule:

Interface: WAN
Protocol: UDP
Destination Port: 1194
Action: Pass

User Management:

System → Access → Users → Add

Username: vpnuser
Password: <strong_password>
Group: VPN_Users
Certificate: Generate

OTP Seed: (optional 2FA)

Client Export:

VPN → OpenVPN → Client Export

Export Type: Windows Installer
Host Name: vpn.example.com
Use Random Local Port: ✓

Download installer

IPsec Site-to-Site VPN

Phase 1 (IKE):

VPN → IPsec → Tunnel Settings → Add Phase 1

Connection Method: Respond only (or default)
Key Exchange Version: IKEv2
Internet Protocol: IPv4
Interface: WAN
Remote Gateway: <remote_opnsense_public_ip>

Authentication:
  Method: Mutual PSK
  Pre-Shared Key: <strong_shared_secret>

Encryption Algorithm: AES 256
Hash Algorithm: SHA256
DH Group: 14 (2048 bit)
Lifetime: 28800

NAT Traversal: Auto
Dead Peer Detection: ✓ Enable

Phase 2 (ESP):

VPN → IPsec → Tunnel Settings → Phase 1 Entry → Add Phase 2

Mode: Tunnel IPv4
Local Network: LAN subnet (192.168.1.0/24)
Remote Network: Remote LAN (192.168.50.0/24)

Protocol: ESP
Encryption Algorithms: AES 256
Hash Algorithms: SHA256
PFS Key Group: 14 (2048 bit)
Lifetime: 3600

Firewall Rules:

1. Allow IPsec on WAN
   Protocol: ESP, UDP 500, UDP 4500
   Action: Pass

2. Allow IPsec traffic to LAN
   Interface: IPsec
   Source: Remote_LAN_Alias
   Destination: LAN net
   Action: Pass

Intrusion Detection & Prevention (IDS/IPS)

Suricata Setup

Installation:

System → Firmware → Plugins
Install: os-suricata

Services → Intrusion Detection → Administration

Basic Configuration:

Services → Intrusion Detection → Administration

General Settings:
  Enabled: ✓
  IPS Mode: ✓ (blocks threats)
  Promiscuous Mode: ✓
  Enable syslog alerts: ✓
  Pattern matcher: Hyperscan (Intel) or Aho-Corasick

Home Networks: 192.168.0.0/16, 10.0.0.0/8

Interfaces:
  ✓ WAN
  ✓ LAN (optional, for internal threats)

Apply

Rule Management:

Services → Intrusion Detection → Download → Select

Rulesets to enable:
  ✓ ET/Open (Emerging Threats)
  ✓ Abuse.ch
  ✓ Feodo Tracker
  ✓ ET/Pro (if you have subscription)

Download & Update

Schedule Updates:
  Frequency: Daily
  Time: 03:00

Apply

Rule Categories:

Services → Intrusion Detection → Policy

Create custom policy:

1. Default Policy: Alert (for testing)
2. After validation: Change to Drop (IPS mode)

Enable rule categories:
  ✓ Malware
  ✓ Exploit
  ✓ Scanning
  ✓ Web Attacks
  ✓ SQL Injection
  ✓ DDoS
  ✓ Brute Force

Disable noisy rules as needed

Performance Tuning:

Services → Intrusion Detection → Advanced

Memory:
  Use memcap: 256MB+

Detection:
  Max pending packets: 1024
  Detect Engine Profile: Medium

Capture:
  Checksum Validation: ✓

Apply and restart Suricata

Monitoring:

Services → Intrusion Detection → Alerts

View real-time alerts
Filter by severity, category, source/dest
Download logs for analysis

HAProxy Load Balancer & Reverse Proxy

Installation

System → Firmware → Plugins
Install: os-haproxy

Basic Reverse Proxy Setup

Backend Configuration:

Services → HAProxy → Settings → Virtual Services → Backend Pools → Add

Name: webservers_backend
Mode: HTTP
Servers:
  - Name: web1
    Address: 192.168.10.10
    Port: 80
    SSL: ✗

  - Name: web2
    Address: 192.168.10.11
    Port: 80

Health Checking:
  Check: ✓ Enable
  Check interval: 2000ms

Balance: roundrobin (or leastconn)

Apply

Frontend (Public Access):

Services → HAProxy → Settings → Virtual Services → Public Services → Add

Name: web_frontend
Description: Public web frontend
Status: Active

Listen Addresses:
  - 0.0.0.0:80
  - 0.0.0.0:443

Type: HTTP / HTTPS (SSL Offloading)
Default Backend: webservers_backend

SSL Offloading:
  - Certificate: Select SSL cert (or use Let's Encrypt)
  - Add: ✓ Add ACL for certificate

HTTP → HTTPS redirect:
  ✓ Use "Redirect" action

Apply

Advanced HAProxy Features

SSL Termination:

Services → HAProxy → Settings → Virtual Services → Public Services

SSL Certificates:
  - Generate via System → Trust → Certificates
  - Or import Let's Encrypt cert
  - Select certificate in frontend config

SSL Options:
  - Minimum SSL: TLSv1.2
  - Ciphers: ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384
  - HSTS: ✓ Enable

Load Balancing Algorithms:

Backend → Balance

- roundrobin: Even distribution
- leastconn: Least connections
- source: Hash by source IP (sticky sessions)
- uri: Hash by URI

Health Checks:

Backend → Health Checking

HTTP Check:
  Method: OPTIONS
  URI: /health
  Expected Status: 200

Advanced:
  Fall: 3 (mark down after 3 failures)
  Rise: 2 (mark up after 2 successes)
  Interval: 2s

ACLs (Access Control Lists):

Services → HAProxy → Settings → Rules & Checks → Conditions → Add

Name: api_path
Condition Type: Path starts with
Value: /api

Use in frontend:
  Actions → Add
  Condition: api_path
  Backend: api_backend

Traffic Shaping & QoS

Traffic Shaping (Bandwidth Management)

Enable Traffic Shaper:

Firewall → Shaper → Settings

Enable: ✓

Interfaces:
  WAN: <your_wan_speed> (e.g., 100 Mbit/s)
  LAN: 1000 Mbit/s

Create Queues:

Firewall → Shaper → Queues

1. VoIP Queue (Priority)
   Name: VoIP
   Priority: 7
   Bandwidth: 10% (or 2 Mbit/s minimum)

2. Streaming Queue
   Name: Streaming
   Priority: 4
   Bandwidth: 30%

3. Bulk Download Queue
   Name: Bulk
   Priority: 1
   Bandwidth: 40%

Assign Traffic to Queues:

Firewall → Shaper → Rules

1. VoIP Traffic
   Interface: LAN
   Protocol: UDP
   Destination Port: 5060, 5061 (SIP)
   Queue: VoIP

2. Video Streaming
   Interface: LAN
   Protocol: TCP
   Destination: Alias_Streaming_Services
   Queue: Streaming

3. Bulk Downloads
   Interface: LAN
   Protocol: TCP
   Destination Port: 80, 443
   Queue: Bulk (default catch-all)

CoDel (Controlled Delay) AQM

Firewall → Shaper → Settings → Advanced

Active Queue Management: CoDel

Parameters:
  Target: 5ms
  Interval: 100ms

Apply to all queues

Monitoring and Logging

Dashboard Customization

Lobby (Dashboard) → Configure Widgets

Useful widgets:
  - Interfaces (traffic graphs)
  - Gateway Status
  - System Information
  - Services
  - Firewall Log
  - CPU Graph
  - Memory Usage
  - Disk Usage
  - Thermal Sensors (if supported)

Log Management

Logging Settings:

System → Settings → Logging

Log Firewall: Default (or All)
Log Packets matched by default pass rules: ✗ (reduces noise)

GUI:
  Number of log entries: 500

Targets:
  ✓ Remote Syslog (optional)
  Server: 192.168.1.50
  Port: 514
  Protocol: UDP

View Logs:

System → Log Files → Firewall (Live View)
Filters:
  - Interface
  - Action (pass/block)
  - Protocol
  - Source/Destination

Download logs for analysis

Monitoring with Prometheus & Grafana

Install Prometheus Exporter:

System → Firmware → Plugins
Install: os-node_exporter

Services → Node Exporter
Enable: ✓
Listen Address: 0.0.0.0:9100

Firewall rule:
  Interface: LAN
  Source: Grafana_Server
  Destination: OPNsense
  Port: 9100
  Action: Pass

Grafana Dashboard:

Import dashboard ID: 11147 (OPNsense)
Configure Prometheus data source
Visualize:
  - Interface throughput
  - Firewall states
  - CPU/Memory usage
  - Gateway latency

High Availability (HA) Setup

CARP (Common Address Redundancy Protocol)

Prerequisites:

  • Two OPNsense firewalls (identical hardware recommended)
  • Direct connection between firewalls (sync interface)
  • Virtual IP addresses for each interface

Primary Firewall Configuration:

System → High Availability → Settings

Synchronize Config to IP: <secondary_firewall_ip>
Remote System Username: root
Remote System Password: <password>

Synchronize:
  ✓ Firewall Rules
  ✓ NAT
  ✓ Virtual IPs
  ✓ IPsec
  ✓ OpenVPN
  ✓ DHCP

Apply

CARP VIP Configuration:

Interfaces → Virtual IPs → Add

Type: CARP
Interface: LAN
Address: 192.168.1.1/24 (virtual IP)
Virtual IP Password: <strong_password>
VHID Group: 1
Advertising Frequency: 1
Description: LAN CARP VIP

Repeat for WAN, DMZ, etc.

Firewall Rules (Allow CARP):

Interface: LAN, WAN
Protocol: CARP
Source: Network
Destination: Network
Action: Pass

Testing Failover:

# On primary
System → High Availability → Status
  - Should show MASTER

# Disconnect primary WAN or LAN
# Secondary should become MASTER
# VIP should migrate to secondary

# Restore primary
# Should return to MASTER (preempt mode)

AI-Powered Security Automation

Automated Threat Response

#!/usr/bin/env python3
"""
OPNsense AI Security Monitor
Analyzes firewall logs for threats and auto-responds
"""

import requests
import json
from datetime import datetime, timedelta
from collections import Counter, defaultdict

class OPNsenseSecurityAI:
    def __init__(self, api_url, api_key, api_secret):
        self.api_url = api_url
        self.auth = (api_key, api_secret)
        self.threat_patterns = defaultdict(int)

    def get_firewall_log(self, limit=1000):
        """Fetch recent firewall log entries"""
        try:
            response = requests.get(
                f"{self.api_url}/api/diagnostics/firewall/log",
                auth=self.auth,
                params={'limit': limit},
                verify=False  # Use proper cert verification in production
            )
            return response.json()
        except Exception as e:
            print(f"Error fetching logs: {e}")
            return []

    def detect_port_scan(self, logs):
        """Detect port scanning attempts"""
        scan_threshold = 20  # ports per minute
        source_ports = defaultdict(set)

        for entry in logs:
            if entry.get('action') == 'block':
                src_ip = entry.get('src_ip')
                dst_port = entry.get('dst_port')
                source_ports[src_ip].add(dst_port)

        scanners = []
        for src_ip, ports in source_ports.items():
            if len(ports) > scan_threshold:
                scanners.append({
                    'ip': src_ip,
                    'ports_scanned': len(ports),
                    'severity': 'HIGH'
                })

        return scanners

    def detect_brute_force(self, logs):
        """Detect brute force login attempts"""
        attempt_threshold = 10
        source_attempts = Counter()

        # Common auth ports
        auth_ports = {22, 23, 3389, 21, 443, 5900}

        for entry in logs:
            if entry.get('dst_port') in auth_ports:
                source_attempts[entry.get('src_ip')] += 1

        brute_forcers = []
        for src_ip, count in source_attempts.items():
            if count > attempt_threshold:
                brute_forcers.append({
                    'ip': src_ip,
                    'attempts': count,
                    'severity': 'HIGH' if count > 50 else 'MEDIUM'
                })

        return brute_forcers

    def block_ip(self, ip_address, description='Auto-blocked by AI'):
        """Add IP to block list via API"""
        try:
            payload = {
                'alias': {
                    'name': f'AI_Block_{ip_address.replace(".", "_")}',
                    'type': 'host',
                    'content': ip_address,
                    'description': description,
                    'enabled': '1'
                }
            }

            response = requests.post(
                f"{self.api_url}/api/firewall/alias/addItem",
                auth=self.auth,
                json=payload,
                verify=False
            )

            if response.status_code == 200:
                # Apply changes
                requests.post(
                    f"{self.api_url}/api/firewall/alias/reconfigure",
                    auth=self.auth,
                    verify=False
                )
                print(f"✓ Blocked {ip_address}")
                return True

        except Exception as e:
            print(f"Error blocking IP: {e}")

        return False

    def analyze_and_respond(self):
        """Main analysis and auto-response loop"""
        print(f"Fetching firewall logs...")
        logs = self.get_firewall_log(limit=5000)

        if not logs:
            print("No logs to analyze")
            return

        print(f"Analyzing {len(logs)} log entries...\n")

        # Detect threats
        scanners = self.detect_port_scan(logs)
        brute_forcers = self.detect_brute_force(logs)

        report = f"""
{'='*70}
OPNsense AI Security Analysis
Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
{'='*70}

Port Scan Detection:
"""

        if scanners:
            report += f"  Found {len(scanners)} potential scanners:\n"
            for scanner in scanners:
                report += f"    - {scanner['ip']}: {scanner['ports_scanned']} ports scanned\n"

                # Auto-block severe cases
                if scanner['ports_scanned'] > 50:
                    self.block_ip(scanner['ip'], 'Port scan detected')
        else:
            report += "  No port scans detected\n"

        report += "\nBrute Force Detection:\n"

        if brute_forcers:
            report += f"  Found {len(brute_forcers)} brute force attempts:\n"
            for attacker in brute_forcers:
                report += f"    - {attacker['ip']}: {attacker['attempts']} attempts ({attacker['severity']})\n"

                # Auto-block high severity
                if attacker['severity'] == 'HIGH':
                    self.block_ip(attacker['ip'], 'Brute force detected')
        else:
            report += "  No brute force attempts detected\n"

        report += f"\n{'='*70}\n"

        return report

    def monitor_continuously(self, interval=300):
        """Continuous monitoring loop"""
        print(f"Starting continuous security monitoring (interval: {interval}s)\n")

        import time
        while True:
            try:
                report = self.analyze_and_respond()
                print(report)

                # Log to file
                with open('opnsense_security_log.txt', 'a') as f:
                    f.write(report)
                    f.write('\n')

                time.sleep(interval)

            except KeyboardInterrupt:
                print("\nMonitoring stopped by user")
                break
            except Exception as e:
                print(f"Error during monitoring: {e}")
                time.sleep(interval)

# Usage
if __name__ == "__main__":
    import sys

    ai_monitor = OPNsenseSecurityAI(
        api_url='https://192.168.1.1',
        api_key='your_api_key_here',
        api_secret='your_api_secret_here'
    )

    if len(sys.argv) > 1 and sys.argv[1] == 'monitor':
        ai_monitor.monitor_continuously(interval=300)
    else:
        report = ai_monitor.analyze_and_respond()
        print(report)

Generate API Credentials:

System → Access → Users → root → API Keys
Generate new key
Copy Key and Secret for script

Troubleshooting

Common Issues

Issue: Can’t access web interface

# Console login
Login as root

# Check if web service running
configctl webgui restart

# Reset admin password
passwd root

# Check firewall rules (allow LAN to 443)

Issue: No internet connectivity

# Check WAN status
Interfaces → WAN → Status
  - Should show IP address
  - Gateway should be reachable

# Test gateway
Diagnostics → Ping
  - Ping gateway IP
  - Ping 8.8.8.8

# Check DNS
Diagnostics → DNS Lookup
  - Query: google.com
  - Server: System default

# Restart interface
Interfaces → WAN → Disconnect/Connect

Issue: VPN not connecting

# WireGuard
Services → WireGuard → Status
  - Check peer status
  - Verify public keys match
  - Check firewall allows port 51820

# OpenVPN
Status → OpenVPN
  - View connection logs
  - Verify certificates valid
  - Check authentication

# IPsec
Status → IPsec → Status
  - Check Phase 1/2 status
  - Verify PSK matches
  - Confirm network settings

Performance Optimization

Tune FreeBSD sysctls:

System → Settings → Tunables

# Increase state table size
net.inet.ip.fw.dyn_max = 65536

# Increase firewall states
net.pf.states = 100000

# TCP optimizations
net.inet.tcp.sendbuf_max = 16777216
net.inet.tcp.recvbuf_max = 16777216

# Disable hardware checksum offload (VM only)
hw.igb.enable_aim = 0

Hardware acceleration:

System → Settings → Miscellaneous

Cryptographic & Thermal Hardware:
  ✓ AES-NI CPU-based Acceleration
  ✓ Intel QuickAssist Technology

(Requires compatible CPU)

Conclusion

OPNsense provides enterprise-grade firewall capabilities perfect for securing homelab environments. With features like IDS/IPS, multiple VPN options, high availability, and advanced traffic shaping, it delivers professional security on affordable hardware.

Key Takeaways

  • Enterprise features on homelab budget
  • Active development with regular updates
  • Extensive plugin ecosystem for extensibility
  • Modern architecture based on FreeBSD
  • High availability for critical deployments

Next Steps

Immediate actions:

  • Deploy OPNsense on dedicated hardware or VM
  • Configure basic firewall rules
  • Set up VPN for remote access
  • Enable logging and monitoring

Advanced exploration:

  • Implement IDS/IPS with Suricata
  • Deploy HAProxy for load balancing
  • Configure high availability
  • Integrate with monitoring stack

Additional Resources


Document Version: 1.0 Last Updated: December 16, 2025 Difficulty: Advanced Estimated Completion Time: 4-8 hours Maintenance Required: Weekly updates and monitoring