Deploy Frigate NVR stack with Mosquitto, Ntfy, and frigate-notify #190

Merged
eblume merged 20 commits from deploy-frigate-nvr into main 2026-02-14 21:27:45 -08:00
Owner

Summary

Deploy a cloud-free NVR stack for the GableCam (ReoLink Elite Floodlight at 192.168.1.159):

  • Mosquitto — shared MQTT broker in mqtt namespace (cluster-internal, no auth)
  • Ntfy — self-hosted push notifications in ntfy namespace, exposed at ntfy.tail8d86e.ts.net / ntfy.ops.eblu.me
  • Frigate — NVR with GableCam via HTTP-FLV, ONNX CPU detection, NFS recordings on sifaka, exposed at nvr.tail8d86e.ts.net / nvr.ops.eblu.me
  • frigate-notify — bridges Frigate detection events (person, car, dog, cat) to Ntfy alerts via MQTT

Also includes:

  • Prometheus scrape target for Frigate metrics
  • Grafana dashboard for Frigate (status, inference speed, FPS, CPU/memory, storage)
  • Caddy reverse proxy entries for nvr.ops.eblu.me and ntfy.ops.eblu.me

Prerequisites

  • Create NFS share frigate on sifaka (/volume1/frigate, RW for indri)
  • Create 1Password item "Reolink Floodlight Camera" in blumeops vault with username and password fields

Deployment (after merge)

argocd app sync apps
argocd app sync mosquitto
argocd app sync ntfy
argocd app sync frigate
argocd app sync grafana-config
argocd app sync prometheus
mise run provision-indri -- --tags caddy
mise run services-check

Verification

  • Mosquitto pod running, accepting connections on 1883
  • Ntfy web UI accessible at ntfy.ops.eblu.me
  • Frigate web UI at nvr.ops.eblu.me showing GableCam live feed
  • Object detection working (ONNX, person/car/dog/cat)
  • Recordings appearing in NFS share on sifaka
  • frigate-notify sending detection alerts to Ntfy
  • Prometheus scraping Frigate metrics
  • Grafana dashboard showing Frigate data
## Summary Deploy a cloud-free NVR stack for the GableCam (ReoLink Elite Floodlight at 192.168.1.159): - **Mosquitto** — shared MQTT broker in `mqtt` namespace (cluster-internal, no auth) - **Ntfy** — self-hosted push notifications in `ntfy` namespace, exposed at `ntfy.tail8d86e.ts.net` / `ntfy.ops.eblu.me` - **Frigate** — NVR with GableCam via HTTP-FLV, ONNX CPU detection, NFS recordings on sifaka, exposed at `nvr.tail8d86e.ts.net` / `nvr.ops.eblu.me` - **frigate-notify** — bridges Frigate detection events (person, car, dog, cat) to Ntfy alerts via MQTT Also includes: - Prometheus scrape target for Frigate metrics - Grafana dashboard for Frigate (status, inference speed, FPS, CPU/memory, storage) - Caddy reverse proxy entries for `nvr.ops.eblu.me` and `ntfy.ops.eblu.me` ## Prerequisites - [ ] Create NFS share `frigate` on sifaka (`/volume1/frigate`, RW for indri) - [ ] Create 1Password item "Reolink Floodlight Camera" in `blumeops` vault with `username` and `password` fields ## Deployment (after merge) ```bash argocd app sync apps argocd app sync mosquitto argocd app sync ntfy argocd app sync frigate argocd app sync grafana-config argocd app sync prometheus mise run provision-indri -- --tags caddy mise run services-check ``` ## Verification - [ ] Mosquitto pod running, accepting connections on 1883 - [ ] Ntfy web UI accessible at `ntfy.ops.eblu.me` - [ ] Frigate web UI at `nvr.ops.eblu.me` showing GableCam live feed - [ ] Object detection working (ONNX, person/car/dog/cat) - [ ] Recordings appearing in NFS share on sifaka - [ ] frigate-notify sending detection alerts to Ntfy - [ ] Prometheus scraping Frigate metrics - [ ] Grafana dashboard showing Frigate data
Add four new services for cloud-free camera recording and alerting:
- Mosquitto MQTT broker (shared service in mqtt namespace)
- Ntfy push notifications (tailnet-accessible)
- Frigate NVR with GableCam via HTTP-FLV, ONNX detection, NFS recordings
- frigate-notify bridging detection events to Ntfy

Also adds Prometheus scrape target, Grafana dashboard, and Caddy
reverse proxy entries for nvr.ops.eblu.me and ntfy.ops.eblu.me.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@ -79,0 +81,4 @@
backend: "https://nvr.tail8d86e.ts.net"
- name: ntfy
host: "ntfy.{{ caddy_domain }}"
backend: "https://ntfy.tail8d86e.ts.net"
Author
Owner

Why no mqtt.ops.eblu.me? There might be a reason.

Why no mqtt.ops.eblu.me? There might be a reason.
eblume marked this conversation as resolved
@ -0,0 +17,4 @@
- person
- car
- dog
- cat
Author
Owner

can we include chicken and duck? does it work like that? We keep chickens and ducks and if they are seen by gablecam then they've gotten out. (this is too cool.)

can we include chicken and duck? does it work like that? We keep chickens and ducks and if they are seen by gablecam then they've gotten out. (this is too cool.)
eblume marked this conversation as resolved
@ -0,0 +12,4 @@
go2rtc:
streams:
gablecam:
- "ffmpeg:http://{FRIGATE_CAMERA_USER}:{FRIGATE_CAMERA_PASSWORD}@192.168.1.159/flv?port=1935&app=bcs&stream=channel0_main.bcs#video=copy#audio=copy#audio=opus"
Author
Owner

here and anywhere else that 192.168.1.159 appears in IaC, include a comment that the IP is reserved in UX7's DHCP config

here and anywhere else that 192.168.1.159 appears in IaC, include a comment that the IP is reserved in UX7's DHCP config
eblume marked this conversation as resolved
@ -0,0 +30,4 @@
detect:
enabled: true
width: 640
height: 480
Author
Owner

I don't know what these dimensions mean but gablecam is a reolink elite floodlight camera which has twin cameras and a very wide field of vision (180*), so 640x480 seems wrong to me. But again I dont know what this config means so that could be irrelevant.

I don't know what these dimensions mean but gablecam is a reolink elite floodlight camera which has twin cameras and a very wide field of vision (180*), so 640x480 seems wrong to me. But again I dont know what this config means so that could be irrelevant.
eblume marked this conversation as resolved
@ -0,0 +32,4 @@
width: 640
height: 480
objects:
track: [person, car, dog, cat]
Author
Owner

same note as above about chickens and ducks being of interest as well

same note as above about chickens and ducks being of interest as well
eblume marked this conversation as resolved
@ -0,0 +19,4 @@
storageClassName: ""
nfs:
server: sifaka
path: /volume1/frigate
Author
Owner

fyi I have created this share

fyi I have created this share
eblume marked this conversation as resolved
@ -0,0 +9,4 @@
tailscale.com/proxy-group: "ingress"
gethomepage.dev/enabled: "true"
gethomepage.dev/name: "Ntfy"
gethomepage.dev/group: "Infrastructure"
Author
Owner

In this same PR, let's move ArgoCD, Prometheus, and devpi/pypi to Infastructure group. CV, Docs, TeslaMate, and Transmission should become "Services".

In this same PR, let's move ArgoCD, Prometheus, and devpi/pypi to Infastructure group. CV, Docs, TeslaMate, and Transmission should become "Services".
eblume marked this conversation as resolved
eblume referenced this pull request from a commit 2026-02-14 12:54:17 -08:00
- Add bird to tracked objects (catches escaped chickens/ducks)
- Add DHCP reservation comment for GableCam IP
- Remove explicit detect dimensions (Frigate auto-detects from stream)
- Reorganize homepage groups: ArgoCD/Prometheus/PyPI to Infrastructure,
  CV/Docs/TeslaMate/Transmission to Services

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace Misc group with Infrastructure and Services in the homepage
layout configuration to match the reorganized ingress annotations.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Configures ntfy to forward poll requests through ntfy.sh for APNs
delivery. Without this, iOS delays notifications by 20-30+ minutes.
Free tier allows 250 messages/day (no account needed).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ONNX detector was crashing due to missing model path config.
CPU/TFLite works out of the box on ARM64 and is sufficient for
single-camera detection of large objects.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Camera had HTTP/RTMP disabled. RTSP is the Frigate-recommended
protocol for ReoLink cameras.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use MQTT-only event collection (disable webapi), fix ntfy alert
config nesting to match frigate-notify's expected format.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
frigate-notify sends detection snapshots as attachments, which
requires ntfy to have attachment support configured.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Clip/snapshot links in notifications were using the internal
cluster URL (frigate:5000). Set public_url to nvr.ops.eblu.me
so links work from phones.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Uses frigate-notify's EventLink template variable with ntfy's
X-Actions header to link to the Frigate event page, which has
a built-in player that handles H.265 transcoding.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
View Clip linked to raw H.265 MP4 which doesn't play in browsers.
Open Event links to Frigate's review page (built-in player handles
transcoding), Open Camera links to the live camera view.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Go type for headers is []map[string]string, so the YAML entry
must be a map (- Key: "value") not a quoted string (- "Key: value").
The string format silently failed unmarshaling, causing the default
"View Clip" button to always appear instead of custom actions.

Also fix camera URL path (added / before # fragment).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Also update ntfy health check URL from Tailscale to Caddy.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Cars stop being tracked after ~30s stationary (150 frames at 5fps).
Other objects get ~5 minutes (1500 frames) before being dropped.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Switches to native ARM64 image (was likely running under Rosetta/QEMU).
No config breaking changes for our setup (CPU detector, no audio, no
TensorRT/ROCm).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Uses YOLO-NAS-s model exported at 320x320 resolution, stored on NFS
at /media/frigate/models/yolo_nas_s.onnx. Significantly better
detection accuracy than the default SSD MobileNet V1.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Plan verified and marked complete with all checklist items checked
(except IoT VLAN isolation which is a separate plan). Updated open
questions with resolved decisions. Updated changelog fragment to
reflect full scope of deployment.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
eblume merged commit 04c7f3c45a into main 2026-02-14 21:27:45 -08: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
eblume/blumeops!190
No description provided.