Skip to content
Back to skills

Ops Opnsense

ASecurity

OPNsense configuration via Terraform. Trigger for interfaces, firewall, NAT, DHCP/DNS, aliases.

  • 5 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added May 28, 2026
ai-agentsgobashnodeterraformgitapisecuritydocumentation

Works with

  • cli
  • api

Security analysis

A100/100

Scanned September 28, 2026

npx -y skills add christopherlouet/claude-base --skill ops-opnsense --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Ops Opnsense?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Ops Opnsense
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/christopherlouet-ops-opnsense/badge)](https://www.skillsdirectory.com/skills/christopherlouet-ops-opnsense)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: ops-opnsense
description: OPNsense configuration via Terraform. Trigger for interfaces, firewall, NAT, DHCP/DNS, aliases.
argument-hint: "[component]"
---

# OPNsense Configuration (Terraform)

Complete guide to configure OPNsense declaratively with Terraform and the `browningluke/opnsense` provider.

## When to use this Skill

**Activate this skill to:**
- Configure OPNsense network interfaces (WAN, LAN, VLANs)
- Manage firewall rules
- Configure NAT and port forwarding
- Manage DHCP and DNS services
- Create aliases to simplify rules

**Do not use for:**
- Initial OPNsense installation (see manual documentation)
- VM provisioning (use `/ops:ops-proxmox`)
- Advanced OPNsense plugins (HAProxy, Suricata)

## Terraform Provider

| Attribute | Value |
|-----------|-------|
| **Provider** | `browningluke/opnsense` |
| **Version** | >= 0.11 |
| **Documentation** | https://registry.terraform.io/providers/browningluke/opnsense/latest/docs |
| **GitHub** | https://github.com/browningluke/terraform-provider-opnsense |

### Provider Configuration

```hcl
terraform {
  required_providers {
    opnsense = {
      source  = "browningluke/opnsense"
      version = "~> 0.11"
    }
  }
}

provider "opnsense" {
  uri                 = var.opnsense_uri        # https://192.168.10.1
  api_key             = var.opnsense_api_key    # Sensitive
  api_secret          = var.opnsense_api_secret # Sensitive
  allow_insecure = true                    # false in production
}
```

## Configuration Patterns

### 1. Network Interfaces

```hcl
# WAN interface (DHCP from ISP box)
resource "opnsense_interface" "wan" {
  device        = "vtnet0"
  description   = "WAN - Orange Box"
  ipv4_type     = "dhcp"
  block_private = true
  block_bogons  = true
}

# LAN interface (static IP)
resource "opnsense_interface" "lan" {
  device      = "vtnet1"
  description = "LAN - Local network"
  ipv4_type   = "static"
  ipv4_addr   = "192.168.10.1"
  ipv4_mask   = 24
}
```

### 2. Firewall Rules (CRITICAL: Anti-lockout)

```hcl
# MANDATORY: Anti-lockout rule (ALWAYS first)
resource "opnsense_firewall_filter" "anti_lockout" {
  interface        = "lan"
  direction        = "in"
  action           = "pass"
  protocol         = "tcp"
  source_net       = "lannet"
  destination_net  = "(self)"
  destination_port = "443"
  description      = "ANTI-LOCKOUT: Admin access"
  sequence         = 1
}

# Allow outbound HTTP/HTTPS
resource "opnsense_firewall_filter" "lan_to_web" {
  interface        = "lan"
  direction        = "in"
  action           = "pass"
  protocol         = "tcp"
  source_net       = "lannet"
  destination_net  = "any"
  destination_port = "80,443"
  description      = "Allow outbound HTTP/HTTPS"
  sequence         = 10
}

# Block everything else (deny by default)
resource "opnsense_firewall_filter" "lan_block_all" {
  interface   = "lan"
  direction   = "in"
  action      = "block"
  protocol    = "any"
  source_net  = "any"
  destination_net = "any"
  log         = true
  description = "Block and log everything else"
  sequence    = 65535
}
```

### 3. NAT / Port Forwarding

```hcl
# Port forward HTTPS to internal web server
resource "opnsense_nat_port_forward" "https_to_web" {
  interface        = "wan"
  protocol         = "tcp"
  source_net       = "any"
  source_port      = "443"
  destination_net  = "wanip"
  destination_port = "443"
  target           = "192.168.10.20"
  local_port       = "443"
  description      = "HTTPS to web server"
  nat_reflection   = "enable"
  filter_rule_association = "add-associated"
}

# SSH on non-standard port
resource "opnsense_nat_port_forward" "ssh_to_server" {
  interface        = "wan"
  protocol         = "tcp"
  source_net       = "any"
  source_port      = "2222"
  destination_net  = "wanip"
  destination_port = "2222"
  target           = "192.168.10.10"
  local_port       = "22"
  description      = "SSH to server (port 2222)"
}
```

### 4. DHCP/DNS Services

```hcl
# DHCP server on LAN
resource "opnsense_dhcp_v4_server" "lan" {
  interface   = "lan"
  enabled     = true
  range_from  = "192.168.10.100"
  range_to    = "192.168.10.200"
  gateway     = "192.168.10.1"
  dns_servers = ["192.168.10.1"]
  domain      = "home.local"
  lease_time  = 86400
}

# DHCP reservation
resource "opnsense_dhcp_v4_static_map" "server_web" {
  interface   = "lan"
  mac         = "00:11:22:33:44:55"
  ipaddr      = "192.168.10.20"
  hostname    = "server-web"
  description = "Main web server"
}

# DNS forwarder
resource "opnsense_unbound_forward" "cloudflare" {
  enabled  = true
  host     = "1.1.1.1"
  port     = 53
  priority = 10
}

# Local DNS entry
resource "opnsense_unbound_host_override" "server_web" {
  enabled  = true
  hostname = "server"
  domain   = "home.local"
  server   = "192.168.10.20"
}
```

### 5. Aliases

```hcl
# Server alias
resource "opnsense_firewall_alias" "servers_web" {
  name        = "SERVERS_WEB"
  type        = "host"
  content     = ["192.168.10.20", "192.168.10.21"]
  description = "Internal web servers"
}

# Port alias
resource "opnsense_firewall_alias" "ports_web" {
  name        = "PORTS_WEB"
  type        = "port"
  content     = ["80", "443", "8080"]
  description = "Web service ports"
}

# Use in a rule
resource "opnsense_firewall_filter" "to_web_servers" {
  interface        = "lan"
  action           = "pass"
  protocol         = "tcp"
  source_net       = "lannet"
  destination_net  = opnsense_firewall_alias.servers_web.name
  destination_port = opnsense_firewall_alias.ports_web.name
  description      = "Access to web servers"
}
```

## Security

### Mandatory Rules

1. **Anti-lockout** (sequence = 1)
   - ALWAYS present
   - Allows admin access from LAN
   - Never delete

2. **Deny by default** (sequence = 65535)
   - Block anything not explicitly allowed
   - Log to detect attempts

3. **Secure credentials**
   - Environment variables or terraform.tfvars
   - NEVER in code
   - NEVER committed

### Best Practices

| Practice | Why |
|----------|-----|
| Use aliases | Readability and maintainability |
| Document each rule | Easier audit |
| Log block rules | Intrusion detection |
| Test in lab | Avoid lockouts |
| Backup before apply | Rollback possible |

## ISP Box + OPNsense Architecture

```
┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│   Internet      │     │   Orange Box    │     │    OPNsense     │
│                 │────▶│   (192.168.1.1) │────▶│   WAN: DHCP     │
│                 │     │   DMZ Mode      │     │   LAN: .10.1    │
└─────────────────┘     └─────────────────┘     └────────┬────────┘
                                                         │
                                           ┌─────────────┴─────────────┐
                                           │                           │
                                    ┌──────┴──────┐             ┌──────┴──────┐
                                    │  Server     │             │   Client    │
                                    │  .10.20     │             │   DHCP      │
                                    └─────────────┘             └─────────────┘
```

### Orange Box DMZ Configuration

1. Access the Livebox: `http://192.168.1.1`
2. Network > NAT/PAT > DMZ
3. Enable DMZ to OPNsense WAN IP
4. All ports are redirected to OPNsense

## WireGuard VPN (P3)

WireGuard VPN server configuration:

```hcl
# WireGuard interface
resource "opnsense_wireguard_server" "vpn" {
  name         = "wg0"
  enabled      = true
  listen_port  = 51820
  tunnel_addr  = "10.10.10.1/24"
  dns          = "192.168.10.1"
  private_key  = var.wireguard_private_key  # Sensitive
}

# Peer (VPN client)
resource "opnsense_wireguard_peer" "laptop" {
  server_id   = opnsense_wireguard_server.vpn.id
  name        = "laptop-chris"
  public_key  = "CLIENT_PUBLIC_KEY"
  allowed_ips = "10.10.10.2/32"
}

# Firewall rule for WireGuard
resource "opnsense_firewall_filter" "wireguard_in" {
  interface        = "wan"
  direction        = "in"
  action           = "pass"
  protocol         = "udp"
  destination_port = "51820"
  description      = "WireGuard VPN"
}
```

## Prometheus Monitoring (P3)

### node_exporter Installation

1. Install the `node_exporter` package via OPNsense
2. System > Services > node_exporter
3. Enable and configure the port (9100)

### Prometheus Configuration

```yaml
# prometheus.yml
scrape_configs:
  - job_name: 'opnsense'
    static_configs:
      - targets: ['192.168.10.1:9100']
    metrics_path: /metrics
```

### Useful Metrics

| Metric | Description |
|--------|-------------|
| `node_network_receive_bytes_total` | Inbound traffic |
| `node_network_transmit_bytes_total` | Outbound traffic |
| `node_cpu_seconds_total` | CPU usage |
| `node_memory_MemAvailable_bytes` | Available memory |
| `node_filesystem_avail_bytes` | Disk space |

## Troubleshooting

### API connection error

```bash
# Test the connection
curl -k -u "api-key:api-secret" \
  "https://192.168.10.1/api/core/firmware/status"

# Check:
# 1. API enabled (System > Settings > Administration)
# 2. API user with permissions
# 3. Firewall is not blocking
# 4. HTTPS certificate
```

### Lockout (lost access)

```bash
# Via Proxmox/local console
pfctl -d                    # Disable firewall
# Fix via web interface
pfctl -e                    # Re-enable firewall
```

### Terraform state out of sync

```bash
# Import existing resource
terraform import opnsense_firewall_filter.rule "uuid"

# Refresh
terraform refresh

# Force recreation
terraform taint opnsense_firewall_filter.rule
terraform apply
```

## Available Templates

Templates are in `.claude/templates/opnsense/`:

| Template | Description |
|----------|-------------|
| `provider-template.tf` | Provider configuration |
| `interfaces-module.tf` | WAN/LAN interfaces |
| `firewall-module.tf` | Firewall rules |
| `nat-module.tf` | NAT/port forward |
| `services-module.tf` | DHCP/DNS |
| `aliases-module.tf` | Address groups |
| `examples/orange-box-dmz/` | Complete example |

## Resources

- [OPNsense Documentation](https://docs.opnsense.org/)
- [Terraform Provider](https://registry.terraform.io/providers/browningluke/opnsense/latest/docs)
- [OPNsense API](https://docs.opnsense.org/development/api.html)
- [WireGuard OPNsense](https://docs.opnsense.org/manual/how-tos/wireguard-client.html)

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.