<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Unbound on inetshell</title><link>https://inet.sh/en/tags/unbound/</link><description>Recent content in Unbound on inetshell</description><generator>Hugo</generator><language>en</language><lastBuildDate>Fri, 25 Sep 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://inet.sh/en/tags/unbound/index.xml" rel="self" type="application/rss+xml"/><item><title>pfSense and OPNsense: the port forward does not work from the LAN itself (NAT reflection and split DNS)</title><link>https://inet.sh/en/posts/pfsense/nat-reflection-port-forward-from-lan/</link><pubDate>Fri, 25 Sep 2026 00:00:00 +0000</pubDate><guid>https://inet.sh/en/posts/pfsense/nat-reflection-port-forward-from-lan/</guid><description>From outside the port forward works, but from the LAN the public IP or the domain lands on the firewall&amp;#39;s GUI or a certificate error. Two fixes: split DNS with host overrides in the DNS Resolver (the recommended one) or NAT reflection in Pure NAT mode with automatic outbound NAT. Includes the OPNsense equivalent and the DNS rebinding trap.</description><content:encoded><![CDATA[<h2 id="tldr">TL;DR</h2>
<p><strong>Clean option (split DNS):</strong> Services → DNS Resolver → <em>Host Overrides</em> → <code>app.example.com</code> → the server&rsquo;s internal IP (<code>192.168.1.50</code>). LAN clients must use the firewall as their DNS.</p>
<p><strong>NAT reflection option:</strong> System → Advanced → <em>Firewall &amp; NAT</em>:</p>
<ul>
<li><em>NAT Reflection mode for port forwards</em>: <strong>Pure NAT</strong></li>
<li><em>Enable NAT Reflection for 1:1 NAT</em>: ✔</li>
<li><em>Enable automatic outbound NAT for Reflection</em>: ✔</li>
</ul>
<p>Save and test from a LAN client against the public IP.</p>
<h2 id="the-problem">The problem</h2>
<p>The port forward <code>WAN:443 → 192.168.1.50:443</code> works from the Internet. From a machine on the same LAN, <code>https://app.example.com</code> (which resolves to the public IP) answers with the pfSense GUI, a certificate error, or <code>Potential DNS Rebind attack detected</code>.</p>
<p>The packet leaves the client towards the public IP, reaches the firewall through the LAN interface, and stops there: the port forward rule listens on the WAN, not the LAN, and the destination IP is one of the firewall&rsquo;s own addresses. It never &ldquo;goes out and comes back in&rdquo;.</p>
<h2 id="option-1-split-dns">Option 1: split DNS</h2>
<p>This is what Netgate recommends: the name resolves to the internal IP inside and to the public one outside. Traffic goes direct, the server sees the client&rsquo;s real IP, and the firewall touches nothing.</p>
<ol>
<li>Services → DNS Resolver → <em>Host Overrides</em> → <strong>Add</strong>: host <code>app</code>, domain <code>example.com</code>, IP <code>192.168.1.50</code>. If the service has several names, add <em>Additional Names</em>.</li>
<li>Clients must use the firewall as DNS (the norm if DHCP hands it out). A client with <code>8.8.8.8</code> hardcoded will keep going to the public IP.</li>
<li><code>nslookup app.example.com</code> from the LAN → <code>192.168.1.50</code>.</li>
</ol>
<p>Requirement: the internal and external ports must be the same (if outside you forward <code>8443 → 443</code>, the internal client will have to use <code>443</code> directly).</p>
<p>If you run the DNS Forwarder (dnsmasq) instead of the Resolver, the equivalent setting is under Services → DNS Forwarder → <em>Host Overrides</em>.</p>
<h2 id="option-2-nat-reflection">Option 2: NAT reflection</h2>
<p>When you do not control the clients&rsquo; DNS, or there are lots of ports, the firewall can &ldquo;reflect&rdquo; the connection: it rewrites the destination to the internal IP and, with automatic outbound NAT, the source too, so the reply comes back through the firewall.</p>
<p>System → Advanced → <em>Firewall &amp; NAT</em>, <em>Network Address Translation</em> section:</p>
<table>
  <thead>
      <tr>
          <th>Setting</th>
          <th>Value</th>
          <th>Why</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>NAT Reflection mode for port forwards</td>
          <td><strong>Pure NAT</strong></td>
          <td>PF rules only: every protocol, no port limit. <em>NAT + Proxy</em> uses a daemon, TCP only and at most 500 ports per rule</td>
      </tr>
      <tr>
          <td>Enable NAT Reflection for 1:1 NAT</td>
          <td>✔</td>
          <td>If you have 1:1 NAT besides port forwards</td>
      </tr>
      <tr>
          <td>Enable automatic outbound NAT for Reflection</td>
          <td>✔</td>
          <td>Without it, when client and server share a subnet the server replies straight to the client, which does not recognize the connection and drops it</td>
      </tr>
      <tr>
          <td>Reflection Timeout</td>
          <td>(NAT + Proxy only)</td>
          <td>Ignore it in Pure NAT</td>
      </tr>
  </tbody>
</table>
<p>It can also be enabled per rule: Firewall → NAT → Port Forward → edit → <em>NAT reflection</em> → <em>Enable (Pure NAT)</em>, leaving the global setting on <em>Disable</em>.</p>
<p>Costs: the server sees the firewall&rsquo;s LAN IP as the source (not the client&rsquo;s), and all that traffic crosses the firewall even when client and server sit on the same switch.</p>
<h2 id="opnsense">OPNsense</h2>
<p>Same idea, other menus:</p>
<ul>
<li>Split DNS: Services → Unbound DNS → <em>Overrides</em> → Host Overrides.</li>
<li>Reflection: Firewall → Settings → <em>Advanced</em> → <strong>Reflection for port forwards</strong>, <strong>Reflection for 1:1</strong>, <strong>Automatic outbound NAT for Reflection</strong>.</li>
</ul>
<h2 id="traps">Traps</h2>
<ul>
<li><strong>DNS rebinding.</strong> If instead of a host override you point the Resolver at an external DNS that returns private IPs (an internal DNS at another site, a provider with views), Unbound drops those answers as rebinding protection. Do not untick <em>Disable DNS Rebinding Checks</em> under System → Advanced → Admin Access: add <code>private-domain: &quot;example.com&quot;</code> under Services → DNS Resolver → <em>Custom options</em> and only that domain is exempt.</li>
<li><strong>A client with hardcoded DNS</strong> bypasses split DNS. Either force it through DHCP, catch it with a port 53 NAT rule, or use reflection.</li>
<li><strong>Pure NAT needs to know the interface and gateway</strong> when rules load; with dynamic WANs that change IP, a <em>Filter Reload</em> after the IP change fixes it.</li>
<li><strong>Different ports inside and outside</strong> only work with reflection; split DNS does not translate ports.</li>
<li><strong>Certificates</strong>: with split DNS the browser still sees <code>app.example.com</code>, so the server&rsquo;s certificate works as is. When reflecting through the public IP, too. The certificate error at the start was the firewall GUI&rsquo;s, not the server&rsquo;s.</li>
</ul>
<p>References: <a href="https://docs.netgate.com/pfsense/en/latest/recipes/port-forwards-from-local-networks.html">Port Forwards from Local Networks</a> and <a href="https://docs.netgate.com/pfsense/en/latest/nat/reflection.html">NAT Reflection</a> in the Netgate documentation.</p>
]]></content:encoded></item></channel></rss>