The stack
- Cameras — any camera that exposes an RTSP / RTMP stream. Most ONVIF cameras (Reolink, Amcrest, Hikvision, Annke, Dahua) and Frigate-specific options like the Reolink Duo / Doorbell Pro.
- Frigate — the recorder + detector. One container; reads RTSP, runs detection on a sampled subset of frames, writes recordings to disk.
- An AI accelerator (not strictly required, but the difference between "happy" and "100% CPU on a quad-core"). Options below.
- An MQTT broker (see that tutorial) — Frigate publishes detection events; Home Assistant / automations subscribe.
Pick an accelerator
- Google Coral USB / M.2 — the canonical Frigate pick. Detects ~20 ms / inference; about $60. The M.2 form factor needs an M.2-E key slot or a PCIe adapter.
- Intel iGPU (8th gen Core or newer) with OpenVINO — works well, no extra hardware needed, slightly slower than Coral.
- NVIDIA GPU — overkill for detection alone but useful when running other inference on the same box.
- CPU only — fine for one or two cameras at low resolution; doesn't scale.
Plan storage
Frigate writes two stream copies:
- The detect substream — low resolution (640×480), used only for object detection. Discarded after analysis.
- The record stream — high resolution, kept on disk. Continuous, event-only, or hybrid.
Rule of thumb: 4 cameras at 4 MP 24/7 continuous ≈ 200–300 GB/day. Event-only recording is much smaller. Always put recordings on a separate dedicated disk or volume — the writes are relentless.
Install via Docker Compose
# docker-compose.yml
services:
frigate:
container_name: frigate
image: ghcr.io/blakeblackshear/frigate:stable
restart: unless-stopped
privileged: true # for hardware accelerator access
shm_size: "512mb" # for camera frame buffer; scale with #cameras
devices:
- /dev/bus/usb:/dev/bus/usb # for Coral USB
- /dev/dri/renderD128:/dev/dri/renderD128 # Intel iGPU
volumes:
- /etc/localtime:/etc/localtime:ro
- ./config:/config
- /mnt/recordings/frigate:/media/frigate
- type: tmpfs
target: /tmp/cache
tmpfs: { size: 1000000000 } # 1 GB
ports:
- "5000:5000" # web UI
- "8554:8554" # RTSP restream
- "8555:8555/tcp" # WebRTC
- "8555:8555/udp"
environment:
FRIGATE_RTSP_PASSWORD: '<long-random>'
Configuration
Frigate's config is one YAML file at ./config/config.yml:
mqtt:
enabled: true
host: mqtt.lab.example.com
user: frigate
password: '<mqtt-password>'
detectors:
coral:
type: edgetpu
device: usb
# or, for OpenVINO on Intel iGPU:
# ov:
# type: openvino
# device: GPU
go2rtc:
streams:
backyard:
- rtsp://camera-user:camera-pass@192.168.1.50:554/h264Preview_01_main
backyard_sub:
- rtsp://camera-user:camera-pass@192.168.1.50:554/h264Preview_01_sub
cameras:
backyard:
ffmpeg:
inputs:
- path: rtsp://127.0.0.1:8554/backyard
input_args: preset-rtsp-restream
roles: [record]
- path: rtsp://127.0.0.1:8554/backyard_sub
input_args: preset-rtsp-restream
roles: [detect]
detect:
enabled: true
width: 640
height: 480
fps: 5
objects:
track: [person, dog, car, cat]
filters:
person: { min_score: 0.6, threshold: 0.75 }
record:
enabled: true
retain:
days: 14
mode: motion # only keep frames with motion across 14 days
events:
retain:
default: 30 # event-tagged clips kept for 30 days
zones:
driveway:
coordinates: 0,0,640,0,640,300,0,300
objects: [person, car]
snapshots:
enabled: true
retain: { default: 30 }
required_zones: [driveway]
Two cameras worth of config explained
go2rtc— Frigate's bundled restreamer. Cameras have one source feeding both detect and record paths; without it, FFmpeg opens two simultaneous RTSP sessions per camera, which some cameras don't tolerate.- Two FFmpeg inputs per camera — main stream for recording, substream for detection. Most ONVIF cameras provide both.
- Zones — named polygons within the frame. An event is only emitted if a tracked object enters the zone. This is how "ignore the neighbour's dog but alert on people in the driveway" gets implemented.
objects.track— the COCO classes the model can detect (person, car, dog, cat, bicycle, motorcycle, etc.). The defaultssd_mobilenet_v2model trained on COCO handles common indoor/outdoor objects well.
MQTT events and Home Assistant
Every detection / event publishes to frigate/events:
{
"type": "new" | "update" | "end",
"after": {
"id": "1727450000.12345-abc",
"camera": "backyard",
"label": "person",
"zones": ["driveway"],
"score": 0.91,
"box": [123, 456, 250, 580],
"snapshot_time": 1727450000.12,
"current_zones": ["driveway"]
}
}
Home Assistant's official Frigate integration parses these and exposes per-camera, per-object sensors plus a media_player for the live stream. Set up via Settings → Devices & Services → Add Integration → Frigate (after installing it from HACS or the built-in repo).
The web UI
At http://<host>:5000/:
- Live camera grid with WebRTC playback
- Events timeline with filterable object/zone/camera
- Per-event clip viewer with the bounding box overlaid
- Settings → Debug feed with the live detection annotations
The web UI is functional but minimal; for full home-automation surface integration, Home Assistant's Frigate card is the polished consumer view.
Hardening
- Put Frigate behind a reverse proxy with auth (it has its own auth in 0.14+; older versions need an outer proxy with basic auth or an OIDC layer via Authentik / Step CA).
- Camera RTSP credentials are baked into the config — restrict the YAML's file permissions and don't commit secrets to a public repo.
- Run cameras on an isolated VLAN with no internet access. Most cheap IP cameras phone home in ways their datasheets don't disclose.
Performance worth knowing
- One Coral TPU handles roughly 5–8 cameras at 5 FPS detection. Two Corals or a more powerful GPU for more.
- Detection at 5 FPS × 640×480 is enough for object tracking; pushing to 10 FPS doubles inference work for marginal accuracy gain.
- Recording bitrate — most cameras default to 8–12 Mbps for 4 MP H.264. H.265 cuts that in half if the camera and downstream players support it.