# Frigate NVR

**AI-Powered Network Video Recorder**

## Service Overview

| Property | Value |
|----------|-------|
| **Service Name** | frigate |
| **Category** | Security / Surveillance |
| **Docker Image** | `ghcr.io/blakeblackshear/frigate:stable` |
| **Web UI Port** | 5000 |
| **RTSP Restream Port** | 8554 |
| **WebRTC Port** | 8555 |
| **Status** | Tested on Seattle (2026-03-27), removed after validation |

## Purpose

Frigate is a self-hosted NVR with real-time AI object detection. Instead of 24/7 recording, it detects people, cars, animals, etc. from RTSP camera streams and only records clips when objects are detected. Integrates with Home Assistant.

## Tested Configuration

Successfully tested on Seattle (16 vCPU, 62GB RAM) with a Tapo camera on the Concord NUC subnet.

### Camera

- **Model**: Tapo camera with RTSP
- **IP**: `192.168.68.67` (GL-MT3000 subnet, `192.168.68.0/22`)
- **RTSP streams**: `rtsp://USER:PASS@192.168.68.67:554/stream1` (high), `stream2` (low) # pragma: allowlist secret
- **RTSP credentials**: Set via Tapo app -> Camera Settings -> Advanced -> Camera Account

### Network Path

The camera is on the Concord NUC's LAN (`192.168.68.0/22`). For other Tailscale nodes to reach it:
1. NUC advertises `192.168.68.0/22` via Tailscale (already configured + approved in Headscale)
2. The Frigate host must have `--accept-routes=true` in Tailscale (`tailscale set --accept-routes=true`)

### Compose File (reference)

```yaml
services:
  frigate:
    image: ghcr.io/blakeblackshear/frigate:stable
    container_name: frigate
    restart: unless-stopped
    shm_size: 256mb
    security_opt:
      - no-new-privileges:true
    environment:
      TZ: America/Los_Angeles
    ports:
      - "5000:5000"
      - "8554:8554"
      - "8555:8555/tcp"
      - "8555:8555/udp"
    volumes:
      - ./config:/config
      - ./storage:/media/frigate
      - type: tmpfs
        target: /tmp/cache
        tmpfs:
          size: 1000000000
```

### Config File (reference)

```yaml
mqtt:
  enabled: false

detectors:
  cpu:
    type: cpu
    num_threads: 4

objects:
  track:
    - person
    - car
    - cat
    - dog
  filters:
    person:
      min_score: 0.5
      threshold: 0.7

record:
  enabled: true
  retain:
    days: 7
    mode: motion
  alerts:
    retain:
      days: 14
  detections:
    retain:
      days: 14

snapshots:
  enabled: true
  retain:
    default: 14

detect:
  enabled: true
  width: 1280
  height: 720
  fps: 5

go2rtc:
  streams:
    tapo_cam:
      - rtsp://USER:PASS@192.168.68.67:554/stream1  # pragma: allowlist secret
    tapo_cam_sub:
      - rtsp://USER:PASS@192.168.68.67:554/stream2  # pragma: allowlist secret

cameras:
  tapo_cam:
    enabled: true
    ffmpeg:
      inputs:
        - path: rtsp://127.0.0.1:8554/tapo_cam
          input_args: preset-rtsp-restream
          roles:
            - record
        - path: rtsp://127.0.0.1:8554/tapo_cam_sub
          input_args: preset-rtsp-restream
          roles:
            - detect
    detect:
      width: 640
      height: 480
      fps: 5
    objects:
      track:
        - person
        - car
        - cat
        - dog

version: 0.14
```

## Deployment Notes

- **CPU detection** works for 1-2 cameras but is not recommended for production. Consider a Google Coral USB TPU for hardware acceleration.
- **go2rtc** handles RTSP restreaming — camera credentials only need to be in go2rtc streams, not in ffmpeg inputs.
- Use `stream2` (sub-stream, lower resolution) for detection to save CPU.
- Use `stream1` (main stream, full resolution) for recording.
- **Default credentials** on first start: `admin` / auto-generated password (check `docker logs frigate`).
- **Config validation errors**: `ui -> live_mode` is not valid in v0.14+. Don't add extra fields not in the docs.

## Future Deployment

Best host options for permanent deployment:
- **Concord NUC**: Same LAN as camera, no Tailscale routing needed. Has Home Assistant running.
- **Homelab VM**: Central infrastructure host, plenty of resources.
- **Atlantis**: Has the most storage for recordings.

All require `tailscale set --accept-routes=true` unless on the same LAN as the camera.
