Skip to content

Frigate NVR

Deploy Frigate Network Video Recorder with camera network isolation.

Overview

This example demonstrates:

  • Docker container management
  • iptables firewall rules for network isolation
  • dnsmasq DHCP server configuration
  • Sysctl settings for IP forwarding
  • Multi-interface network setup

Architecture

Main LAN (192.168.1.0/24)          Camera Network (10.0.100.0/24)
         │                                    │
         │ eth0                          eth1 │
    ┌────┴────────────────────────────────────┴────┐
    │                  Frigate Host                │
    │  ┌─────────────┐    ┌─────────────────────┐  │
    │  │   Frigate   │◄───│  iptables firewall  │  │
    │  │  Container  │    │  (isolates cameras) │  │
    │  └─────────────┘    └─────────────────────┘  │
    │                     ┌─────────────────────┐  │
    │                     │      dnsmasq        │  │
    │                     │   (DHCP for cams)   │  │
    │                     └─────────────────────┘  │
    └──────────────────────────────────────────────┘
              ┌───────────────┼───────────────┐
              │               │               │
         ┌────┴────┐    ┌────┴────┐    ┌────┴────┐
         │ Camera1 │    │ Camera2 │    │ Camera3 │
         └─────────┘    └─────────┘    └─────────┘

Security Model

Cameras are isolated on a separate network:

  • Cameras → Frigate: Allowed (RTSP streams)
  • Cameras → Internet: Limited (NTP only)
  • Cameras → Main LAN: Blocked
  • Main LAN → Cameras: Blocked (except Frigate host)

Files

examples/frigate_nvr/
├── deploy.py
├── templates/
│   ├── frigate.yml.j2
│   ├── iptables-cameras.rules.j2
│   └── dnsmasq-cameras.conf.j2
└── README.md

Configuration

# Network configuration
MAIN_INTERFACE = "eth0"
CAMERA_INTERFACE = "eth1"
CAMERA_NETWORK = "10.0.100.0/24"
CAMERA_GATEWAY = "10.0.100.1"
CAMERA_DHCP_RANGE = "10.0.100.100,10.0.100.200"

# Frigate configuration
FRIGATE_CONFIG_DIR = "/opt/frigate"
FRIGATE_STORAGE_DIR = "/mnt/nvr"
FRIGATE_WEB_PORT = 5000

# Camera definitions
CAMERAS = [
    {"name": "front_door", "ip": "10.0.100.10", "mac": "aa:bb:cc:dd:ee:01"},
    {"name": "backyard", "ip": "10.0.100.11", "mac": "aa:bb:cc:dd:ee:02"},
    {"name": "garage", "ip": "10.0.100.12", "mac": "aa:bb:cc:dd:ee:03"},
]

Usage

# Preview changes
python examples/frigate_nvr/deploy.py --dry-run

# Deploy
sudo python examples/frigate_nvr/deploy.py

What Gets Deployed

1. Network Interface

Configure the camera network interface:

def configure_camera_interface():
    # Set static IP on camera interface
    config = f"""
auto {CAMERA_INTERFACE}
iface {CAMERA_INTERFACE} inet static
    address {CAMERA_GATEWAY}
    netmask 255.255.255.0
"""
    file(f"/etc/network/interfaces.d/{CAMERA_INTERFACE}", config)
    run(f"ifup {CAMERA_INTERFACE}", sudo=True)

2. IP Forwarding

def enable_ip_forwarding():
    lineinfile(
        "/etc/sysctl.conf",
        line="net.ipv4.ip_forward=1",
        regexp=r"^#?net\.ipv4\.ip_forward"
    )
    run("sysctl -p", sudo=True)

3. iptables Rules

/etc/iptables/rules.v4:

# Camera isolation rules
*filter
:CAMERA_IN - [0:0]
:CAMERA_OUT - [0:0]

# Allow established connections
-A CAMERA_IN -m state --state ESTABLISHED,RELATED -j ACCEPT

# Allow cameras to reach Frigate ports
-A CAMERA_IN -p tcp --dport 5000 -j ACCEPT  # Web UI
-A CAMERA_IN -p tcp --dport 1935 -j ACCEPT  # RTMP

# Block cameras from main LAN
-A CAMERA_OUT -d 192.168.1.0/24 -j DROP

# Allow NTP for cameras
-A CAMERA_OUT -p udp --dport 123 -j ACCEPT

# Apply to camera interface
-A FORWARD -i eth1 -j CAMERA_IN
-A FORWARD -o eth1 -j CAMERA_OUT

COMMIT

4. dnsmasq DHCP

/etc/dnsmasq.d/cameras.conf:

interface=eth1
bind-interfaces

# DHCP range
dhcp-range=10.0.100.100,10.0.100.200,24h

# Static leases for cameras
dhcp-host=aa:bb:cc:dd:ee:01,front_door,10.0.100.10
dhcp-host=aa:bb:cc:dd:ee:02,backyard,10.0.100.11
dhcp-host=aa:bb:cc:dd:ee:03,garage,10.0.100.12

# DNS and gateway
dhcp-option=option:router,10.0.100.1
dhcp-option=option:dns-server,10.0.100.1

5. Frigate Container

def start_frigate_container():
    cmd = f"""
docker run -d \
    --name frigate \
    --restart=unless-stopped \
    --privileged \
    -v {FRIGATE_CONFIG_DIR}:/config \
    -v {FRIGATE_STORAGE_DIR}:/media/frigate \
    -v /etc/localtime:/etc/localtime:ro \
    -p {FRIGATE_WEB_PORT}:5000 \
    -p 8554:8554 \
    -p 8555:8555/tcp \
    -p 8555:8555/udp \
    ghcr.io/blakeblackshear/frigate:stable
"""
    run(cmd, sudo=True)

6. Frigate Configuration

/opt/frigate/config.yml:

mqtt:
  enabled: false

cameras:
  front_door:
    ffmpeg:
      inputs:
        - path: rtsp://10.0.100.10:554/stream
          roles:
            - detect
            - record
    detect:
      width: 1920
      height: 1080

  backyard:
    ffmpeg:
      inputs:
        - path: rtsp://10.0.100.11:554/stream
          roles:
            - detect
            - record

record:
  enabled: true
  retain:
    days: 7

detectors:
  cpu1:
    type: cpu

Key Code Sections

iptables Setup

def configure_firewall():
    rules = template(
        "templates/iptables-cameras.rules.j2",
        camera_interface=CAMERA_INTERFACE,
        camera_network=CAMERA_NETWORK,
        main_network="192.168.1.0/24",
        frigate_ports=[5000, 1935, 8554, 8555]
    )

    file("/etc/iptables/rules.v4", rules, mode="0600")
    run("iptables-restore < /etc/iptables/rules.v4", sudo=True)

dnsmasq Setup

def configure_dnsmasq():
    config = template(
        "templates/dnsmasq-cameras.conf.j2",
        interface=CAMERA_INTERFACE,
        gateway=CAMERA_GATEWAY,
        dhcp_range=CAMERA_DHCP_RANGE,
        cameras=CAMERAS
    )

    file("/etc/dnsmasq.d/cameras.conf", config, mode="0644")
    run("systemctl restart dnsmasq", sudo=True)

Troubleshooting

Check Camera Connectivity

# From Frigate host
ping 10.0.100.10

# Check DHCP leases
cat /var/lib/misc/dnsmasq.leases

Verify iptables Rules

iptables -L CAMERA_IN -v -n
iptables -L CAMERA_OUT -v -n

Check Frigate Logs

docker logs frigate -f

Test Camera Isolation

# From a camera (should fail)
ping 192.168.1.1  # Main LAN gateway

# From main LAN (should fail unless you're the Frigate host)
ping 10.0.100.10