Skip to content

Frigate NVR Setup

Frigate — 4 camera live view with AI detection

Frigate is a self-hosted NVR running inside a Docker container on a privileged Proxmox LXC, providing real-time AI object detection, recording, and snapshot capture for all four PoE cameras — completely local with no cloud dependencies.

Why Frigate?

The FUTO philosophy is clear: own your surveillance footage locally. Cloud-based camera systems (Ring, Nest) send your video to someone else's servers. Frigate runs entirely locally, stores recordings on your own NAS, and does AI-based object detection without phoning home.

The Reolink RLC-510A cameras support RTSP streaming, which Frigate ingests directly. No cloud account required.

Architecture

graph LR
    subgraph IoT["IoT VLAN (10.0.30.x)"]
        DB["Doorbell<br/>10.0.30.117"]
        FC["Front Camera<br/>10.0.30.114"]
        SC["Side Camera<br/>10.0.30.115"]
        RC["Rear Camera<br/>10.0.30.116"]
    end
    subgraph MGMT["Management VLAN (10.0.10.x)"]
        Frigate["Frigate NVR<br/>LXC 102 · 10.0.10.104"]
        NAS["Pi 5 NAS<br/>10.0.10.50"]
        HA["Home Assistant<br/>10.0.10.60"]
    end

    DB -- "RTSP" --> Frigate
    FC -- "RTSP" --> Frigate
    SC -- "RTSP" --> Frigate
    RC -- "RTSP" --> Frigate
    Frigate -- "NFS" --> NAS
    Frigate -- "MQTT" --> HA

Hardware

Cameras:

Location Model IP MAC
Doorbell Reolink PoE Doorbell 10.0.30.117 ec:71:db:xx:xx:xx
Front Reolink RLC-510A (5MP) 10.0.30.114 ec:71:db:xx:xx:xx
Side Reolink RLC-510A (5MP) 10.0.30.115 ec:71:db:xx:xx:xx
Rear Reolink RLC-510A (5MP) 10.0.30.116 ec:71:db:xx:xx:xx

All cameras are powered via PoE from the USW-Lite-8-PoE switch with ports assigned to the IoT VLAN profile.

Compute: Frigate runs as LXC container 102 on pve1 (HP EliteDesk 800 G3 Mini, i7-6700T). The Intel HD 530 iGPU provides both VAAPI hardware video decoding and OpenVINO AI object detection.

LXC Container

The Frigate container runs as a privileged LXC to allow GPU device passthrough and future Coral TPU support.

Setting Value
CT ID 102
Node pve1
IP 10.0.10.104/24
Gateway 10.0.10.1
RAM 4096 MB
CPU 4 cores
Disk 16 GB (local-lvm)
Type Privileged (unprivileged=0)
Features nesting=1

Intel iGPU Passthrough

The Intel HD 530 iGPU is passed through to the LXC for hardware-accelerated video decoding (VAAPI) and AI inference (OpenVINO). This is configured in the container's Proxmox config file.

On pve1 host — edit /etc/pve/lxc/102.conf:

lxc.cgroup2.devices.allow: c 226:* rwm
lxc.mount.entry: /dev/dri dev/dri none bind,optional,create=dir

After adding these lines, restart the container. Frigate auto-detects the GPU and enables VAAPI decoding.

Storage

Recordings and snapshots are stored on the Pi 5 NAS (10.0.10.50) via NFS.

NAS side (OMV7):

  1. Create shared folder frigate-recordings on the RAID 5 array
  2. Enable NFS share for 10.0.10.0/24 with rw,no_root_squash permissions

Proxmox host side — mount and bind into LXC:

# /etc/fstab on pve1
10.0.10.50:/export/frigate-recordings /mnt/nas-frigate nfs defaults 0 0
# /etc/pve/lxc/102.conf
mp0: /mnt/nas-frigate,mp=/mnt/nas-frigate

Inside the container, the NFS mount appears at /mnt/nas-frigate and is mapped to /media/frigate in the Docker container via the compose file.

Docker Compose

version: "3.9"
services:
  frigate:
    container_name: frigate
    privileged: true
    restart: unless-stopped
    image: ghcr.io/blakeblackshear/frigate:stable
    shm_size: "640mb"
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - ./config:/config
      - /mnt/nas-frigate:/media/frigate
      - type: tmpfs
        target: /tmp/cache
        tmpfs:
          size: 1000000000
    ports:
      - "5000:5000"
      - "8554:8554"
      - "8555:8555/tcp"
      - "8555:8555/udp"
    devices:
      - /dev/dri:/dev/dri

SHM Size

With 4 cameras (8 streams total — main + sub per camera), the default 64MB SHM is far too small. Frigate recommends at least 634MB. Set shm_size: "640mb" or higher. Insufficient SHM causes frame drops, decoder crashes, and intermittent black screens.

Frigate Configuration

The full config/config.yml with all four cameras, OpenVINO detection, VAAPI hardware decode, and dual-stream recording with tiered retention:

mqtt:
  enabled: true
  host: 10.0.10.60
  port: 1883
  user: mqtt
  password: "<your-mqtt-password>"

ffmpeg:
  hwaccel_args: preset-vaapi

go2rtc:
  streams:
    doorbell:
      - rtsp://admin:<password-url-encoded>@10.0.30.117:554/h264Preview_01_main
    doorbell_sub:
      - rtsp://admin:<password-url-encoded>@10.0.30.117:554/h264Preview_01_sub
    front_camera:
      - rtsp://admin:<password-url-encoded>@10.0.30.114:554/h264Preview_01_main
    front_camera_sub:
      - rtsp://admin:<password-url-encoded>@10.0.30.114:554/h264Preview_01_sub
    side_camera:
      - rtsp://admin:<password-url-encoded>@10.0.30.115:554/h264Preview_01_main
    side_camera_sub:
      - rtsp://admin:<password-url-encoded>@10.0.30.115:554/h264Preview_01_sub
    rear_camera:
      - rtsp://admin:<password-url-encoded>@10.0.30.116:554/h264Preview_01_main
    rear_camera_sub:
      - rtsp://admin:<password-url-encoded>@10.0.30.116:554/h264Preview_01_sub

detectors:
  ov:
    type: openvino
    device: GPU
    model_path: /openvino-model/ssdlite_mobilenet_v2.xml

model:
  width: 300
  height: 300
  input_tensor: nhwc
  input_pixel_format: bgr
  labelmap_path: /openvino-model/coco_91cl_bkgr.txt

detect:
  enabled: true

cameras:
  doorbell:
    ffmpeg:
      inputs:
        - path: rtsp://127.0.0.1:8554/doorbell
          roles:
            - record
        - path: rtsp://127.0.0.1:8554/doorbell_sub
          roles:
            - detect
    detect:
      width: 640
      height: 480
      fps: 5
    record:
      enabled: true
      retain:
        days: 3
        mode: motion
      alerts:
        retain:
          days: 14
      detections:
        retain:
          days: 14
    snapshots:
      enabled: true
      retain:
        default: 14
    objects:
      track:
        - person
        - car
        - dog
        - cat

  front_camera:
    ffmpeg:
      inputs:
        - path: rtsp://127.0.0.1:8554/front_camera
          roles:
            - record
        - path: rtsp://127.0.0.1:8554/front_camera_sub
          roles:
            - detect
    detect:
      width: 640
      height: 480
      fps: 5
    record:
      enabled: true
      retain:
        days: 3
        mode: motion
      alerts:
        retain:
          days: 14
      detections:
        retain:
          days: 14
    snapshots:
      enabled: true
      retain:
        default: 14
    objects:
      track:
        - person
        - car
        - dog
        - cat

  side_camera:
    ffmpeg:
      inputs:
        - path: rtsp://127.0.0.1:8554/side_camera
          roles:
            - record
        - path: rtsp://127.0.0.1:8554/side_camera_sub
          roles:
            - detect
    detect:
      width: 640
      height: 480
      fps: 5
    record:
      enabled: true
      retain:
        days: 3
        mode: motion
      alerts:
        retain:
          days: 14
      detections:
        retain:
          days: 14
    snapshots:
      enabled: true
      retain:
        default: 14
    objects:
      track:
        - person
        - car
        - dog
        - cat

  rear_camera:
    ffmpeg:
      inputs:
        - path: rtsp://127.0.0.1:8554/rear_camera
          roles:
            - record
        - path: rtsp://127.0.0.1:8554/rear_camera_sub
          roles:
            - detect
    detect:
      width: 640
      height: 480
      fps: 5
    record:
      enabled: true
      retain:
        days: 3
        mode: motion
      alerts:
        retain:
          days: 14
      detections:
        retain:
          days: 14
    snapshots:
      enabled: true
      retain:
        default: 14
    objects:
      track:
        - person
        - car
        - dog
        - cat

version: 0.16-0
semantic_search:
  enabled: true
  model_size: large
face_recognition:
  enabled: true
  model_size: large
lpr:
  enabled: true
classification:
  bird:
    enabled: false

Stream Architecture

Each camera uses a dual-stream approach to balance detection quality with storage efficiency:

  • Main stream (h264Preview_01_main at 2560×1920) → used for recording, saving full 5MP quality to the NAS
  • Sub stream (h264Preview_01_sub at 640×480) → used for AI detection, already close to the 300×300 model input size so minimal CPU is needed for downscaling

All streams pass through go2rtc for restreaming, which provides stable WebRTC playback in the UI and prevents multiple direct connections to the cameras.

VAAPI hardware decode is enabled globally via ffmpeg: hwaccel_args: preset-vaapi, offloading video decoding to the Intel HD 530 iGPU for all cameras including the doorbell.

Tiered Retention (Frigate 0.16 schema)

Frigate 0.16 uses alerts and detections keys (not the old events key) for tiered retention:

Retention Type Duration What It Keeps
Motion 3 days Any segment with motion detected
Alerts 14 days Segments where tracked objects triggered alerts
Detections 14 days Segments where AI detected objects of interest

This tiered approach dropped NAS usage from 99% to ~30% steady state — well within the 2.58 TiB usable capacity.

AI Features

Frigate 0.16 includes several AI capabilities enabled in this deployment:

  • Semantic search — natural language search across recorded events (large model, GPU-accelerated)
  • Face recognition — identifies known faces from snapshots (large model, GPU-accelerated)
  • LPR (License Plate Recognition) — reads number plates from detected vehicles
  • Object tracking — person, car, dog, and cat detection on all cameras

Detection Performance

The Intel HD 530 iGPU running OpenVINO provides significant performance improvements over CPU-based detection:

Metric CPU Detector OpenVINO (GPU)
Inference speed 482 ms 8.98 ms
Detector CPU usage 174.7% 14.0%
Improvement 53× faster

This performance headroom comfortably supports all 4 cameras simultaneously with room to spare.

Firewall Rules

Frigate needs cross-VLAN access to reach the cameras on the IoT VLAN.

OPNsense → Firewall → Rules → MGMT interface:

Action Protocol Source Destination Description
Pass TCP/UDP 10.0.10.104 10.0.30.0/24 Allow Frigate to access cameras

Network Cabling

All four cameras are wired with outdoor-rated Cat6 cable to the USW-Lite-8-PoE switch. Cable runs were planned using floor plan measurements:

Camera Approximate Run
Doorbell (front door) ~12m
Front (front of property) ~15m
Side (side passage) ~20m
Rear (back garden) ~30m

Total cable used: approximately 77 metres of outdoor-rated Cat6.

Adding New Cameras

To add a camera to the system:

  1. Connect the camera to a PoE port on the switch with IoT VLAN profile
  2. Create a static DHCP reservation in OPNsense (Services → DHCPv4 → IoT)
  3. Set admin credentials on the camera via its web UI
  4. Add the RTSP stream URLs to go2rtc.streams in the Frigate config
  5. Add the camera definition to the cameras section
  6. Restart Frigate: docker compose restart frigate

Storage Considerations

With the corrected stream architecture (main stream for recording, sub stream for detection), storage usage is significantly reduced compared to recording the full 5MP main stream:

Estimated storage usage with tiered retention:

Scenario Daily (est.) Steady State
4 cameras, main stream record, 3d motion + 14d alerts ~25–40 GiB ~500–700 GiB

The NAS has 2.58 TiB usable, providing over a terabyte of headroom.

Home Assistant Integration

Frigate integrates with Home Assistant via MQTT (Mosquitto broker), enabling:

  • Live camera feeds on the HA dashboard using picture-glance cards with native Frigate camera entities (no iframes needed)
  • Mobile push notifications via the Frigate Notifications blueprint from HACS — sends snapshot with bounding box when a person is detected at the doorbell
  • Event-driven automations based on object detection events

For full Home Assistant setup, see the Home Assistant guide.

Lessons Learned

Stream roles matter — sub for detect, main for record. The detection model input is 300×300 pixels. Sending 5MP frames to the detector wastes massive CPU on downscaling. The sub-stream at 640×480 is already close to model input size. Meanwhile, the main stream records at full 5MP quality to the NAS.

URL-encode special characters in passwords. The # character is interpreted as a URL fragment delimiter in RTSP URLs, silently truncating the password. Use %23 instead of #.

SHM size must scale with camera count. The default 256MB is adequate for 1–2 cameras but causes crashes with 4. Frigate logs the recommended minimum — watch for the warning on startup.

VAAPI globally with preset-vaapi. Enable hardware decode for all cameras at the global ffmpeg level rather than per-camera. This ensures the doorbell and all other cameras use iGPU decode.

Tiered retention saves storage. The jump from flat 14-day retention to 3-day motion / 14-day alerts dropped NAS usage from 99% to ~30%.

VLAN double-tagging. If the Proxmox host bridge already carries the management VLAN as untagged traffic, do not add a VLAN tag to the LXC network interface. Double-tagging prevents the container from getting an IP address.

go2rtc restreaming is essential. Connecting Frigate directly to camera RTSP streams causes multiple concurrent connections to each camera, leading to instability. Routing everything through go2rtc ensures a single connection per camera with stable restreaming to all consumers.