docs: add caddy acme dns redirect exception guidance

This commit is contained in:
Brian Pooe 2026-03-06 23:05:50 +02:00
parent 3145dddb1d
commit 3322911fcd
4 changed files with 73 additions and 0 deletions

View file

@ -96,6 +96,11 @@ Reference (fast entry):
Reference (full explanation):
- [pfsense-forced-dns-all-vlans.md](./pfsense-forced-dns-all-vlans.md)
Important for Caddy DNS-01 + Cloudflare:
- If Caddy host is inside a force-redirected VLAN (for this setup, `OFFICE`), exclude that host from the interface's forced DNS NAT rule.
- Keep rule source as inverted `!CADDY_HOST` and source port as `any` to `any`.
- This prevents ACME failures like: `expected 1 zone, got 0 for home.brianpooe.com`.
Optional hardening for encrypted DNS bypass:
- [pfsense-dot-doh-blocking-quick-entry.md](./pfsense-dot-doh-blocking-quick-entry.md)

View file

@ -23,6 +23,11 @@ Create host alias:
- Type: `Host(s)`
- Value: `192.168.60.5`
Recommended (if Caddy uses DNS-01 with Cloudflare):
- Name: `CADDY_HOST`
- Type: `Host(s)`
- Value: `192.168.10.5`
Optional (cleaner descriptions):
- Name: `DNS_CLIENT_INTERFACES`
- Type: `Network(s)`
@ -66,6 +71,27 @@ Reason:
For OPT3/OPT4/OPT5/OPT6:
- Keep `Pi-hole` pass rules (or associated pass from NAT) above RFC1918 block rules.
## Step 3b: Add DNS redirect exception for Caddy (ACME DNS-01)
Path: `Firewall > NAT > Port Forward`
If Caddy runs on a VLAN that is also force-redirected for DNS (example: `OFFICE` / `192.168.10.0/24`), edit that interface's forced DNS rule and exclude the Caddy host.
Example rule to edit:
- `Force DNS to LOCAL_DNS (OFFICE)`
Set:
- Source: `Invert Match` = checked
- Source type/value: `Address or Alias` = `CADDY_HOST`
- Source Port: `any` to `any` (do not set `DNS`)
- Destination: keep `Invert Match` checked and `LOCAL_DNS`
- Destination Port: keep `DNS (53)`
- Redirect target: keep `LOCAL_DNS:53`
Root cause this prevents:
- Forced DNS NAT can intercept Caddy's resolver lookups to public resolvers.
- In split-DNS environments, this makes Caddy see local zone `home.brianpooe.com` instead of public authority chain.
- Cloudflare DNS plugin then fails zone detection with `expected 1 zone, got 0 for home.brianpooe.com`.
## Step 4: Apply changes
- Save and `Apply Changes` in NAT and Rules tabs.
@ -88,6 +114,14 @@ nslookup proxmox.home.brianpooe.com
nslookup switchlite8poe.home.brianpooe.com
```
If using Caddy DNS-01, verify from Caddy host:
```bash
dig +short SOA home.brianpooe.com @1.1.1.1
```
Expected:
- Result should not be your local Technitium SOA (`dns01.home.brianpooe.com ...`).
## Optional hardening (recommended)
Port 53 forcing does not stop encrypted DNS bypass:
- DoT uses TCP `853`

View file

@ -10,6 +10,11 @@ Create:
- Type: `Host(s)`
- Value: `192.168.60.5`
Optional (recommended when using Caddy DNS-01 with Cloudflare):
- Name: `CADDY_HOST`
- Type: `Host(s)`
- Value: `192.168.10.5`
## 1) NAT Port Forward rules (enter these 6)
Path: `Firewall > NAT > Port Forward`
@ -104,6 +109,31 @@ For each block below, click `Add` and use exactly these fields.
Do not add this redirect on `OPT7` (DNS server VLAN).
## 1b) Exception for Caddy ACME DNS-01 traffic (important)
If Caddy is using DNS-01 challenges with Cloudflare, exclude the Caddy host from forced DNS redirect on the interface where Caddy lives (for this setup, `OFFICE` / `OPT2`).
Edit rule:
- `Force DNS to LOCAL_DNS (OFFICE)`
Set:
- Source: `Invert Match` = checked
- Source type/value: `Address or Alias` = `CADDY_HOST`
- Source Port: `any` to `any` (do not set `DNS` here)
- Destination: keep `Invert Match` checked and `LOCAL_DNS`
- Destination Port: keep `DNS (53)`
- Redirect target IP/Port: keep `LOCAL_DNS:53`
Why this is needed:
- Without this exception, pfSense intercepts Caddy's outbound DNS lookups (even when targeting public resolvers like `1.1.1.1`) and redirects them to local Technitium.
- Caddy then sees local split-DNS zone `home.brianpooe.com`, but Cloudflare only has public zone `brianpooe.com`.
- ACME fails with: `expected 1 zone, got 0 for home.brianpooe.com`.
Validation from Caddy host:
```bash
dig +short SOA home.brianpooe.com @1.1.1.1
```
- This should not return Technitium SOA (`dns01.home.brianpooe.com ...`) once the exception is active.
## 2) Rule order checks (critical)
### NAT order

View file

@ -87,6 +87,10 @@ nslookup switchlite8poe.home.brianpooe.com 192.168.60.5
- If Technitium fails to bind port 53, check for other DNS services on the host (for example `systemd-resolved`, `dnsmasq`, old Pi-hole container).
- If Dockhand cannot manage containers, verify `DOCKER_GID` and docker socket mount.
- If Dockhand shows `Invalid ENCRYPTION_KEY`, regenerate with `openssl rand -base64 32`, re-render the compose file, and restart Dockhand.
- If Caddy ACME DNS-01 fails with `expected 1 zone, got 0 for home.brianpooe.com`, your forced-DNS NAT is likely intercepting Caddy's resolver lookups.
- Add `CADDY_HOST` alias and exclude it in the forced DNS NAT rule on Caddy's interface (source `!CADDY_HOST`, source port `any`).
- Keep destination invert `!LOCAL_DNS`, destination port `53`, redirect to `LOCAL_DNS:53`.
- See: [pfsense-forced-dns-all-vlans.md](./pfsense-forced-dns-all-vlans.md)
- If `http://<DNS_BIND_IP>:5380` is refused, run:
```bash
docker compose -f docker-compose-files/technitium-dockhand.yaml ps technitium-dns