OPNsense Unbound Settings

This role configures the general and advanced Unbound DNS resolver settings in OPNsense via the REST API.

Ansible DHCP DNS HTTPS JSON OPNsense REST API SSL

OPNsense Unbound Settings Role

Overview

This role configures the general and advanced Unbound DNS resolver settings in OPNsense via the REST API.

Purpose

  • DNS Configuration: Configure Unbound listening ports and interfaces
  • Security: Enable DNSSEC validation and privacy settings
  • Performance: Configure caching, prefetching, and performance tuning
  • Logging: Configure DNS query and reply logging
  • Code as Configuration: Define Unbound settings in YAML
  • API-Based: Reliable automation via OPNsense REST API
  • Idempotent: Safe to run multiple times

Requirements

  • Ansible 2.9 or higher
  • OPNsense firewall with API access enabled
  • API key and secret stored in Ansible Vault
  • Network connectivity to OPNsense (VLAN10)
  • OPNsense user with Unbound permissions

Role Variables

Required Variables

VariableRequiredDescription
vault_opnsense_bjoffrey_user_api_keyYesOPNsense API key (in vault)
vault_opnsense_bjoffrey_user_api_secretYesOPNsense API secret (in vault)
opnsense_unbound_settings_generalYesGeneral Unbound settings
opnsense_unbound_settings_advancedYesAdvanced Unbound settings

Optional Variables

VariableDefaultDescription
opnsense_unbound_settings_validate_certstrueValidate SSL certificates

General Settings Structure

opnsense_unbound_settings_general:
  enabled: "1"              # Enable Unbound (1) or disable (0)
  port: "53"                # DNS listening port
  stats: "0"                # Enable statistics (0 or 1)
  active_interface:         # Interfaces to listen on (list)
    - opt1                  # VLAN10Management
    - opt2                  # VLAN12Servers
  dnssec: "0"               # Enable DNSSEC validation (0 or 1)
  dns64: "0"                # Enable DNS64 (0 or 1)
  dns64prefix: ""           # DNS64 prefix (if enabled)
  noarecords: "0"           # Do not generate A records from AAAA
  regdhcp: "0"              # Register DHCP leases in DNS
  regdhcpdomain: ""         # Domain for DHCP registrations
  regdhcpstatic: "0"        # Register DHCP static mappings
  noreglladdr6: "0"         # Don't register IPv6 link-local
  noregrecords: "0"         # Don't register system A/AAAA records
  txtsupport: "0"           # Enable TXT record support
  cacheflush: "0"           # Flush cache on reload
  safesearch: "0"           # Enable SafeSearch for Google/YouTube/Bing/DuckDuckGo
  local_zone_type: "transparent"  # Local zone type
  outgoing_interface:       # Interfaces for outgoing queries (list)
    - wan
  enable_wpad: "0"          # Enable WPAD support

Advanced Settings Structure

opnsense_unbound_settings_advanced:
  hideidentity: "0"         # Hide server identity
  hideversion: "0"          # Hide server version
  prefetch: "0"             # Enable prefetching
  prefetchkey: "0"          # Enable DNSKEY prefetching
  dnssecstripped: "0"       # Log DNSSEC stripped responses
  aggressivensec: "0"       # Aggressive NSEC use
  serveexpired: "0"         # Serve expired cache entries
  serveexpiredreplyttl: ""  # TTL for expired replies
  serveexpiredttl: ""       # Max TTL for expired entries
  serveexpiredttlreset: "0" # Reset TTL to this on serve expired
  serveexpiredclienttimeout: ""  # Client timeout for serve expired
  qnameminstrict: "0"       # Strict QNAME minimization
  extendedstatistics: "0"   # Extended statistics
  logqueries: "0"           # Log DNS queries
  logreplies: "0"           # Log DNS replies
  logtagqueryreply: "0"     # Tag query/reply logs
  logservfail: "0"          # Log SERVFAIL responses
  loglocalactions: "0"      # Log local zone actions
  logverbosity: "1"         # Log verbosity level (0-5)
  valloglevel: "0"          # Validation log level (0-2)
  privateaddress:           # RFC1918 and other private addresses (list)
    - "10.x.x.x/8"
    - "172.16.x.x/12"
    - "192.168.x.x/16"
  msgcachesize: ""          # Message cache size
  rrsetcachesize: ""        # RRset cache size
  outgoingnumtcp: ""        # Outgoing TCP connections
  incomingnumtcp: ""        # Incoming TCP connections
  numqueriesperthread: ""   # Queries per thread
  outgoingrange: ""         # Outgoing port range
  jostletimeout: ""         # Jostle timeout
  discardtimeout: ""        # Discard timeout
  cachemaxttl: ""           # Maximum cache TTL
  cachemaxnegativettl: ""   # Maximum negative cache TTL
  cacheminttl: ""           # Minimum cache TTL
  infrahostttl: ""          # Infrastructure host TTL
  infrakeepprobing: "0"     # Keep probing infrastructure
  infracachenumhosts: ""    # Infrastructure cache hosts
  unwantedreplythreshold: "" # Unwanted reply threshold

Interface Codes

CodeInterface Name
opt9LAN
opt1VLAN10Management
opt2VLAN12Servers
opt3VLAN14Desktops
opt4VLAN16WifiTrusted
opt5VLAN18WifiGuest
opt6VLAN20WifiCCTV
opt7VLAN22EthernetGuest
wanWAN
opt8WG0 (WireGuard)

Local Zone Types

TypeDescription
transparentNormal resolution (default)
always_nxdomainAlways return NXDOMAIN
always_refuseAlways refuse queries
always_transparentAlways resolve normally
denyDrop queries silently
informLog and resolve normally
inform_denyLog and drop
nodefaultNo default local zones
refuseRefuse queries with error
staticOnly serve local data
typetransparentResolve except for local overrides

Log Verbosity Levels

LevelDescription
0No logging
1Operational information (Default)
2Detailed operational information
3Query level information
4Algorithm level information
5Client identification for cache misses

Dependencies

This role has no dependencies on other Ansible roles, but requires:

  • OPNsense firewall with API enabled
  • Unbound DNS service enabled
  • API key with Unbound management permissions
  • Ansible Vault for storing API credentials

Example Playbook

Basic Usage

---
- name: Configure OPNsense Unbound Settings
  hosts: mint-vm
  gather_facts: false

  vars_files:
    - ../../roles/opnsense_unbound_settings/vars/settings.yml

  tasks:
    - name: Configure Unbound settings
      ansible.builtin.include_role:
        name: opnsense_unbound_settings

Inline Variables

---
- name: Configure Unbound Settings
  hosts: mint-vm
  gather_facts: false

  vars:
    opnsense_unbound_settings_general:
      enabled: "1"
      port: "53"
      stats: "1"
      active_interface:
        - opt1
        - opt2
        - opt3
      dnssec: "1"
      cacheflush: "1"
      local_zone_type: "transparent"
      outgoing_interface:
        - wan

    opnsense_unbound_settings_advanced:
      prefetch: "1"
      aggressivensec: "1"
      logqueries: "1"
      logreplies: "1"
      logverbosity: "1"
      privateaddress:
        - "10.x.x.x/8"
        - "172.16.x.x/12"
        - "192.168.x.x/16"

  roles:
    - opnsense_unbound_settings

What This Role Does

  1. Fetches existing config via /api/unbound/settings/get
  2. Compares with desired config (general and advanced settings)
  3. Updates if different via /api/unbound/settings/set
  4. Reconfigures Unbound via /api/unbound/service/reconfigure
  5. Displays summary of settings status

OPNsense API Endpoints

Get Unbound Configuration

GET /api/unbound/settings/get
Authorization: Basic (API key:secret)

Returns current Unbound configuration.

Update Unbound Configuration

POST /api/unbound/settings/set
Authorization: Basic (API key:secret)
Content-Type: application/json

Request body:

{
  "unbound": {
    "general": {
      "enabled": "1",
      "port": "53",
      "stats": "1",
      "active_interface": "opt1,opt2,opt3",
      "dnssec": "1",
      "local_zone_type": "transparent",
      "outgoing_interface": "wan"
    },
    "advanced": {
      "prefetch": "1",
      "logqueries": "1",
      "logverbosity": "1",
      "privateaddress": "10.x.x.x/8,172.16.x.x/12,192.168.x.x/16"
    }
  }
}

Reconfigure Unbound Service

POST /api/unbound/service/reconfigure
Authorization: Basic (API key:secret)

Applies Unbound configuration changes.

Configuration Examples

Basic DNS Server

opnsense_unbound_settings_general:
  enabled: "1"
  port: "53"
  active_interface:
    - opt1
  dnssec: "0"
  local_zone_type: "transparent"
  outgoing_interface:
    - wan

opnsense_unbound_settings_advanced:
  logverbosity: "1"
  privateaddress:
    - "10.x.x.x/8"
    - "172.16.x.x/12"
    - "192.168.x.x/16"

Secure DNS with DNSSEC

opnsense_unbound_settings_general:
  enabled: "1"
  port: "53"
  active_interface:
    - opt1
    - opt2
    - opt3
  dnssec: "1"
  cacheflush: "1"
  local_zone_type: "transparent"
  outgoing_interface:
    - wan

opnsense_unbound_settings_advanced:
  aggressivensec: "1"
  dnssecstripped: "1"
  logqueries: "1"
  logreplies: "1"
  logverbosity: "1"
  valloglevel: "1"
  privateaddress:
    - "10.x.x.x/8"
    - "172.16.x.x/12"
    - "192.168.x.x/16"

High Performance

opnsense_unbound_settings_general:
  enabled: "1"
  port: "53"
  stats: "1"
  active_interface:
    - opt1
    - opt2
  dnssec: "1"
  cacheflush: "0"
  local_zone_type: "transparent"
  outgoing_interface:
    - wan

opnsense_unbound_settings_advanced:
  prefetch: "1"
  prefetchkey: "1"
  aggressivensec: "1"
  serveexpired: "1"
  serveexpiredttl: "86400"
  logqueries: "0"
  logreplies: "0"
  logverbosity: "0"
  privateaddress:
    - "10.x.x.x/8"
    - "172.16.x.x/12"
    - "192.168.x.x/16"

Security Considerations

  • API Credentials: Stored in Ansible Vault
  • HTTPS: Uses SSL/TLS for API calls
  • Basic Auth: API key/secret authentication
  • Certificate Validation: Enabled by default
  • DNSSEC: Validates DNS responses when enabled
  • Privacy: Can hide server identity and version

Troubleshooting

DNS resolution not working

Cause: Unbound disabled or wrong interface configuration

Solution: Check enabled: "1" and verify active_interface includes correct interfaces

DNSSEC validation failures

Cause: Clock skew or upstream DNS not supporting DNSSEC

Solution: Verify system time is correct, check upstream DNS servers

Slow DNS resolution

Cause: Prefetching disabled or cache too small

Solution: Enable prefetch: "1" and consider increasing cache sizes

Changes not applying

Cause: Reconfigure not triggered

Solution: Verify the role calls /api/unbound/service/reconfigure after updates

Best Practices

  1. Enable DNSSEC: Use dnssec: "1" for secure DNS resolution
  2. Configure interfaces: Only listen on necessary internal interfaces
  3. Use WAN for outgoing: Set outgoing_interface to WAN only
  4. Enable logging: Use logqueries: "1" for troubleshooting (disable in production)
  5. Private addresses: Keep RFC1918 addresses in privateaddress for security
  6. Prefetching: Enable for frequently accessed domains to improve performance

This role works well with:

  • opnsense_unbound_dnsbl: Configure DNS blocklists
  • opnsense_unbound_host_overrides: Manage DNS host overrides
  • opnsense_firewall: Configure firewall rules for DNS traffic

License

MIT

Author

Created for homelab infrastructure management.