Use case · Video surveillance

A Frigate NVR server on bare metal: detector, disks and the uplink

A Frigate NVR server needs a processor with AVX and AVX2, hardware video decoding, a dedicated object detector and local disk for recordings; Frigate's documentation says it runs best in Docker on bare-metal Debian, not in a VM. In a data centre a fifth constraint decides everything else: the upload at the camera site has to carry every stream, all day. This page picks the detector, sizes the disks, wires the cameras over WireGuard and says when a box on site is the better answer.

Configure a TPU server

What Frigate asks of the machine

Frigate splits the work in two. The CPU decodes the video and looks for motion; regions with motion go to a detector, which says whether there is a person, a car or a dog in them. Frigate is designed around a detector; its plain CPU detector is listed for testing only.

ResourceFrigate's guidance
CPUAVX and AVX2 required; older Xeons may have AVX but lack AVX2
Video decodingIntegrated or discrete GPU highly recommended
Object detectionA dedicated accelerator or GPU
Memory4 GB basic minimum with an accelerator, 8 GB for enrichments, 16 GB recommended for 8+ cameras
Shared memoryAbout 210 MB for 2 cameras detecting at 720p; Docker's default is 64 MB
RecordingsLocal storage preferred over NAS
PlatformDocker on bare-metal Debian; VMs not recommended

Detection runs on a lower-resolution substream (Frigate's example uses 1280x720): Frigate crops the moving region and resizes it to the model's 320x320 input, so the detect resolution only needs to be high enough for the objects you want to catch, and anything above that mostly costs CPU. Recording takes the camera's main stream and writes it to disk without re-encoding. The default detection rate is 5 fps, and Frigate's docs say it rarely needs raising.

Choosing the detector

DetectorFrigate typeInference time in Frigate's docsStatus
Hailo-8 (M.2)hailo8lYOLOv6n ~7 ms; SSD MobileNet v1 ~6 msDefault model downloaded on first start
Coral Edge TPU (M.2)edgetpu~10 ms in Frigate's example (1000/10 = about 100 detections/s)Not recommended for new installs
Intel iGPU (OpenVINO)openvinoHD 630: ~15 ms, MobileNetV2 (Iris Pro P580 not listed)6th-gen Intel and newer
NVIDIA GPU (ONNX)onnxGTX 1070: 16 ms, YOLOv9 s-320Compute capability 5.0+, driver 545+

For a new build, take the Hailo-8. Frigate now advises against the Coral for new installations except where power is very tight or nothing else fits, and keeps supporting it for existing ones. Google has also archived the Coral software, so its PCIe driver comes from community forks; Frigate's docs point to jnicolson/gasket-builder. Keep the Coral if your models already run on an Edge TPU.

A Coral's ceiling is easy to compute: Frigate's docs give 1000 divided by the inference time in milliseconds, so 10 ms means about 100 detections per second. Frigate's planning guide puts 1-6 cameras with occasional motion on one entry-level accelerator, 12 or more busy cameras on multiple accelerators or one discrete GPU, and 40-plus cameras on a modern discrete GPU. That last tier belongs on GPU dedicated servers, with the card in a rack machine.

The two TPU cartridges

Our Coral and Hailo-8 TPU servers are HPE Moonshot cartridges with the module on the M.2 slot: the m710x with a quad-core Xeon E3-1585L v5, and the m510 with an 8- or 16-core Xeon D. The entry build of either has 32 GB DDR4, one 240 GB NVMe drive and an unmetered 1 Gbps port. You get root and the remote console, and no other customer's workload runs on the cartridge.

  • m710x: its Iris Pro P580 graphics decode video in hardware, which is the job Frigate wants off the CPU. The E3-1585L v5 is a 6th-generation (Skylake) part, so Frigate's table gives preset-vaapi for it.
  • m510: more cores, but no Xeon D has Quick Sync, so the cores decode every stream themselves. Pick it when the camera count is small and you want cores for other services.
  • Disks: 240 GB holds little video. Disks are set in the same configurator as the module; size them for the retention below, or keep continuous footage short.
  • Lead time: a module makes the order a custom build, so it is built to order in 4-24 hours rather than taken off the shelf.

Sizing recording storage

Frigate stores the record stream as the camera encodes it, so disk use is the camera's bitrate multiplied by the time kept. Our arithmetic, not Frigate's: one camera at 1 Mbit/s fills 10.8 GB a day. Read the bitrate from the camera's encoder settings and scale.

Record bitrate per cameraPer day, continuous14 days, 4 cameras
2 Mbit/s21.6 GB1.2 TB
4 Mbit/s43.2 GB2.4 TB
8 Mbit/s86.4 GB4.8 TB

Retention is what brings that down. Frigate holds each class of footage (continuous, motion, alerts, detections) for its own number of days, and the most generous matching rule wins. Continuous recording is off by default; keeping motion for a week and alerts for a month costs a fraction of the table. Exported clips are never removed by retention.

Remote cameras: bandwidth and latency

Sending cameras to a data centre moves the cost to the site's upload. Frigate writes new segments to a cache first and only then decides whether retention keeps them, so the record stream has to flow all the time, motion or not. Each camera therefore sends its main stream plus the detect substream, continuously. Frigate's Add Camera wizard shows an estimated bandwidth figure per stream: add them up and compare the sum with the upload your line actually sustains, with room left for everything else on it.

  • Latency: every alert arrives one network round trip and some buffering later than it would on site. Ping the test IP in each city and pick the nearest; the looking glass runs traceroutes from our edge.
  • Outages: if the site's line drops, nothing reaches the server for that window. Keep the cameras' own card recording on if they have it.
  • Connections: the camera wizard's restream option lets Frigate and the live view share one connection to each camera, instead of each pulling its own copy across the tunnel.
  • Exposure: never forward RTSP ports to the internet. Put the site router and the server on a WireGuard tunnel and let Frigate reach the camera subnet through it.

Inbound traffic is not billed and the port is unmetered, so the data centre side costs nothing extra per camera. The upload at the site is the limit.

Setting it up

  1. Configure an m710x with the Hailo-8 and Debian or Ubuntu. When it is handed over, check AVX2 and that the module is on the PCIe bus.
  2. Install the Hailo driver with Frigate's own script, which pins its driver version, rather than a newer HailoRT release. For a Coral, build gasket-builder and check /dev/apex_0.
  3. Install Docker Engine (the apt-repository method in Docker's docs), then bring the WireGuard tunnel to the camera site up.
  4. Write the compose file, launch the stack (docker compose up -d) and read the generated admin password with docker logs frigate.
  5. Add cameras with the wizard or in YAML: substream for detect, main stream for record.
grep -m1 -o avx2 /proc/cpuinfo        # Frigate needs AVX and AVX2
lspci -nn | grep -Ei '1e60|1ac1'       # Hailo-8 = 1e60:2864, Coral = 1ac1:089a

# Hailo-8: Frigate's own host driver script (read it before you run it)
wget https://raw.githubusercontent.com/blakeblackshear/frigate/dev/docker/hailo8l/user_installation.sh
sudo chmod +x user_installation.sh
./user_installation.sh
sudo reboot
ls -l /dev/hailo0 && cat /sys/module/hailo_pci/version
services:
  frigate:
    container_name: frigate
    restart: unless-stopped
    stop_grace_period: 30s
    image: ghcr.io/blakeblackshear/frigate:stable
    shm_size: "512mb"            # size it with Frigate's shm calculator
    devices:
      - /dev/hailo0:/dev/hailo0   # Coral M.2 instead: /dev/apex_0:/dev/apex_0
      - /dev/dri/renderD128:/dev/dri/renderD128   # m710x graphics, for decoding
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - ./config:/config
      - ./storage:/media/frigate
      - type: tmpfs
        target: /tmp/cache
        tmpfs:
          size: 1000000000
    ports:
      - "127.0.0.1:8971:8971"     # ssh -L 8971:127.0.0.1:8971 root@server
mqtt:
  enabled: False        # turn on if you run Home Assistant / an MQTT broker
detectors:
  hailo:
    type: hailo8l          # the same type serves the Hailo-8
    device: PCIe
model:
  width: 320
  height: 320
  input_tensor: nhwc
  input_pixel_format: rgb
  input_dtype: int
  model_type: yolo-generic
  labelmap_path: /labelmap/coco-80.txt
ffmpeg:
  hwaccel_args: preset-vaapi
record:
  enabled: True
  motion:
    days: 7
  alerts:
    retain:
      days: 30
cameras:
  gate:
    ffmpeg:
      inputs:
        - path: rtsp://192.168.10.20:554/sub    # low-res substream
          roles: [detect]
        - path: rtsp://192.168.10.20:554/main   # full-res main stream
          roles: [record]

Running it

  • Port 8971 is the authenticated UI. Port 5000 is unauthenticated and 8554 restreams without a password by default: do not publish either.
  • Docker's -p and ports: publish on all interfaces and bypass ufw. The compose file publishes the UI on loopback only, which an SSH port forward reaches; to use it over the tunnel instead, publish it on the WireGuard interface's IP.
  • Change the generated admin password under Settings > Users; Frigate requires at least 12 characters.
  • Back up /config: it holds the config file and the SQLite database.
  • Hold the kernel and the Hailo or Coral driver at versions that work together. Nothing on our side updates the machine for you.
  • Watch System > Metrics: if detections are being skipped, tune motion masks before adding hardware.

When a box on site is the better answer

Frigate's own hardware page favours a small local PC with two network ports, so the cameras sit on a private network with no internet access. That is the right design when the site's upload cannot carry every stream, when footage must keep recording through an internet outage, or when alerts must fire within the shortest possible delay. A server here earns its place when several sites feed one recorder, when the recorder must not be stolen along with the cameras, or when the site already has fibre with upload to spare.

Questions

Is a Coral still worth buying for Frigate?

For a new installation, Frigate's docs say no: they recommend other detectors unless power is very constrained or the hardware takes nothing else. Frigate still supports the Coral for existing setups. On our cartridges the Hailo-8 is the same kind of M.2 option with a maintained toolchain, so take it for new work.

Hailo-8 or an NVIDIA GPU for Frigate?

A Hailo-8 suits a small to medium number of cameras and runs Frigate's default YOLOv6n model in about 7 ms. Frigate's planning guide points installations with 40 or more cameras at a modern discrete GPU, which also decodes video. That is a GPU server, not a TPU cartridge.

How many cameras can one Hailo-8 handle?

It depends on how many cameras see motion at once, the model and the detect resolution, so Frigate publishes inference times rather than camera counts. Watch System > Metrics after the cameras are added: skipped detections mean the detector is saturated. Motion masks reduce the load before more hardware does.

Can Frigate run in a VM on this server instead?

Frigate's docs advise Docker on bare-metal Debian and do not recommend VMs, because the detector and the GPU need low-overhead access. On a cartridge you have root on the whole machine, so install Debian or Ubuntu and run the container directly.

Does sending camera streams in cost anything per gigabyte?

No. Inbound traffic is not billed and the port is unmetered, with no allowance or overage line. The limit is the upload of the line at the camera site, which must carry every stream continuously.

Put a detector next to the recorder

Pick the m710x or m510, tick the Hailo-8 or the Coral, and set the disks for your retention.

Configure a TPU server

Related on Server Room

Other use cases