by: Helge, published: May 24, 2025, in

Frigate: NVR With Object Detection on Raspberry Pi 5 & Coral TPU

This article explains how to install and configure the Frigate NVR software on a Raspberry Pi 5 with a Coral Edge TPU.

Overview

What is Frigate?

Frigate is a free network video recorder (NVR) software. It collects your surveillance camera video streams (typically via RTSP), performs object detection and stores the resulting clips.

Local Object Detection With a Coral Edge TPU

One of the most important features of an NVR is object detection. You want to review relevant movement only (e.g., people), not leaves blowing in the wind. By offloading object detection to an inexpensive Coral Edge TPU, Frigate achieves excellent detection quality even on low-cost hardware like a Raspberry Pi. As a big plus, everything runs locally without uploading your video streams to the cloud.

Hardware Choices

I selected a Raspberry Pi 5 as the basis for my NVR. The OS goes on a 32 GB SD card while a 512 GB NVMe SSD provides reliable storage for the recordings.

Initially, I went for the PCIe version of the Coral Edge TPU but that turned out to be a bad idea. It requires a driver that doesn’t seem to be maintained anymore and causes errors when updating the OS. The USB version of the Coral Edge TPU is a much better choice. It doesn’t require any custom software on the OS. Everything that is needed is included in the Frigate Docker image.

Installing and Configuring Raspberry Pi OS

Raspberry Pi Imager

  • Connect the SD card you want to use for the Raspberry Pi OS to your PC.
  • Download, install, and run the Raspberry Pi Imager.
  • Select your Pi model, the 64-bit Pi OS and your SD card. Click Next.
  • The Use OS customization? dialog comes up.
  • Click Edit settings and configure:
    • General:
      • Hostname: nvr-int
      • Username and password: set according to your preference
      • Configure wireless LAN: specify your WiFi’s SSID and password
      • Set locale settings: set according to your preference
    • Services:
      • Enable SSH: checked
      • Allow public-key authentication only: selected. Paste your public key into the text box.
    • Click Save to close the settings dialog.
  • You’re back in the Use OS customization? dialog. Select yes.
  • Let the imager write the OS image to the SD card.

First Boot

  • Insert the SD card into the Raspberry’s slot.
  • If you use a HAT for SSD storage, put it in place and connect it to the Raspberry Pi.
  • Connect the Coral Edge TPU with the included cable to one of the (blue) USB 3.0 ports.
  • Connect the power supply, powering on the Raspberry.
  • The Raspberry Pi should now be connected to your WiFi network.
  • Convert the dynamic DHCP address to static and configure a DNS record for name resolution.

Initial Configuration

Connect via SSH to the Raspberry using the key you specified earlier.

Update the OS:

sudo apt update && sudo apt dist-upgrade

Partition and format the NVMe SSD:

sudo fdisk /dev/nvme0n1
sudo mkfs.ext4 /dev/nvme0n1p1

Create a mount point and mount the NVMe SSD:

sudo mkdir /data
sudo mount /dev/nvme0n1p1 /data

Configure mounting the NVMe SSD into the /data directory at boot by editing /etc/fstab:

/dev/nvme0n1p1  /data  ext4  defaults  0  2

Reboot and verify that the SSD is mounted by running lsblk.

Verify that the Coral Edge TPU USB device is connected correctly by running lsusb. The device should show up as Global Unichip Corp. as it’s still uninitialized. Once initialized by Frigate it’ll be listed as Google Inc (docs).

Note: Some guides recommend assigning more RAM to the GPU by adding gpu_mem=512 to /boot/firmware/config.txt. Due to the changed GPU memory allocation scheme of the Raspberry Pi 5, this is not only not necessary anymore, but the setting is completely ignored. The GPU memory as shown by vcgencmd get_mem gpu is always a fixed carveout of 4 MB.

Installing Frigate

Installing Docker

Frigate comes as a Docker image, so we’ll first install and configure Docker according to my documentation here. Proceed only once Docker is installed.

Dockerized Frigate Directory Structure

This is what the directory structure will look like when we’re done:

data/
 └── docker/
     └── frigate/
         ├── config/
             └── config.yml
         ├── data/
         ├── container-vars.env
         └── docker-compose.yml

Create the new directories:

sudo mkdir -p /data/docker/frigate/config
sudo mkdir -p /data/docker/frigate/data

Frigate Docker Compose File

Create docker-compose.yml with the following content:

services:
  frigate:
    container_name: frigate
    image: ghcr.io/blakeblackshear/frigate:stable
    privileged: true
    restart: unless-stopped
    shm_size: "512mb"
    devices:
      - /dev/bus/usb:/dev/bus/usb
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /data/docker/frigate/config:/config
      - /data/docker/frigate/data:/media/frigate
      - type: tmpfs
        target: /tmp/cache
        tmpfs:
          size: 1000000000
    ports:
      - "8971:8971"        # WebGUI TLS self-signed cert
      - "8554:8554"        # RTSP feeds

Create Frigate’s config file config/config.yml with the following content:

mqtt:
  enabled: false

detectors:
  coral:
    type: edgetpu
    device: usb

cameras:
  # ADD CAMERA(S) HERE

record:
  enabled: true
  retain:
    days: 0
  alerts:
    retain:
      days: 30
      mode: motion
  detections:
    retain:
      days: 30
      mode: motion

tls:
  enabled: false     # Handled by Caddy

auth:
  enabled: false     # Handled by Caddy

Note: The above config lacks the camera configuration as that depends on your camera hardware. See the docs for details.

Start the Frigate Container

Navigate into the directory with docker-compose.yml and run:

sudo docker compose up -d

Notes:

  • Be patient! It’ll take a while until Frigate is fully initialized.
  • When started for the first time, Frigate may have to initialize the Coral. You may have to stop and restart the container after initialization.

Inspect the container logs for errors with the command sudo docker compose logs --tail 100 --timestamps.

Expected Errors During Frigate Startup

[error] 177#177: *1 connect() failed (111: Connection refused) while connecting to upstream, client: 127.0.0.1, server: , request: "GET /api/version HTTP/1.1", subrequest: "/auth", upstream: "http://127.0.0.1:5001/auth", host: "127.0.0.1:5000"

[error] 177#177: *1 auth request unexpected status: 502 while sending to client, client: 127.0.0.1, server: , request: "GET /api/version HTTP/1.1", host: "127.0.0.1:5000"

Log Messages When Startup is Successful

INFO: Attempting to load TPU as usb
INFO: TPU found
INFO: Camera processor started for CAM_NAME
INFO: Capture process started for CAM_NAME
INFO: FastAPI started

Let’s Encrypt Certificate for Frigate via Caddy

Caddyfile

Add the following to Caddyfile (details):

nvr.{$MY_DOMAIN} {
	import auth
	reverse_proxy nvr-int.{$MY_DOMAIN}:8971
	tls {
		dns cloudflare {env.CLOUDFLARE_API_TOKEN}
	}
}

Note: the definition of the auth snippet can be found here.

DNS A Records

Add the following A records to your DNS domain (details):

nvr.home.yourdomain.com 192.168.0.4     # replace with your Docker host's IP address

Try to resolve the name on a machine in your network (e.g., nslookup nvr.home.yourdomain.com).

Reload Caddy’s Configuration

Instruct Caddy to reload its configuration by running:

docker exec -w /etc/caddy caddy caddy reload

You should now be able to access Frigate at https://nvr.home.yourdomain.com without getting a certificate warning from your browser.

Frigate: Verification & Initial Configuration

Verifying Your Installation from the Web UI

If you configured your cameras correctly, you should see a thumbnail live view of each camera feed on the homepage.

Verify that the UI shows System is healthy in the lower-right corner.

Navigate the Settings > System logs. There should be no errors and only the following warning: Did not detect hwaccel, using a GPU for accelerated video decoding is highly recommended. Currently, there doesn’t seem to be hardware acceleration for the GPU of the Raspberry Pi 5 (docs).

Frigate CPU & RAM Utilization

Navigate to Settings > System metrics and inspect all three tabs (General, Storage, Cameras). Frigate provides nicely detailed performance metrics.

In my setup with two video streams, Frigate uses the following system resources on average:

  • Raspberry load average: 0.3 (as measured by htop)
  • Raspberry CPU: 6-8% (as measured by Frigate)
  • Raspberry memory: 1.6 GB (as measured by htop)
  • Coral CPU: 0-5% (as measured by Frigate)
  • Coral memory: 3.5% (as measured by Frigate)

Initial Configuration

UI Settings

Navigate to Settings > Configuration > Settings > UI Settings and configure the following:

  • Recordings Viewer > Default Playback Rate: 2x
  • Calendar > First weekday: Monday

Masks and Zones

You may want to define detection masks (also called zones). This prevents Frigate from recording when someone walks on the street, for example.

To define masks, navigate to Settings > Configuration > Settings > Masks/Zones and create a zone.

Switch over to the Camera Settings tab and enable the alerts and detections for the zone you created:

  • Alerts: enabled (All person, car objects detected in ZONE on CAM will be shown as Alerts)
  • Detections:
    • Limit detections to specific zones: enabled (All objects not classified as Alerts that are detected in ZONE on CAM will be shown as Detections.)

Backup

OS & App Configuration

I’m using my Linux config file backup script to back up OS and Frigate config changes to a private GitHub repository. The following is the contents of my backup_src.txt file:

/backup/.ssh
/backup/config/backup_src.txt
/etc/**/*.conf
/etc/ssh/sshd_config
/data/docker/frigate/config/config.yml
/data/docker/frigate/docker-compose.yml

Camera Recordings

It would make a lot of sense to synchronize Frigate’s recordings to a cloud storage service for safekeeping in case a burglar finds the NVR. Ideally, Frigate would have built-in functionality for cloud backup. Until that is the case, we can build it ourselves. Details to follow soon.

Previous Article Elasticsearch ES|QL: Energy Consumption Chart With Home Assistant Data