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.