homelab-blueprint/docs/network/allow-caddy-to-apps.md
Brian Pooe a7de8cec3a docs(network): document IoT->Caddy path for HA's Forgejo git access
Home Assistant now pulls homelab-blueprint from Forgejo through Caddy,
which needed both a UniFi zone rule (IoT -> CADDY) and a ufw allow on
the Caddy host itself for the IoT subnet — two independent enforcement
layers, both previously missing/misconfigured.
2026-07-19 14:36:00 +02:00

7.5 KiB

Caddy Firewall Policies — Missing and Incorrect Rules

Note

For the complete list of custom firewall rules, see firewall-rules.md.

Audit findings from the zone policy review. Apply these in UniFi Settings → Policy Engine → Policy Table in the order shown. All custom policies must be above the built-in Block All Traffic terminal rule.


0. Immediate Cleanup — Redundant and Incorrect Rules

Sort these out before adding anything new.

Delete — completely redundant

Policy Why
Allow CADDY to Gateway DNS The Caddy Pi's resolv.conf points to Technitium at 10.0.10.5 (TRUSTED). Allow CADDY to DNS already covers that. The UDM Gateway DNS forwarder is not in use.

Keep — intra-zone rules that are actually required

UniFi's documentation implies intra-zone traffic is allowed by default, but in practice this does not apply to custom zones — removing these breaks intra-zone traffic.

Policy Why to keep
Allow TRUSTED to TRUSTED Any Without this rule, devices within TRUSTED cannot reach each other (confirmed: removing it broke SSH to Technitium).
Allow IoT to IoT Any Same — IoT intra-zone traffic requires an explicit allow for custom zones.

Fix — wrong action

Policy Problem Fix
Allow FAMILY to CADDY Action is set to Block instead of Allow. FAMILY devices cannot reach Caddy at all. Edit the policy and change Action to Allow.

Review — direct pinholes that bypass Caddy

These work but contradict the network design (§7.3/7.4), which says MEDIA and FAMILY should only reach internal services through Caddy. Once the ALLOW CADDY to arr stack backend policy (§2 below) is in place, both zones can reach Emby via emby.yourdomain.com through Caddy instead.

Policy Impact of keeping Impact of removing
Allow MEDIA to Emby Apple TV can connect directly to LXC — wider attack surface, bypasses Caddy logging and auth. Apple TV must use emby.yourdomain.com via Caddy. Requires Caddy backend policy in place first.
Allow FAMILY to EMBY Family devices bypass Caddy for Emby. Family devices must use emby.yourdomain.com via Caddy. Requires Caddy backend policy in place first.

Remove these only after the ALLOW CADDY to arr stack policy is created and confirmed working.


1. Fix: Allow FAMILY to CADDY (currently set to Block)

The existing Allow FAMILY to CADDY policy has Action = Block. Edit it and change the action to Allow.

Field Value
Name Allow FAMILY to CADDY
Action Allow (currently wrong — set to Block)
Source zone FAMILY
Source IP Any
Destination zone CADDY
Destination IP Any
Destination port 443
Protocol TCP

2. CADDY → TRUSTED Backend App Policies

Caddy at 10.0.15.5 cannot proxy to any backend apps in the TRUSTED zone until these policies exist. Create one policy per row.

Every policy in this table uses:

  • Action: Allow
  • Source zone: CADDY
  • Source IP: 10.0.15.5
  • Destination zone: TRUSTED
  • Protocol: TCP
Policy name Destination IP Destination port(s) Purpose
ALLOW CADDY to arr stack 10.0.10.20 5055,6767,7878,8000,8080,8096,8191,8282,8989,9696 Arr-stack LXC (bazarr, radarr, gluetun, qbittorrent, emby, flaresolverr, sabnzbd, sonarr, prowlarr, seerr)
ALLOW CADDY to Technitium UI 10.0.10.5 5380 Technitium admin UI
ALLOW CADDY to Proxmox 10.0.10.10 8006 Proxmox VE
ALLOW CADDY to PBS 10.0.10.8 8007 Proxmox Backup Server
ALLOW CADDY to LAN web devices 10.0.1.6 80 Lite-8 PoE switch UI
ALLOW CADDY to Beszel 10.0.10.13 8090 Beszel monitoring
ALLOW CADDY to Gramps 10.0.10.17 80 Gramps Web
ALLOW CADDY to Immich 10.0.10.15 2283 Immich
ALLOW CADDY to IT Tools 10.0.10.7 80 IT Tools
ALLOW CADDY to Paperless 10.0.10.11 8000 Paperless-ngx
ALLOW CADDY to YTD 10.0.10.14 3087 Youtarr
ALLOW CADDY to Bento PDF 10.0.10.6 8080 Bento PDF
ALLOW CADDY to Koffan 10.0.10.12 8080 Koffan (LXC 111)
ALLOW CADDY to Hermes 10.0.10.19 9119 Hermes Agent dashboard (LXC 113)
ALLOW CADDY to Forgejo 10.0.10.18 3000 Forgejo (LXC 114)

3. CADDY → IoT Backend Policies

Caddy cannot proxy to Home Assistant or Zigbee until these exist.

Every policy in this table uses:

  • Action: Allow
  • Source zone: CADDY
  • Source IP: 10.0.15.5
  • Destination zone: IoT
  • Protocol: TCP
Policy name Destination IP Destination port(s) Purpose
ALLOW CADDY to Home Automation 10.0.30.6 8080,8123 Zigbee2MQTT and Home Assistant
ALLOW CADDY to Zigbee 10.0.30.5 80 SLZB-06U Zigbee coordinator UI

3a. IoT → CADDY Policies (reverse direction)

The Home Assistant host itself also needs to reach Caddy directly — it pulls homelab-blueprint from Forgejo (git.home.brianpooe.com, proxied through Caddy) to deploy its own docker-compose stack.

Two independent layers enforce traffic into the Caddy host — both must allow it, and both were found misconfigured while wiring this up:

  1. UniFi zone-based firewall (router-level, VLAN → VLAN):

    Policy name Source zone Source IP Src. Port Destination zone Destination IP Destination port(s) Purpose
    Allow HA to Caddy IoT 10.0.30.6 (Home Assistant IP) Any CADDY 10.0.15.5 (Caddy IP) 443 git fetch/pull of homelab-blueprint from Forgejo

    Src. Port must be Any, not restricted to HA's own listening ports (8080/8123) — this is outbound traffic from HA, so the source port is a random ephemeral port, not the port HA listens on. Setting Src. Port to a "Home Assistant" port object here was the original bug: the rule never matched, so traffic fell through to Block All Traffic below it.

  2. ufw on the Caddy host itself (10.0.15.5) — a second, separate enforcement point the UniFi rule doesn't touch. It allow-lists inbound 80/443 per source subnet and did not include the IoT VLAN (10.0.30.0/24):

    sudo ufw allow from 10.0.30.0/24 to any port 80,443 proto tcp
    

    ufw status on that host is the fastest way to check which subnets can already reach it before assuming a UniFi rule is the problem.


4. Public DNS Block Policies (per zone)

Without these, devices can bypass Technitium by querying public resolvers (8.8.8.8, 1.1.1.1, etc.) directly. Place each policy above the broad External allow for its zone.

Every policy in this table uses:

  • Action: Block
  • Source IP: Any
  • Destination zone: External
  • Destination IP: Any
  • Protocol: TCP/UDP
  • Destination port: 53
Policy name Source zone
BLOCK FAMILY public DNS FAMILY
BLOCK MEDIA public DNS MEDIA
BLOCK IoT public DNS IoT
BLOCK GUEST public DNS GUEST

Policy Order Reference

Within each zone's rule set, the evaluation order must be:

specific allows (DNS, DHCP, Caddy, app pinholes)
public DNS block (above the External allow)
External allow
Gateway DHCP allow
Gateway block
Block All Traffic  ← built-in terminal rule

If a broad block rule sits above a specific allow, the block wins and the intended traffic is dropped. Use Reorder in UniFi to verify positions after adding new policies.