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)