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.
199 lines
7.5 KiB
Markdown
199 lines
7.5 KiB
Markdown
# Caddy Firewall Policies — Missing and Incorrect Rules
|
|
|
|
> [!NOTE]
|
|
> For the complete list of custom firewall rules, see [firewall-rules.md](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`):
|
|
|
|
```bash
|
|
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.
|