Split-Horizon DNS with Technitium and OPNsense: Resolving Internal Hosts Locally (plus Let’s Encrypt via DNS-01)

My home network uses Technitium DNS as the primary DNS server and OPNsense as the router. I own a public domain (in this post I’ll use domain.com as a placeholder), and I wanted truenascale.domain.com to point to my TrueNAS SCALE box on the LAN instead of being resolved somewhere on the internet. On top of that, I wanted a proper TLS certificate for it without exposing the NAS to the outside world.

The answer to the first part is split-horizon DNS: the internal resolver answers certain names itself, with internal IPs, while everything else resolves normally. The answer to the second part is the ACME DNS-01 challenge.

Step 1: Create a zone for just that hostname in Technitium

The tempting mistake is to create a zone for the whole domain.com. Don’t. Technitium would then be authoritative for the entire domain, and every public record you didn’t copy over (www, MX, and so on) would stop resolving inside your network.

Instead, create a zone for exactly the one name:

  1. In Technitium, go to Zones → Add Zone.
  2. Zone name: truenascale.domain.com, type: Primary Zone.
  3. Inside that zone, add an A record with name @ pointing to the TrueNAS LAN IP (e.g. 192.168.1.20).

Technitium now answers that single name locally, while everything else under domain.com still resolves publicly through your normal forwarders or recursion.

Tip: if you run several internal services (for example behind a reverse proxy), use a subdomain zone such as home.domain.com and put individual records or a wildcard * inside it.

Step 2: Make sure clients actually use Technitium

In OPNsense, check the DHCP server settings (Kea or ISC, per interface) and make sure the DNS server handed out to clients is the Technitium IP, not the OPNsense IP. Clients need to renew their lease (or reconnect) to pick this up.

If OPNsense’s own Unbound resolver is still enabled and clients reach it instead, you would have to maintain host overrides there as well. Keeping a single source of truth is much simpler.

Step 3: Watch out for the usual suspects

  • Browser DNS-over-HTTPS: Firefox and Chrome can use “Secure DNS” and bypass your local resolver completely. Disable it in the browser or via policy. For Firefox, blocking the canary domain use-application-dns.net in Technitium signals it to turn DoH off.
  • Client DNS cache: after changing things, flush it with ipconfig /flushdns on Windows or resolvectl flush-caches on Linux.
  • Hardcoded DNS on devices (8.8.8.8 and friends): optionally add a NAT port-forward rule in OPNsense that redirects all outbound port 53 traffic from the LAN to Technitium. Exclude Technitium itself from the rule, or it can’t reach its upstreams.
  • DNS rebind protection: if anything in the chain passes through OPNsense Unbound, it may drop public names that resolve to private IPs. Add domain.com to Unbound’s private domains list if needed.

Step 4: Test

nslookup truenascale.domain.com <technitium-ip>
nslookup truenascale.domain.com

Both should return the LAN IP. If the first works but the second doesn’t, the client isn’t using Technitium yet.

Bonus: a valid Let’s Encrypt certificate via DNS-01

Now that the name resolves internally, you’ll want HTTPS without browser warnings. Since the NAS isn’t reachable from the internet, the HTTP-01 challenge is out. The DNS-01 challenge works perfectly here.

One thing that confused me at first: where does DNS-01 happen, OPNsense or Technitium? Neither. Let’s Encrypt checks a TXT record _acme-challenge.truenascale.domain.com on the public DNS provider that hosts domain.com (Cloudflare, Hetzner, OVH, INWX, your registrar…). Technitium only answers inside the LAN, so Let’s Encrypt never sees it.

What you run locally is an ACME client with an API token for your public DNS provider. It creates the TXT record, obtains the certificate and cleans up afterwards. There are three sensible places to run it:

Option A: TrueNAS SCALE itself

Simplest if TrueNAS is the only thing that needs a certificate:

  1. Credentials → Certificates → ACME DNS-Authenticators: add your provider with an API token. Cloudflare, Route53 and OVH are built in; newer versions also allow a custom shell-script authenticator.
  2. Create a Certificate Signing Request for truenascale.domain.com.
  3. Click the wrench icon → Create ACME Certificate, select the authenticator, then choose the new certificate under System → General → GUI.

TrueNAS renews it automatically.

Option B: OPNsense with the os-acme-client plugin

Useful if you want one central place for certificates. It’s based on acme.sh and supports almost every DNS provider API. The catch: you then have to get the certificate onto TrueNAS. The plugin offers “automations” to deploy certificates to other hosts, but for TrueNAS this is more fiddly than option A.

Option C: Your reverse proxy

The best choice once you have several internal services. Traefik, Caddy, Nginx Proxy Manager or its fork NPMplus can request a wildcard certificate (*.domain.com or *.home.domain.com) via DNS-01 once. Point the internal DNS names in Technitium to the proxy’s IP and let the proxy terminate TLS for everything, TrueNAS included.

What if your registrar is INWX?

If domain.com is registered and its DNS hosted at INWX, DNS-01 works through the INWX API, but not every client supports it:

  • TrueNAS SCALE has no built-in INWX authenticator. Use the custom shell-script authenticator with an INWX-capable tool, or issue the certificate elsewhere.
  • OPNsense os-acme-client supports INWX out of the box, because acme.sh ships a dns_inwx hook.
  • NPMplus (the Nginx Proxy Manager fork) ships INWX in its DNS challenge provider list. When requesting a certificate, enable the DNS challenge, pick INWX and fill in the credentials template:
    dns_inwx_url = https://api.domrobot.com/xmlrpc/
    dns_inwx_username = your_username
    dns_inwx_password = your_password
    dns_inwx_shared_secret = your_shared_secret (only needed if 2FA is enabled)
  • Traefik supports INWX natively through its lego library. For other reverse proxies, check whether an INWX DNS plugin is available.

The INWX API authenticates with account credentials rather than a narrowly scoped token. If two-factor authentication is enabled, you also need the 2FA shared secret. Where possible, use a separate account limited to DNS for this, rather than your main login.

Two practical notes

  • Give the API token the minimum scope, e.g. on Cloudflare Zone → DNS → Edit for domain.com only.
  • The hostname needs no public A record. DNS-01 only needs the temporary TXT record, so the NAS stays completely invisible from the outside.

Summary

A single-host primary zone in Technitium gives you local resolution without breaking the rest of your public domain. Make sure every client really uses Technitium, keep an eye on DoH and hardcoded resolvers, and use DNS-01 at your public DNS provider to get trusted certificates for hosts that never face the internet.

Leave a comment