# Configuring DoT with Unbound and Pi-hole on OPNsense

The configuration described using OPNsense’s Unbound DNS resolver set up with DNS over TLS (DoT) to encrypt all DNS queries, combined with Pi-hole on the same host to provide network-wide ad-blocking, with strict firewall rules and DNS redirect rules to prevent leaks is currently one of the most private and secure DNS setups available for a home or small office network.

### Potential Additional Privacy Enhancements

* Using a self-hosted, fully recursive Unbound instance on OPNsense without forwarding (making your own DNS root queries) enhances privacy but may require more maintenance and resources.
* Combining DNS over HTTPS (DoH) alongside or instead of DoT could obscure DNS traffic further within HTTPS traffic, although OPNsense natively supports DoT best.
* Regularly updating blocklists in Pi-hole and enabling DNSSEC validation in Unbound adds further robustness.
* Using privacy-focused upstream DNS providers (e.g., Quad9, Cloudflare with privacy features) is recommended.

***

### Overview

This setup represents a strong privacy-first DNS architecture for most users. It securely encrypts DNS, controls DNS traffic flow on the network, and filters unwanted content, all with open-source components and configurable controls.

## Part 1: Enable and Configure DNS over TLS (DoT) with Unbound on OPNsense <a href="#part-1-enable-and-configure-dns-over-tls-dot-with" id="part-1-enable-and-configure-dns-over-tls-dot-with"></a>

1. **Enable Unbound DNS Resolver:**
   * Log into OPNsense Web UI.
   * Navigate to **Services > Unbound DNS > General**.
   * Check **Enable Unbound** and save.
2. **Add Upstream DNS over TLS Servers:**
   * Go to **Services > Unbound DNS > DNS over TLS**.
   * Click **+ Add** and input trusted DNS servers supporting DoT (Cloudflare, Quad9, Google, etc.).
   * Leave **Domain** blank and enable **Verify CN**.
   * Save and apply.
3. **Configure Unbound General Settings:**
   * Enable **DNSSEC Support** for response validation.
   * Optionally uncheck **Use System Nameservers** to force use of configured DoT servers.
   * Save and apply.
4. **Restart Unbound:**
   * Restart Unbound under **Services > Unbound DNS**.

***

## Part 2: Install and Integrate Pi-hole with OPNsense Unbound DNS <a href="#part-2-install-and-integrate-pi-hole-with-opnsense" id="part-2-install-and-integrate-pi-hole-with-opnsense"></a>

1. **Install Pi-hole and Assign Static IP:**
   * Deploy Pi-hole on a LAN device or VM.
   * Assign a **static IP** (example: `192.168.1.10`).
   * Reserve this IP in OPNsense DHCP.
2. **Configure Pi-hole Upstream DNS:**
   * Access Pi-hole Admin UI.
   * Go to **Settings > DNS**.
   * Set upstream DNS server to OPNsense LAN IP (`192.168.1.1`).
   * Add fallback DNS servers (Cloudflare, Quad9, etc.).
   * Optionally enable **Conditional Forwarding** with LAN subnet and OPNsense IP.
3. **Configure Interface and Requests in Pi-hole:**
   * Enable **Respond only on interface** for Pi-hole interface.
   * Adjust/request settings for multi-VLAN use if applicable.
4. **Configure OPNsense DHCP to Use Pi-hole DNS:**
   * Go to **Services > DHCPv4 > LAN**.
   * Enter Pi-hole IP (`192.168.1.10`) as DNS server.
   * In **System > Settings > General**, uncheck **Allow DNS server list to be overridden by DHCP/PPP on WAN**.
   * Save and apply.
5. **Test Pi-hole Integration:**
   * Renew DHCP leases on clients.
   * Verify clients use Pi-hole for DNS.
   * Confirm Pi-hole receives and logs queries.
   * Test local hostname resolution if conditional forwarding enabled.

***

## Part 3: Firewall Rules and CLI Commands for DNS Traffic Control <a href="#part-3-firewall-rules-and-cli-commands-for-dns-tra" id="part-3-firewall-rules-and-cli-commands-for-dns-tra"></a>

### Rule 1: Allow Pi-hole to Query OPNsense Unbound DNS

**Description:**

* This rule permits DNS traffic (TCP/UDP port 53) from Pi-hole’s IP to OPNsense LAN IP running Unbound.
* Ensures Pi-hole can forward DNS requests to OPNsense.

**Settings:**

* Action: Pass
* Interface: LAN
* Protocol: TCP/UDP
* Source: Pi-hole IP (`192.168.1.10`)
* Destination: This firewall (OPNsense LAN IP)
* Destination Port: 53
* Description: Allow Pi-hole DNS queries to OPNsense Unbound
* Place this rule at the top.

**CLI Command:**

```bash
opn-cli firewall rule create \
  --interface lan \
  --action pass \
  --protocol tcp/udp \
  --source 192.168.1.10 \
  --destination <OPNsense LAN IP> \
  --destination-port 53 \
  --description "Allow Pi-hole DNS queries to Unbound" \
  --enabled true
```

*Replace IP addresses accordingly.*

***

### Rule 2: Block DNS Bypass from Other LAN Clients

**Description:**

* Blocks all DNS queries (port 53) from LAN clients except those allowed by previous rules.
* Prevents clients from bypassing Pi-hole for DNS resolution.

**Settings:**

* Action: Block
* Interface: LAN
* Protocol: TCP/UDP
* Source: LAN net (all clients)
* Destination: Any
* Destination Port: 53
* Description: Block DNS bypassing Pi-hole

**CLI Command:**

```bash
opn-cli firewall rule create \
  --interface lan \
  --action block \
  --protocol tcp/udp \
  --source lan-net \
  --destination any \
  --destination-port 53 \
  --description "Block DNS bypassing Pi-hole" \
  --enabled true
```

***

### Rule 3: Allow OPNsense Outbound DoT Queries on WAN Interface

**Description:**

* Allows outbound TCP traffic on port 853 from OPNsense to upstream DoT servers to enable encrypted DNS queries.

**Settings:**

* Action: Pass
* Interface: WAN
* Protocol: TCP
* Source: This firewall (OPNsense itself)
* Destination: Upstream DoT server IPs or Any
* Destination Port: 853
* Description: Allow OPNsense Unbound DNS over TLS outbound

**CLI Command:**

```bash
opn-cli firewall rule create \
  --interface wan \
  --action pass \
  --protocol tcp \
  --source 'this firewall' \
  --destination any \
  --destination-port 853 \
  --description "Allow OPNsense Unbound DNS over TLS outbound" \
  --enabled true
```

***

## Part 4: Optional NAT Redirect Rule to Force DNS Requests to Pi-hole <a href="#part-4-optional-nat-redirect-rule-to-force-dns-req" id="part-4-optional-nat-redirect-rule-to-force-dns-req"></a>

**Description:**

* Redirects all DNS (port 53) traffic from LAN clients to Pi-hole.
* Enforces DNS queries use Pi-hole despite client DNS settings.

**Settings:**

* Interface: LAN
* Protocol: TCP/UDP
* Source: LAN net
* Destination: LAN net or Any
* Destination Port: 53
* Redirect Target IP: Pi-hole IP (e.g., `192.168.1.10`)
* Redirect Target Port: 53
* Description: Redirect DNS traffic to Pi-hole

**CLI Command:**

```bash
opn-cli nat rule add \
  --interface lan \
  --protocol tcp/udp \
  --source lan-net \
  --destination lan-net \
  --destination-port 53 \
  --redirect-address 192.168.1.10 \
  --redirect-port 53 \
  --description "Redirect DNS traffic to Pi-hole" \
  --enabled true
```

***

## Firewall Rule Order Summary After Parts 3 & 4 <a href="#part-4a-firewall-rule-order-summary-after-parts-3" id="part-4a-firewall-rule-order-summary-after-parts-3"></a>

<table data-full-width="true"><thead><tr><th width="88">Order</th><th>Rule Purpose</th><th width="109">Interface</th><th width="92">Action</th><th>Protocol</th><th width="99">Source</th><th>Destination</th><th width="96">Port(s)</th><th>Description</th></tr></thead><tbody><tr><td>1</td><td>Allow Pi-hole DNS queries to OPNsense Unbound</td><td>LAN</td><td>Pass</td><td>TCP/UDP</td><td>Pi-hole IP</td><td>OPNsense LAN IP</td><td>53</td><td>Allow Pi-hole DNS queries</td></tr><tr><td>2</td><td>Block DNS bypass from other LAN clients</td><td>LAN</td><td>Block</td><td>TCP/UDP</td><td>LAN net</td><td>Any</td><td>53</td><td>Block DNS bypassing Pi-hole</td></tr><tr><td>3</td><td>(Optional) NAT redirect all DNS to Pi-hole</td><td>LAN</td><td>NAT</td><td>TCP/UDP</td><td>LAN net</td><td>LAN net</td><td>53</td><td>Redirect DNS traffic to Pi-hole</td></tr><tr><td>4</td><td>Allow OPNsense outbound DoT queries</td><td>WAN</td><td>Pass</td><td>TCP</td><td>This firewall</td><td>Upstream DoT IPs</td><td>853</td><td>Allow DNS over TLS outbound</td></tr></tbody></table>

***

## Part 5: Prevent DNS Leaks from OPNsense Host Itself <a href="#part-5-prevent-dns-leaks-from-opnsense-host-itself" id="part-5-prevent-dns-leaks-from-opnsense-host-itself"></a>

### Step 1: Clear External DNS Servers from System Settings

* Navigate to **System > Settings > General**.
* Remove any DNS servers listed.
* Uncheck **Allow DNS server list to be overridden by DHCP/PPP on WAN**.
* Save settings.

### Step 2: Configure Unbound to Listen on Loopback and LAN

* Go to **Services > Unbound DNS > General**.
* Set **Network Interfaces** to include `127.0.0.1` and LAN IP.
* Save and apply.

### Step 3: Block OPNsense Host Direct DNS Requests to External DNS

**Description:**

* Block outbound DNS (port 53 TCP/UDP) from the OPNsense host to prevent DNS leaks outside Unbound.

**CLI Command:**

```bash
opn-cli firewall rule create \
  --interface wan \
  --action block \
  --protocol tcp/udp \
  --source 'this firewall' \
  --destination any \
  --destination-port 53 \
  --description "Block OPNsense host direct DNS leaks" \
  --enabled true
```

### Step 4 (Optional): Allow DNS Queries to Localhost Only

**Description:**

* Allow OPNsense to query only its local Unbound DNS resolver via loopback.

**CLI Command:**

```bash
opn-cli firewall rule create \
  --interface wan \
  --action pass \
  --protocol tcp/udp \
  --source 'this firewall' \
  --destination 127.0.0.1 \
  --destination-port 53 \
  --description "Allow OPNsense host DNS to localhost" \
  --enabled true
```

### Step 5: Configure Services to Use Local DNS

This is a manual, configuration-specific step; OPNsense doesn't enforce this automatically, so regular review is recommended especially after adding new services or plugins.

1. **Identify Services or Plugins that Use DNS:**
   * Common services include VPN clients, proxy servers, monitoring tools, or packages installed on OPNsense.
   * Examples: OpenVPN client, Snort/Suricata, pfBlockerNG, or third-party plugins installed via the OPNsense interface.
2. **Access Each Service’s Configuration:**
   * In the OPNsense Web UI, navigate to the specific service/plugin configuration page.
   * Look for DNS-related settings or name server fields.
3. **Set DNS Server to Local Unbound:**
   * Change any DNS server IPs from external IPs (example: 9.9.9.9) to:
     * `127.0.0.1` (localhost), or
     * the OPNsense LAN IP address on which Unbound DNS resolver is listening (e.g., `192.168.1.1`).
   * Save and apply the changes.
4. **Verify That Services Use Local DNS:**
   * Use system logs or service-specific diagnostic pages to confirm DNS queries are resolved via the local Unbound.
   * This ensures DNS resolution remains encrypted and consistent with your DNS over TLS setup.
5. **Check for Hardcoded External DNS in Config Files (Optional):**
   * For deeper inspection, SSH into OPNsense and review service config files in `/usr/local/etc` or `/usr/local/opnsense`.
   * Replace any hardcoded external DNS IPs with `127.0.0.1` or LAN IP.

***

## Rule Order Summary After Parts 3, 4 & 5 <a href="#part-4a-firewall-rule-order-summary-after-parts-3" id="part-4a-firewall-rule-order-summary-after-parts-3"></a>

<table data-full-width="true"><thead><tr><th width="88">Order</th><th width="116">Interface</th><th width="90">Action</th><th width="109">Protocol</th><th>Source</th><th width="205">Destination</th><th width="87">Port(s)</th><th>Description</th></tr></thead><tbody><tr><td>1</td><td>LAN</td><td>Pass</td><td>TCP/UDP</td><td>Pi-hole IP (e.g., 192.168.1.10)</td><td>This firewall (OPNsense LAN IP)</td><td>53</td><td>Allow Pi-hole DNS queries to Unbound</td></tr><tr><td>2</td><td>LAN</td><td>Block</td><td>TCP/UDP</td><td>LAN net (all clients)</td><td>Any</td><td>53</td><td>Block DNS bypass attempts to servers other than Pi-hole</td></tr><tr><td>3</td><td>LAN</td><td>NAT</td><td>TCP/UDP</td><td>LAN net</td><td>LAN net</td><td>53</td><td>(Optional) Redirect all DNS queries to Pi-hole</td></tr><tr><td>4</td><td>WAN</td><td>Pass</td><td>TCP</td><td>This firewall (OPNsense host)</td><td>Upstream DoT IPs or Any</td><td>853</td><td>Allow outbound DNS over TLS (TCP/853) queries from OPNsense</td></tr><tr><td>5</td><td>WAN</td><td>Block</td><td>TCP/UDP</td><td>This firewall (OPNsense host)</td><td>Any external addresses</td><td>53</td><td>Block direct DNS queries from OPNsense to external DNS servers (prevent leaks)</td></tr><tr><td>6</td><td>WAN</td><td>Pass</td><td>TCP/UDP</td><td>This firewall (OPNsense host)</td><td>127.0.0.1 (loopback)</td><td>53</td><td>(Optional) Allow DNS queries from OPNsense host to local Unbound</td></tr></tbody></table>

### Rules by guide sections:

<table><thead><tr><th>Step # in Guide</th><th width="320">Description</th><th>Table Rule #s</th></tr></thead><tbody><tr><td>Part 3: Firewall Rules</td><td>Allow Pi-hole DNS / Block bypass DNS / DoT</td><td>1, 2, 4</td></tr><tr><td>Part 4: NAT Redirect Rule</td><td>Optional NAT redirect DNS to Pi-hole</td><td>3</td></tr><tr><td>Part 5: Host Leak Rules</td><td>Block host direct DNS leaks, allow localhost</td><td>5, 6</td></tr></tbody></table>

### Summary

* Rule #1: Allow Pi-hole DNS queries (LAN firewall rules, Part 3)
* Rule #2: Block DNS bypass on LAN (Part 3)
* Rule #3: NAT redirect all DNS traffic to Pi-hole (Part 4)
* Rule #4: Allow outbound DNS over TLS from OPNsense (Part 3)
* Rule #5: Block OPNsense host DNS leaks (Part 5)
* Rule #6: Allow OPNsense host to query local DNS (Part 5) (optional)

***

### Notes:

* The **allow rule (Order 1)** **must be at the top** on the LAN interface to enable Pi-hole to forward queries to Unbound successfully.
* The **block rule (Order 2)** prevents clients from circumventing Pi-hole by using external DNS servers directly.
* The **NAT redirect (Order 3)** transparently forces all LAN DNS traffic through Pi-hole before firewall filtering; it applies at the NAT layer.
* WAN interface rules (Orders 4-6) govern DNS requests originating from the firewall (OPNsense) itself, enforcing DoT usage and blocking DNS leaks by default.
* The `(Optional)` tag indicates rules that can be omitted if not desired but are best practice for full DNS privacy.

### How to verify and adjust order:

* Go to **Firewall > Rules > LAN** (or WAN).
* Use drag-and-drop handles or checkboxes with arrow buttons to reorder.
* Click **Apply Changes** to save.

***

## Testing & Validation <a href="#part-6-testing--validation" id="part-6-testing--validation"></a>

* Renew DHCP leases on clients; check DNS server settings point to Pi-hole.
* Verify Pi-hole receives DNS queries and blocks ads.
* From OPNsense shell, run:

  ```
  dig @127.0.0.1 example.com
  ```

  to confirm Unbound resolution.
* Use DNS leak test websites from clients and OPNsense host.
* Review firewall logs for DNS traffic compliance.

***

## How to reorder firewall rules in OPNsense Web UI:

1. Navigate to **Firewall > Rules**.
2. Select the interface tab, **LAN** or **WAN**, depending on where the rules are applied.
3. You'll see a list of the existing firewall rules in order from top to bottom.
4. To reorder:
   * Use the small **drag handles** (three horizontal lines) beside each rule to click and drag the rule up or down.
   * Alternatively, select one or more rules by checking the box(es) on the left, then use the **up/down arrow buttons** at the top of the rules list to move the selected rule(s).
5. After repositioning the rules in the desired order (such as allowing Pi-hole queries above block DNS bypass), click the **Apply Changes** button at the top to save and activate the new order.

### When using CLI commands (`opn-cli`):

* Rules created via CLI will appear at the top by default on the target interface.
* If the order is not perfect after bulk CLI creation, simply use the above drag-and-drop UI technique to fine-tune rule positions.
* This hybrid approach of CLI for creation + UI for ordering is common.

### Why in this the order?:

* OPNsense evaluates firewall rules **top to bottom**, stopping at the first match (first-match wins).
* The **allow rule for Pi-hole DNS queries** must be **above** the **block rule** that blocks all other DNS port 53 traffic from LAN clients. This ensures legitimate DNS traffic to Pi-hole is allowed before general DNS blocking kicks in.
* The **block rule** for other DNS traffic from clients is placed just below the Pi-hole allow rule, to catch all DNS attempts not directed to Pi-hole and block them.
* The WAN rules allowing outbound DoT TCP/853 traffic from OPNsense itself are on the WAN interface and independent but must also be placed logically in a way that permits this encrypted DNS traffic.
* The NAT redirect rule (optional) is processed before firewall rules and works at the NAT layer to transparently redirect DNS queries to Pi-hole.

### Supporting Details:

* According to OPNsense firewall best practices and documentation:
* Put **more specific rules first** (allow Pi-hole IP on port 53).
* Follow with **broader block rules** (block DNS port 53 from other clients).
* Always confirm after rule creation in the UI under **Firewall > Rules** that rules appear in the expected order and adjust manually if needed.
* Firewall logs and traffic monitoring help verify rules are applied correctly.

***

### DNS Query Flow Overview

Clients → Pi-hole (ad blocking, caching) → OPNsense Unbound (resolves DNS queries via encrypted DoT) → Upstream DoT servers (Cloudflare, Quad9, etc.)

***

### Additional Tips

* Regularly update Pi-hole blocklists and OPNsense software for security enhancements.
* Monitor Pi-hole and OPNsense logs for DNS query issues or anomalies.
* Consider DNSSEC validation enabled on Unbound for protection against forgery.
* Use test tools and packet capture to verify all DNS traffic is encrypted and forced through Pi-hole and Unbound.
