frigate: expose go2rtc on a dedicated MetalLB LB IP (RTSP 8554 + WebRTC 8555) #17

Merged
viktor merged 1 commit from emo/frigate-go2rtc-expose into master 2026-06-30 07:28:48 +00:00
Collaborator

Why

HA (ha-sofia) live video from the cluster Frigate hangs or never starts. Root cause is purely network/transport: the only path to Frigate is the Traefik HTTP(S) ingress (frigate-lan.viktorbarzin.lan → 10.0.20.203), which carries only 80/443. So:

  • WebRTC (go2rtc :8555) is unreachable — the container listens on 8555 (TCP+UDP) but no Service ever exposed it. With enable_webrtc: true the HA frontend tries WebRTC first, ICE never completes → hang.
  • RTSP restream (:8554) is only a NodePort (30554), not at the frigate-lan host → HA's native stream/HLS can't reach it either.
  • Only go2rtc MSE over the HTTPS websocket works today (already pinned on the dashboard as a workaround).

The Hikvision NVR cameras work fine because hikvision_next connects HA directly to a LAN RTSP and serves HLS through the HA proxy — no cluster ingress/port problem.

What this PR changes (Terraform)

stacks/frigate/main.tf: convert the frigate-rtsp Service NodePort → LoadBalancer on a dedicated MetalLB IP 10.0.20.204 (ETP=Local; the Frigate pod is pinned to the GPU node so the IP is advertised only from there — same pattern as Traefik .203 / KMS .202), exposing RTSP 8554 + WebRTC 8555 (TCP+UDP). Gives HA + LAN browsers a stable cross-VLAN L4 endpoint.

⚠️ One decision for you

.204 is the first free address in the MetalLB pool (10.0.20.200-220; .200 shared, .201 Technitium, .202 KMS, .203 Traefik). Please confirm no conflict before merge.

Companion steps (NOT Terraform — won't work without these)

  1. go2rtc WebRTC candidate — in Frigate config.yml (on the frigate-config PVC, via the Frigate UI config editor):
    go2rtc:
      webrtc:
        candidates:
          - 10.0.20.204:8555
    
  2. HA Frigate integration (Settings → Devices → Frigate → Configure): set
    rtsp_url_template = rtsp://10.0.20.204:8554/{{ name }}
    so native HLS (picture-entity more-info / native Frigate card) reaches the restream. enable_webrtc can stay true once the candidate above is set.

Optional follow-up (lighter live)

go2rtc currently restreams only the main 4MP stream for every camera (no sub-stream) → heavy live. Adding a low-res sub-stream (Hikvision /Streaming/Channels/X02) with the live/detect role would make live much snappier, especially for the valchedrym cameras (which come over WAN). This is also a config.yml change, not Terraform.

Status

Dashboard "Видеонаблюдение" already works via the MSE workaround (Home tiles = picture-entity snapshots like the NVR ones; Frigate view = advanced-camera-card pinned to go2rtc MSE). This PR is the clean fix to also enable native WebRTC/HLS.


Added below (token lacks write:issue, so folded into the description instead of a separate comment):

Companion changes (non-Terraform) — apply alongside the merge

These three live outside this PR (Frigate config.yml on the frigate-config PVC + the HA integration), so they won't show in the diff. Copy-paste ready:

1) go2rtc WebRTC candidate — Frigate config.yml (Frigate UI → Config editor)

Add a webrtc: block as a sibling of streams: under the existing go2rtc: key:

go2rtc:
  webrtc:
    candidates:
      - 10.0.20.204:8555   # the dedicated LB IP from this PR
  streams:
    # ...existing streams unchanged...

Then reload/restart Frigate so go2rtc re-reads the candidate. (Single host candidate = LAN-only; remote/WAN WebRTC would need a public candidate + NAT, out of scope.)

2) HA Frigate integration — rtsp_url_template

ha-sofia → Settings → Devices & Services → Frigate → Configure:

rtsp://10.0.20.204:8554/{{ name }}

Points HA's native stream/HLS (picture-entity more-info + native Frigate card) at the reachable restream. {{ name }} → the frigate camera name, e.g. vermont-10rtsp://10.0.20.204:8554/vermont-10. enable_webrtc can stay true once step 1 is in.

3) (optional) lighter live — sub-stream

Each camera currently restreams only the main 4MP (/Streaming/Channels/X01/1). Add the Hikvision sub-stream (/Streaming/Channels/X02) as a second go2rtc stream and use it for the live (and ideally detect) role, keeping main for record. Makes live much snappier, especially the WAN-fed valchedrym cameras. Exact 0.17 wiring is your call.


Dashboard note: the "Видеонаблюдение" Frigate view is currently pinned to go2rtc: { modes: [mse] } (the working workaround). Once .204 + the candidate are live, it can stay on MSE or be relaxed to auto to prefer WebRTC — ping me and I'll do that dashboard tweak.

## Why HA (ha-sofia) live video from the **cluster** Frigate hangs or never starts. Root cause is purely network/transport: the only path to Frigate is the Traefik HTTP(S) ingress (`frigate-lan.viktorbarzin.lan` → 10.0.20.203), which carries **only 80/443**. So: - **WebRTC** (go2rtc :8555) is unreachable — the container listens on 8555 (TCP+UDP) but **no Service ever exposed it**. With `enable_webrtc: true` the HA frontend tries WebRTC first, ICE never completes → hang. - **RTSP restream** (:8554) is only a `NodePort` (30554), not at the `frigate-lan` host → HA's native `stream`/HLS can't reach it either. - Only **go2rtc MSE over the HTTPS websocket** works today (already pinned on the dashboard as a workaround). The Hikvision NVR cameras work fine because `hikvision_next` connects HA directly to a LAN RTSP and serves HLS through the HA proxy — no cluster ingress/port problem. ## What this PR changes (Terraform) `stacks/frigate/main.tf`: convert the `frigate-rtsp` Service `NodePort → LoadBalancer` on a **dedicated MetalLB IP `10.0.20.204`** (`ETP=Local`; the Frigate pod is pinned to the GPU node so the IP is advertised only from there — same pattern as Traefik .203 / KMS .202), exposing **RTSP 8554 + WebRTC 8555 (TCP+UDP)**. Gives HA + LAN browsers a stable cross-VLAN L4 endpoint. ### ⚠️ One decision for you `.204` is the first free address in the MetalLB pool (`10.0.20.200-220`; .200 shared, .201 Technitium, .202 KMS, .203 Traefik). **Please confirm no conflict** before merge. ## Companion steps (NOT Terraform — won't work without these) 1. **go2rtc WebRTC candidate** — in Frigate `config.yml` (on the `frigate-config` PVC, via the Frigate UI config editor): ```yaml go2rtc: webrtc: candidates: - 10.0.20.204:8555 ``` 2. **HA Frigate integration** (Settings → Devices → Frigate → Configure): set `rtsp_url_template = rtsp://10.0.20.204:8554/{{ name }}` so native HLS (picture-entity more-info / native Frigate card) reaches the restream. `enable_webrtc` can stay `true` once the candidate above is set. ## Optional follow-up (lighter live) go2rtc currently restreams only the **main 4MP** stream for every camera (no sub-stream) → heavy live. Adding a low-res sub-stream (Hikvision `/Streaming/Channels/X02`) with the `live`/`detect` role would make live much snappier, especially for the `valchedrym` cameras (which come over WAN). This is also a `config.yml` change, not Terraform. ## Status Dashboard "Видеонаблюдение" already works via the MSE workaround (Home tiles = picture-entity snapshots like the NVR ones; Frigate view = advanced-camera-card pinned to go2rtc MSE). This PR is the clean fix to also enable native WebRTC/HLS. --- > _Added below (token lacks `write:issue`, so folded into the description instead of a separate comment):_ ## Companion changes (non-Terraform) — apply alongside the merge These three live **outside** this PR (Frigate `config.yml` on the `frigate-config` PVC + the HA integration), so they won't show in the diff. Copy-paste ready: ### 1) go2rtc WebRTC candidate — Frigate `config.yml` (Frigate UI → Config editor) Add a `webrtc:` block as a sibling of `streams:` under the existing `go2rtc:` key: ```yaml go2rtc: webrtc: candidates: - 10.0.20.204:8555 # the dedicated LB IP from this PR streams: # ...existing streams unchanged... ``` Then reload/restart Frigate so go2rtc re-reads the candidate. (Single host candidate = LAN-only; remote/WAN WebRTC would need a public candidate + NAT, out of scope.) ### 2) HA Frigate integration — `rtsp_url_template` ha-sofia → **Settings → Devices & Services → Frigate → Configure**: ``` rtsp://10.0.20.204:8554/{{ name }} ``` Points HA's native `stream`/HLS (picture-entity more-info + native Frigate card) at the reachable restream. `{{ name }}` → the frigate camera name, e.g. `vermont-10` → `rtsp://10.0.20.204:8554/vermont-10`. `enable_webrtc` can stay `true` once step 1 is in. ### 3) (optional) lighter live — sub-stream Each camera currently restreams only the **main 4MP** (`/Streaming/Channels/X01/1`). Add the Hikvision **sub-stream** (`/Streaming/Channels/X02`) as a second go2rtc stream and use it for the `live` (and ideally `detect`) role, keeping main for `record`. Makes live much snappier, especially the WAN-fed `valchedrym` cameras. Exact 0.17 wiring is your call. --- **Dashboard note:** the "Видеонаблюдение" Frigate view is currently pinned to `go2rtc: { modes: [mse] }` (the working workaround). Once `.204` + the candidate are live, it can stay on MSE or be relaxed to `auto` to prefer WebRTC — ping me and I'll do that dashboard tweak.
ebarzin added 1 commit 2026-06-30 07:15:52 +00:00
frigate: expose go2rtc on a dedicated MetalLB LB IP (RTSP 8554 + WebRTC 8555)
All checks were successful
ci/woodpecker/push/default Pipeline was successful
469cdd7507
HA live video from the cluster Frigate hangs/fails because the only path
to Frigate is the Traefik HTTP(S) ingress (frigate-lan -> 10.0.20.203),
which cannot carry RTSP or WebRTC. The container already listens on
8554+8555 but only RTSP had a Service (NodePort), and WebRTC (8555) was
never exposed. Convert frigate-rtsp to a LoadBalancer on a dedicated MetalLB
IP (.204, ETP=Local, pod pinned to the GPU node) carrying RTSP 8554 +
WebRTC 8555 (TCP+UDP), giving HA Sofia + LAN browsers a stable cross-VLAN
endpoint for native HLS/WebRTC live (parity with the Hikvision NVR).
Companion non-Terraform steps are in the PR body.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
viktor merged commit 469cdd7507 into master 2026-06-30 07:28:48 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: viktor/infra#17
No description provided.