Frigate is an open-source Network Video Recorder (NVR) specifically designed for real-time AI-based object detection. It not only offers traditional video recording and playback but also automatically detects people, vehicles, animals, and other objects using machine learning.

Why Frigate Became the Solution for My Video Surveillance

Before moving to Paraguay in 2019, I worked in Germany planning and installing video surveillance systems. I applied that knowledge here as well: from the start, our house was equipped with a traditional surveillance setup consisting of several network cameras and an NVR recorder with a hard drive.

However, some time ago I began looking for a more flexible solution. I wanted a central platform that would allow me to easily access my IP cameras. That’s when I discovered Frigate, and it quickly became clear: it can do much more than just store videos. Combined with a Coral TPU for AI object detection, it could even replace my conventional NVR entirely.

Initial Tests on My Home Server

My first installation of Frigate was on my sumpfgeist.lan server to evaluate how well the system would perform in daily use. The original plan was to use an M.2 Dual Coral, provided it would work in the M.2 Wi-Fi slot of my Lenovo ThinkCentre. I don’t need Wi-Fi anyway, and the slot was available.

In practice, however, it turned out that dual-chip Corals are not supported in most M.2 Wi-Fi slots. These slots are often designed exclusively for Wi-Fi modules and do not provide a usable PCIe lane. If you’re lucky, a PCIe lane is available, allowing a Coral TPU to be installed instead of the Wi-Fi module.

This was the case with the ThinkCentre, where I could easily run a single-chip Coral in the M.2 Wi-Fi slot. On the EQ14 (eq14.lan), however, the slot supports Wi-Fi only, so the Coral TPU was not detected.

The EQ14 does have two full-size M.2 slots for NVMe drives. Since only one NVMe SSD was installed, the second slot was free — allowing me to install and use a single Coral TPU chip there via an adapter board.

Camera Configuration and Migration to the EQ14

At the moment, I have five IP cameras distributed across our property, all of which can be easily integrated into Frigate. More will likely be added in the future.

After the initial tests went well, I migrated the Frigate installation from sumpfgeist.lan to eq14.lan. Thanks to Docker Compose, the move was almost seamless — only a small adjustment in the .env file was needed: switching from AMD GPU support to Intel, which simply meant removing one environment variable.

To get the Coral chip working on Alpine Linux with the EQ14, I have already implemented and documented all the necessary steps. I will cover these details in my next blog post.

Since the existing Traefik proxy runs on a different Docker host and cannot automatically handle domain configuration from external hosts, I set up a second Traefik proxy on the EQ14. Through this, Frigate is now accessible within the internal network. For the subdomain, I only had to update the IP address in the Pi-hole DNS server.

With the core hardware and network setup now complete, the next step will be installing Frigate using Docker Compose - from initial preparation to the first working configuration.

Frigate Installation

For running Frigate, I decided to use Docker Compose — not least because I’m a big fan of Docker and run multiple containers on different hosts in my homelab. The topic is broad enough that I’ll probably dedicate a separate blog post to it at some point.

Docker Compose has the advantage of making configurations easy to adjust, back up, and migrate to other systems when needed. The official Frigate documentation also provides a solid foundation, which I adapted to my requirements — particularly the integration of multiple IP cameras.

My current docker-compose.yaml file looks like this:

services:
  frigate:
    container_name: frigate
    restart: unless-stopped
    image: ghcr.io/blakeblackshear/frigate:stable
    devices:
      #- /dev/bus/usb:/dev/bus/usb # USB Coral
      - /dev/apex_0:/dev/apex_0 # M.2 Coral
      #- /dev/apex_1:/dev/apex_1 # M.2 Dual Coral
      - /dev/dri/renderD128:/dev/dri/renderD128 # for intel hwaccel, needs to be updated for your hardware
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /home/sz/docker/frigate/config.yml:/config/config.yml:ro
      - /mnt/frigate/clips:/media/frigate/clips
      - /mnt/frigate/recordings:/media/frigate/recordings
      - /home/sz/docker/frigate/db-data:/media/frigate
      - type: tmpfs # Optional 1GB memory to reduce SSD/SD card wear
        target: /tmp/cache
        tmpfs:
          size: 1000000000
    networks:
      proxy:
        ipv4_address: 192.168.x.x
    ports:
      - "5000:5000" # Frigate Webinterface
      #- "1935:1935" # RTMP feeds (deprecated) ???
      - "1984:1984" # go2rtc
      - "8554:8554" # go2rtc
    env_file: .env
    security_opt:
      - no-new-privileges:true
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.frigate.entrypoints=http"
      - "traefik.http.routers.frigate.rule=Host(`frigate.techlab.icu`)"
      - "traefik.http.middlewares.frigate-https-redirect.redirectscheme.scheme=https"
      - "traefik.http.routers.frigate.middlewares=frigate-https-redirect"
      - "traefik.http.routers.frigate-secure.entrypoints=https"
      - "traefik.http.routers.frigate-secure.rule=Host(`frigate.techlab.icu`)"
      - "traefik.http.routers.frigate-secure.tls=true"
      - "traefik.http.routers.frigate-secure.service=frigate"
      - "traefik.http.services.frigate.loadbalancer.server.port=5000"
      - "traefik.docker.network=proxy"

networks:
  proxy:
    external: true

For storing video recordings and clips, I’ve mounted a network share from my Synology NAS and pointed to it in the Frigate Docker configuration using the directories /mnt/frigate/clips and /mnt/frigate/recordings.

The current config.yml file looks like this:

detectors:
  coral1:
    type: edgetpu
    device: pci:0
#  coral2:
#    type: edgetpu
#    device: pci:1

# Optional: Database configuration
database:
  # The path to store the SQLite DB (default: shown below)
  path: /media/frigate/frigate.db

auth:
  enabled: True

birdseye:
  # Optional: Enable birdseye view (default: shown below)
  enabled: True
  # Optional: Width of the output resolution (default: shown below)
  width: 1280
  # Optional: Height of the output resolution (default: shown below)
  height: 720
  # Optional: Encoding quality of the mpeg1 feed (default: shown below)
  # 1 is the highest quality, and 31 is the lowest. Lower quality feeds utilize less CPU resources.
  quality: 8
  # Optional: Mode of the view. Available options are: objects, motion, and continuous
  #   objects - cameras are included if they have had a tracked object within the last 30 seconds
  #   motion - cameras are included if motion was detected in the last 30 seconds
  #   continuous - all cameras are included always
  mode: continuous

ffmpeg:
  hwaccel_args: #preset-vaapi
    - -hwaccel
    - vaapi
    - -hwaccel_device
    - /dev/dri/renderD128
    - -hwaccel_output_format
    - yuv420p
  output_args:
    record: -f segment -segment_time 10 -segment_format mp4 -reset_timestamps 1 -strftime 1 -c:v copy -c:a aac

detect:
  enabled: True
  width: 640 # <---- update for your camera's resolution
  height: 480 # <---- update for your camera's resolution
  fps: 5

objects:
  track:
    - person
    - dog
    - cat
    - bird

record:
  enabled: True
  detections:
    pre_capture: 5
    post_capture: 5
    retain:
      days: 30
      mode: active_objects

snapshots:
  enabled: True
  timestamp: False
  bounding_box: True
  retain:
    default: 30

go2rtc:
  streams:
    carport:
      - rtsp://{FRIGATE_RTSP_USER}:{FRIGATE_RTSP_PASSWORD}@192.168.x.x:554/cam/realmonitor?channel=1&subtype=0
    carport_sub:
      - rtsp://{FRIGATE_RTSP_USER}:{FRIGATE_RTSP_PASSWORD}@192.168.x.x:554/cam/realmonitor?channel=1&subtype=1
    garden:
      - rtsp://{FRIGATE_RTSP_USER}:{FRIGATE_RTSP_PASSWORD}@192.168.x.x:554/cam/realmonitor?channel=1&subtype=0
    garden_sub:
      - rtsp://{FRIGATE_RTSP_USER}:{FRIGATE_RTSP_PASSWORD}@192.168.x.x:554/cam/realmonitor?channel=1&subtype=1
    office:
      - rtsp://{FRIGATE_RTSP_USER}:{FRIGATE_RTSP_PASSWORD}@192.168.x.x:554/cam/realmonitor?channel=1&subtype=0
    office_sub:
      - rtsp://{FRIGATE_RTSP_USER}:{FRIGATE_RTSP_PASSWORD}@192.168.x.x:554/cam/realmonitor?channel=1&subtype=1
    workshop:
      - rtsp://{FRIGATE_RTSP_USER}:{FRIGATE_RTSP_PASSWORD}@192.168.x.x:554/cam/realmonitor?channel=1&subtype=0
    workshop_sub:
      - rtsp://{FRIGATE_RTSP_USER}:{FRIGATE_RTSP_PASSWORD}@192.168.x.x:554/cam/realmonitor?channel=1&subtype=1

cameras:
  carport:
    ffmpeg:
      inputs:
        - path: rtsp://{FRIGATE_RTSP_USER}:{FRIGATE_RTSP_PASSWORD}@192.168.x.x:554/cam/realmonitor?channel=1&subtype=0
          roles:
            - record
        - path: rtsp://{FRIGATE_RTSP_USER}:{FRIGATE_RTSP_PASSWORD}@192.168.x.x:554/cam/realmonitor?channel=1&subtype=1
          roles:
            - detect
    webui_url: "http://192.168.x.x"
    detect:
      width: 704 # <---- update for your camera's resolution
      height: 480 # <---- update for your camera's resolution
      fps: 5
  garden:
    ffmpeg:
      inputs:
        - path: rtsp://{FRIGATE_RTSP_USER}:{FRIGATE_RTSP_PASSWORD}@192.168.x.x:554/cam/realmonitor?channel=1&subtype=0
          roles:
            - record
        - path: rtsp://{FRIGATE_RTSP_USER}:{FRIGATE_RTSP_PASSWORD}@192.168.x.x:554/cam/realmonitor?channel=1&subtype=1
          roles:
            - detect
    webui_url: "http://192.168.x.x"
    detect:
      width: 704 # <---- update for your camera's resolution
      height: 480 # <---- update for your camera's resolution
      fps: 5
  office:
    ffmpeg:
      inputs:
        - path: rtsp://127.0.0.1:8554/office
          roles:
            - audio
            - record
        - path: rtsp://127.0.0.1:8554/office_sub
          roles:
            - detect
    webui_url: "http://192.168.x.x"
    onvif:
      host: 192.168.x.x
      port: 80
      user: frigate
      password: "{FRIGATE_RTSP_PASSWORD}"
  workshop:
    ffmpeg:
      inputs:
        - path: rtsp://127.0.0.1:8554/workshop
          roles:
            - audio
            - record
        - path: rtsp://127.0.0.1:8554/workshop_sub
          roles:
            - detect
    webui_url: http://192.168.x.x
    onvif:
      host: 192.168.x.x
      port: 80
      user: frigate
      password: "{FRIGATE_RTSP_PASSWORD}"

In this Frigate configuration, I’ve included example IP addresses — you’ll definitely need to adjust these to match your own home network.

One major advantage of my EQ14 setup is that it has two separate network interfaces. This allows me to run the IP cameras on their own isolated network, adding an extra layer of security. Only the second network interface of the EQ14 is connected to my homelab. This way, the camera devices are physically separated from the rest of the network, minimizing potential attack surfaces.

Integrating Camera Streams with go2rtc

To integrate the RTSP streams from my IP cameras into Frigate as flexibly and efficiently as possible, I use go2rtc.

Why go2rtc?

go2rtc is a modern stream relay server that can aggregate, transcode, and forward RTSP, RTMP, and WebRTC streams. It’s especially useful because it ensures compatibility with various clients, reduces latency, and offloads work from the cameras.

Additionally, go2rtc makes it possible to seamlessly use streams with different protocols (RTSP, WebRTC) within the homelab and beyond. This is particularly valuable for more complex setups with multiple cameras and clients. The go2rtc service is already running inside the Frigate container.

To find the correct RTSP links for my OEM Dahua IP cameras, I used this helpful website, which documents many common URL formats. These links can easily be opened and played with VLC or other media players.

Example for my office camera:

rtsp://192.168.x.x:554/live
rtsp://192.168.x.x:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif
rtsp://192.168.x.x:554/cam/realmonitor?channel=1&subtype=1

Current Setup and Hardware

I recently ordered a Coral M.2 A+E TPU on eBay.com and installed it in my server. The AI object detection with the Coral chip is significantly more efficient than using the CPU, which otherwise runs at full load and is not recommended for this task. I will link my blog post about the Coral TPU chip here once it’s available.

I have already integrated the GPU for hardware acceleration with ffmpeg, and the system currently runs stably with four cameras. A fifth camera will be added soon, and in the long term, I plan to run up to eight cameras. This hardware setup should handle that without any issues.

Important Environment Variable for GPU Support

To enable detection of the AMD GPU in my ThinkCentre (sumpfgeist.lan) by Frigate, I had to set the following environment variable in my .env file:

FRIGATE_RTSP_USER=frigate
FRIGATE_RTSP_PASSWORD=secure_password
LIBVA_DRIVER_NAME=radeonsi

After migrating to the EQ14 (eq14.lan), which uses an Intel GPU, I removed the LIBVA_DRIVER_NAME variable because the AMD drivers are not needed there and would cause errors.

FRIGATE_RTSP_USER=frigate
FRIGATE_RTSP_PASSWORD=secure_password

Recording Quality and Stream Management

The recordings should be as high quality as possible. For this, I needed to adjust some settings and, as mentioned before, use go2rtc to better manage the streams. Since switching, go2rtc has been working very well.

Frigate is currently accessible via my Traefik proxy server at: https://frigate.techlab.icu

Configuring the go2rtc Streaming Server

For optimized video playback and real-time streaming, it’s recommended to use the integrated go2rtc server.

The configuration is quite simple: you extend the config.yml with the streams that go2rtc should manage.

go2rtc:
  streams:
    office:
      - rtsp://{FRIGATE_RTSP_USER}:{FRIGATE_RTSP_PASSWORD}@192.168.x.x:554/cam/realmonitor?channel=1&subtype=0
    office_sub:
      - rtsp://{FRIGATE_RTSP_USER}:{FRIGATE_RTSP_PASSWORD}@192.168.x.x:554/cam/realmonitor?channel=1&subtype=1

These streams can then be accessed and monitored via the go2rtc web interface at http://192.168.x.x:1984.

To use the streams in the live view and for recordings at high quality with Frigate, the cameras must be configured accordingly in the config.yml to use the go2rtc stream paths:

cameras:
  office:
    ffmpeg:
      inputs:
        - path: rtsp://127.0.0.1:8554/office
          roles:
            - audio
            - record
        - path: rtsp://127.0.0.1:8554/office_sub
          roles:
            - detect

Troubleshooting

For my indoor camera in the workshop, the stream initially wouldn’t start through go2rtc, while the identical model in the office worked fine.

I checked and compared the video and audio settings of the cameras. The problem turned out to be the audio codec: I had to switch from AAC to G.711A. After that, the stream started successfully in Frigate via go2rtc - both video and audio now work flawlessly.

Object Detection

Object detection in Frigate is based on AI-powered recognition. For hardware acceleration, I use a Coral Edge TPU chip with 4 TOPS (tera operations per second). How to install this chip including its drivers is already described here.

Image Frigate Object Detection Coral Edge TPU

Adjusting Docker Compose

To use the Coral Edge TPU inside the Docker container, I modify the docker-compose.yaml file in my ~/docker-compose/frigate/ directory as follows, so the device is passed through to the container:

devices:
  #- /dev/bus/usb:/dev/bus/usb # USB Coral
  - /dev/apex_0:/dev/apex_0 # M.2 Coral
  #- /dev/apex_1:/dev/apex_1   # M.2 Dual Coral (optional)

Activating Frigate Configuration

In the config.yml file located in my ~/docker/frigate/ folder, I activate the detectors by adding this section:

detectors:
  coral1:
    type: edgetpu
    device: pci:0

Configuring Object Detection

Object detection is enabled and configured in the detect section:

detect:
  enabled: True
  width: 640 # <---- update for your camera's resolution
  height: 480 # <---- update for your camera's resolution
  fps: 5

Note: The parameters width, height, and fps are usually overridden in the individual camera settings under cameras: and tailored per device. For detection, a lower resolution and frame rate are sufficient to save resources.

Restart

After making these changes, you can restart the Docker container or, if you only changed the configuration, simply restart Frigate via the web interface.

Conclusion

The combination of Frigate, Coral Edge TPU, and the EQ14 has now become the core of my video surveillance system. Thanks to the high detection accuracy and stable performance, I now have a solution that is reliable and future-proof.

Next, I plan to fine-tune the detection further, integrate additional automations via Home Assistant, and gradually make my system even smarter.

Hardware Recommendations

  • EQ14 Mini-PC on Amazon - compact and energy-efficient machine for Frigate
  • Coral Edge TPU on Amazon US - AI accelerator for fast and precise object detection
  • Coral Dual Edge TPU on Amazon - powerful AI accelerator (does not fit in EQ14)

Some of the above are affiliate links. As an Amazon Associate, I earn from qualifying purchases.

Tools used: