Frigate NVR Setup: Self-Hosted Camera Recording with Object Detection
Run Frigate as your own NVR in Docker: picking a detector in 2026, PoE cameras and switch, substreams for detection, recording retention, and keeping it off the internet.
This post contains affiliate links. If you buy through them, I earn a small commission at no extra cost to you.
Frigate is a self-hosted NVR that does real object detection, which means it can tell the difference between a person walking up your driveway and a tree moving in the wind. That distinction is the entire reason to run it instead of whatever recording mode your cameras came with. If you have worked through Docker Compose basics, the install itself is not hard; the parts that take thought are which detector to use and how much footage you keep.
This guide walks the whole path: picking a detector in 2026, the camera and PoE switch side, a working Compose file and config, and the retention and access decisions that matter more than the install. The hardware recommendation has genuinely changed in the last year, so if you read an older Frigate guide that told you to buy a Coral TPU first, start with the next section.
Quick Answer
Run Frigate in Docker with the detect role on a low-resolution camera substream and the record role on the main stream. For the detector, use OpenVINO on an Intel iGPU if the host has one, which costs nothing and is what most budget builds should do:
detectors:
ov:
type: openvino
device: GPU
Do not buy a Coral TPU for a new install. Frigate’s own hardware documentation now states that “The Coral is no longer recommended for new Frigate installations, except in deployments with particularly low power requirements or hardware incapable of utilizing alternative AI accelerators for object detection.” The rest of this guide covers the camera side, the Compose file, retention, and keeping it off the internet.
The Detector Decision Changed
For several years the standard Frigate advice was to buy a Google Coral Edge TPU before anything else. That advice is out of date, and following it now means spending money on a part the project itself steers new installs away from.
Here is where the options actually stand, per Frigate’s own hardware page:
| Detector | What it needs | Notes |
|---|---|---|
| OpenVINO | A 6th-gen-or-newer Intel platform with an iGPU, an Arc GPU, or an Intel NPU | The budget answer. Uses hardware you likely already bought. device: GPU, CPU, or NPU. |
| Hailo-8 / 8L | An M.2 slot, or a HAT on a Raspberry Pi | Listed first in Frigate’s current accelerator tier. The option to design around if you want a dedicated accelerator. |
| Google Coral Edge TPU | USB, Mini PCIe, or M.2 | Still supported, explicitly described as not recommended for new installs except where power draw is the binding constraint. |
| ONNX | An Nvidia CUDA GPU (use the -tensorrt image) | Fine if a suitable GPU is already in the box. |
| AMD ROCm | A discrete AMD GPU (use the -rocm image) | Supported, less commonly travelled in homelab writeups. |
| CPU | Nothing | Shipped, and explicitly not recommended. Proof-of-concept only. |
The honest read: if your Frigate host is an N100-class mini PC or any reasonably recent Intel box, you already own a perfectly good detector and the right move is to use it. That is the setup this guide configures by default. The mini PC buying guide covers the hardware side if you are still choosing a host; what matters for Frigate specifically is an Intel CPU with AVX and AVX2 support and an iGPU.
If you want a dedicated accelerator anyway, Frigate currently lists Hailo-8/8L ahead of the Coral. And if you already own a Coral, keep using it; type: edgetpu is still supported and nothing here says to replace working hardware.
What You Need
- A Frigate host. An Intel CPU with AVX and AVX2 instructions, capable of running Debian, with an iGPU if you want OpenVINO. This can be a VM or an LXC on an existing Proxmox host, though a VM is the simpler path for device passthrough.
- PoE cameras with RTSP. The single most important spec is not resolution, it is whether the camera exposes a configurable substream alongside its main stream, and whether it gives you a plain RTSP URL. Cameras that only talk to a vendor cloud app are useless here.
- A PoE switch with power budget for every camera you plan to add, not just today’s. The budget managed switch guide covers the options, and a managed switch lets you put cameras on their own VLAN.
- Storage for recordings, sized from your own retention math rather than a number from a guide. See Step 7.
- Patience for the camera URL step, reliably where the most time goes. Every manufacturer formats its RTSP paths differently and the documentation is often wrong.
Specific camera model recommendations go stale fast, and firmware revisions change what substreams a model exposes. Check the manufacturer’s spec sheet for RTSP and substream support before buying, and check current price rather than trusting a figure in any guide, including this one.
Step 1: Plan the Network Side First
Cameras are the one part of a homelab where network design should come before software. Two decisions pay off later:
Put the cameras on their own VLAN. Cheap IP cameras are not well-maintained software and many of them would very much like to phone home. A separate VLAN with no outbound internet route, plus a firewall rule allowing only your Frigate host to reach them, contains that. It is the highest-value thing you can do for camera security, and it is why a managed switch earns its small premium over an unmanaged one.
Size the PoE budget for the build you want. A switch’s total power budget matters more than its per-port rating, and the failure mode is ports cutting out under load rather than a clear error.
Throughout this guide, cameras live at 10.0.0.x and the Frigate host at 10.0.0.10; substitute your own.
Step 2: Create the Directory Layout
Frigate needs two persistent locations that should not be the same disk if you can help it: a small config directory, and a much larger recordings directory.
# config: holds config.yml and the sqlite database. Small, back this up.
mkdir -p /opt/frigate/config
# storage: holds recordings, snapshots, and exports. Large, do not back this up.
mkdir -p /srv/frigate/media
These get treated differently. The config directory is a few megabytes and holds the database Frigate uses for event history, so it belongs in your backup rotation alongside everything else in the restic backups guide. The media directory is hundreds of gigabytes of footage that ages out on its own and has no business in an offsite backup.
Step 3: Write the Compose File
Frigate’s documented Compose example, with the detector mapping added for OpenVINO:
services:
frigate:
container_name: frigate
image: ghcr.io/blakeblackshear/frigate:stable
restart: unless-stopped
stop_grace_period: 30s
shm_size: "512mb"
devices:
# Intel iGPU, for OpenVINO detection and hardware-accelerated decoding
- /dev/dri/renderD128:/dev/dri/renderD128
volumes:
- /etc/localtime:/etc/localtime:ro
- /opt/frigate/config:/config
- /srv/frigate/media:/media/frigate
- type: tmpfs
target: /tmp/cache
tmpfs:
size: 1000000000
ports:
- "8971:8971" # authenticated web UI
- "8554:8554" # RTSP restream
- "8555:8555/tcp" # WebRTC
- "8555:8555/udp" # WebRTC
environment:
TZ: "America/New_York"
Three things in there deserve explanation, because they are the ones people get wrong:
shm_size is shared memory for frame buffers and it scales with camera count and resolution. The documented 512mb is a starting point, not a universal answer; Frigate’s install docs provide an SHM calculator and recommend using it rather than assuming a fixed value. If Frigate logs errors about running out of shared memory, this is the knob.
The tmpfs mount on /tmp/cache is not optional housekeeping. Recording segments are written there first and converted to mp4 before landing in /media/frigate. Leaving it on disk means writing every segment twice to your storage, which is how people wear out an SSD running an NVR.
The device mapping. /dev/dri/renderD128 is what gives the container the Intel iGPU, for both OpenVINO detection and hardware-accelerated video decoding. Confirm the path exists on your host first:
ls -l /dev/dri/
If you see renderD128, you are set. If /dev/dri does not exist at all, the host either has no iGPU or is not exposing it, which is the common situation in an unprivileged LXC and the main reason a VM is the easier path here. Frigate’s install docs use privileged: true in their example; a specific device mapping is the tighter version, and prefer it where it works. A USB Coral needs a USB device mapping instead of this one.
Step 4: Write a Minimal config.yml
Start with exactly one camera. Resist the urge to add all six at once, because debugging a camera URL is far easier when it is the only thing that could be wrong.
mqtt:
enabled: false
detectors:
ov:
type: openvino
device: GPU
cameras:
driveway:
enabled: true
ffmpeg:
inputs:
# substream: low resolution, used for detection
- path: rtsp://viewer:{FRIGATE_RTSP_PASSWORD}@10.0.0.21:554/cam/realmonitor?channel=1&subtype=2
roles:
- detect
# main stream: full resolution, used for recordings
- path: rtsp://viewer:{FRIGATE_RTSP_PASSWORD}@10.0.0.21:554/cam/realmonitor?channel=1&subtype=0
roles:
- record
detect:
width: 1280
height: 720
objects:
track:
- person
- car
The two-input pattern is the core of a sane Frigate config. Frigate’s documentation recommends you “use a lower resolution stream for object detection, but create recordings from a higher resolution stream,” which is what the two roles above do: detection reads a 720p substream, recordings come from the 4K main stream. Detection gets scaled to the detector’s input size regardless, so decoding 4K frames for it is pure waste.
Note the {FRIGATE_RTSP_PASSWORD} substitution rather than a plaintext password in the config. Set it in the container environment and keep credentials out of the file you are going to commit somewhere or paste into a forum thread when asking for help.
The RTSP paths above are Dahua-style, an example rather than a universal format; yours will differ by manufacturer. Test them with ffprobe from the host before putting anything in the config:
ffprobe "rtsp://viewer:password@10.0.0.21:554/cam/realmonitor?channel=1&subtype=2"
If ffprobe reports a resolution and codec, the URL is good. If it hangs or errors, the URL is wrong and no amount of Frigate configuration will fix it. Work out both URLs this way first.
Worth doing early: create a dedicated read-only viewer account on each camera rather than pointing Frigate at admin credentials. If the config ever leaks, a viewer account is a much smaller problem.
Step 5: Start It and Watch the Logs
cd /opt/frigate
docker compose up -d
docker compose logs -f frigate
The logs are the whole diagnostic story on a first run. What you want to see is the detector initialising and the camera’s ffmpeg process starting without repeatedly restarting. What you do not want is a loop of ffmpeg errors, which almost always means the RTSP URL or credentials are wrong.
Then open https://10.0.0.10:8971 and complete the login. Port 8971 is the authenticated UI that Frigate added specifically so the interface is not wide open by default; use it rather than the unauthenticated internal port.
Step 6: Verify the Detector Is Actually Being Used
This is the step most guides skip, and skipping it is how people run on CPU for months believing they configured an accelerator. Some misconfigurations fall back rather than fail loudly, so verify directly.
In the Frigate UI, open the System metrics page and look for two things: the detector listed by name with an inference speed in milliseconds, and CPU usage low relative to what detection on that many cameras would cost.
If the detector is missing or inference looks implausibly slow, go back to the device mapping and the logs. An iGPU not actually reaching the container is the usual cause:
docker compose exec frigate ls -l /dev/dri/
Treat a working inference figure as the gate for adding more cameras. Adding five more on a broken detector only makes the diagnosis harder.
Step 7: Decide Retention Deliberately
Retention is the decision that determines your disk bill, and the defaults are not a choice you should inherit silently. Frigate separates retention into continuous recording and event-based retention:
record:
enabled: true
continuous:
days: 1
motion:
days: 2
alerts:
retain:
days: 10
mode: all
detections:
retain:
days: 10
mode: all
snapshots:
enabled: true
retain:
default: 14
In the documentation’s terms, continuous retention “preserves all video” regardless of activity, while alerts and detections retention only preserves “recording segments that overlap with alerts and detections.” For a camera pointed at a quiet driveway that difference is enormous.
A reasonable pattern for a budget build is a short continuous window plus a longer event window, which is what the block above does: a day of everything so you can scrub back through an evening, plus ten days of actual events. Continuous recording for weeks on every camera is what fills a disk, and it is rarely what people actually use.
Do not take those numbers as sized for you. Run it for a week, look at what /srv/frigate/media actually consumed, and scale from your own figure; camera bitrate varies enormously with scene complexity and compression settings, so your real numbers beat any in a guide. The record schema has also shifted across Frigate releases, so check the documentation for the version you are running.
Step 8: Cut False Alerts With Zones
A fresh Frigate install pointed at a street-facing camera will alert on every passing car, which trains you to ignore it inside two days. Zones are the fix:
cameras:
driveway:
# ...inputs as above...
zones:
my_driveway:
coordinates: 0.1,0.9,0.1,0.4,0.8,0.4,0.8,0.9
objects:
- person
- car
review:
alerts:
required_zones:
- my_driveway
Coordinates are normalised, so they survive a resolution change. Drawing them by hand is unpleasant; the Frigate UI has a zone editor that writes this block for you, which is the sane path.
The required_zones filter is the part that matters: it says an event only becomes an alert if the object entered your driveway, so the public sidewalk stops generating notifications while still being recorded as a detection. That distinction, alerts versus detections, is what makes the notifications worth having.
Resist tuning thresholds before you have watched real footage for a few days. The usual mistake is raising confidence thresholds to silence false positives when the actual problem was a zone covering the street.
Step 9: Keep It Off the Internet
An NVR holds continuous video of your home. It is the single worst candidate in a homelab for a port forward, and “but it has a login now” is not a sufficient reason to expose it.
The options, in order of how much I’d recommend them:
- A VPN, such as Tailscale. Nothing is exposed; your phone joins the network and reaches Frigate at its LAN address. For a single-user NVR this is the right answer and the one I’d pick.
- A reverse proxy reachable only on the LAN or tailnet. If you are already running Nginx Proxy Manager for a clean hostname and a certificate, point it at Frigate but do not give it a public DNS record.
- A public reverse proxy with authentication in front. Defensible if you genuinely need browser access from arbitrary networks, but you have now taken on responsibility for keeping that edge patched.
Do not forward port 8971 on your router. The homelab security guide covers the broader reasoning, and the camera VLAN from Step 1 is the other half: Frigate reaches the cameras, the cameras reach nothing.
Finally, back up /opt/frigate/config. It is small, it holds both config.yml and the event database, and rebuilding a tuned multi-camera config with hand-drawn zones from memory is a miserable afternoon. The recordings directory ages out by design and does not need backing up.
What This Actually Costs
The software is free and the detector probably is too, which leaves cameras, switch, and disk as the real spend:
| Line item | Notes |
|---|---|
| Frigate | Free and open source. |
| Detector | Free if the host has an Intel iGPU and you use OpenVINO. A Hailo-8/8L or a Coral is an added cost you probably do not need. |
| Host | The box you already run, or a mini PC from the buying guide. Check current price. |
| PoE cameras | Per camera, and the largest line as camera count grows. Check current price. |
| PoE switch | See the managed switch guide. Budget for the camera count you want, not today’s. |
| Storage | Driven entirely by your retention choices in Step 7. |
The detector line is where 2026 advice differs most from older writeups: if the host has a recent Intel iGPU, that is your detector, and the money you were about to spend on an accelerator is better put toward another camera or a bigger disk. Running costs are power for the host, switch, and cameras; the homelab power usage piece covers working that out from your own hardware and rate.
Where to Go Next
Once Frigate is recording reliably, the next steps are notifications and uptime monitoring. Frigate publishes events over MQTT, which is the usual hook for a phone notification when a person enters a zone, and it integrates with Home Assistant if you run it. Adding Frigate to Uptime Kuma is worth five minutes too, because a silently stopped NVR is worse than no NVR: you find out it was down at exactly the moment you needed the footage.