cam-proxy

An ultra-lightweight, zero-stress edge gateway for IP security cameras.

Eliminate camera freezes, RTSP socket exhaustion, and heavy CPU decoding. Sub-100ms HTTP snapshots, single-flight coalescing, PTZ control, MJPEG streaming, and ONVIF-to-MQTT events.

brew tap smford/tap && brew install cam-proxy

Have you ever tried displaying snapshots from your IP cameras on a Home Assistant wall tablet, MagicMirror, or web dashboardโ€”only to have the camera freeze, disconnect, or crash under the connection load? Or spent hours wrestling with complex ONVIF SOAP protocols and RTSP credentials just to pan a camera or receive a motion alert?

cam-proxy solves this. It acts as an intelligent, featherweight (< 20MB RAM) buffer between your cameras and your smart home or custom applications. Instead of running heavy 24/7 video decoders or exposing fragile camera hardware to multiple concurrent clients, cam-proxy gives you simple HTTP snapshot URLs, clean REST PTZ controls, and automatic MQTT motion alertsโ€”without burning CPU or overloading your cameras.

Current Release

0.4.0 Stable
View Release Notes on GitHub โ†’

Download pre-compiled static zero-dependency binaries for Linux, macOS, and Raspberry Pi:

macOS (Apple Silicon)
Darwin ARM64 (M1 / M2 / M3 / M4)
Download tar.gz โ†“
macOS (Intel)
Darwin AMD64 (x86_64)
Download tar.gz โ†“
Linux & Raspberry Pi (ARM64)
RPi 3 / 4 / 5 & Zero 2 W
Download tar.gz โ†“
Linux (x86_64)
Linux AMD64 (Servers, VMs, Intel NUC)
Download tar.gz โ†“

๐Ÿ’ก What Problems Does cam-proxy Solve?

Addressing the architectural limitations of low-cost IP cameras and smart home setups.

๐Ÿšซ

Camera Freezes & Socket Flooding

Budget IP cameras (Tapo, Reolink, Hikvision, Dahua, Amcrest) have limited microcontrollers. When a dashboard refreshes, multiple tablets load simultaneously, or an automation requests snapshots, the camera's RTSP connection crashes. cam-proxy uses single-flight request coalescing and an in-memory TTL frame cache: 20 simultaneous snapshot requests hit the camera as a single connection.

โšก

Resource Exhaustion on Edge Hardware

Running a full NVR (like Frigate or Blue Iris) requires gigabytes of RAM and constant CPU/GPU decoding just to grab periodic pictures. cam-proxy idles at < 15MB RAM and 0% CPU, connecting to the camera only when a snapshot or PTZ action is requested.

๐Ÿ”

Complex Protocols (ONVIF SOAP & Digest)

Controlling a PTZ camera or pulling an ONVIF snapshot normally requires crafting complex XML SOAP envelopes with WS-Security timestamps and HTTP Digest handshakes. cam-proxy translates all of this into standard, browser-friendly JSON REST endpoints: GET /snapshot and POST /ptz.

๐Ÿ“ก

Cloud-Free Alerts in Home Assistant

Subscribes directly to local camera event queues (motion detection, tampering, line crossing) and publishes them to MQTT with Home Assistant MQTT Auto-Discoveryโ€”no cloud subscriptions, vendor apps, or flaky webhooks required.

๐ŸŒ

Web Dashboard & Browser Security

Browsers cannot connect directly to camera RTSP streams or digest-authenticated HTTP endpoints due to CORS restrictions. cam-proxy provides configurable CORS middleware and standard security headers (X-Content-Type-Options: nosniff) out of the box, ready for embedding directly in wall tablets, MagicMirrors, and web applications.

Why cam-proxy? (Comparison with Alternatives)

If you already use tools like Frigate, go2rtc, or ffmpeg scripts, where does cam-proxy fit?

Feature / Capability cam-proxy Full NVRs (Frigate, Blue Iris, Shinobi) Streaming Servers (go2rtc, MediaMTX) DIY Scripts (ffmpeg / curl cron)
Primary Focus Lightweight Snapshots, PTZ & MQTT Events 24/7 Video Recording & AI Detection Low-Latency Live Video Streaming Ad-hoc Frame Grabbing
Idle Memory (RAM) < 15โ€“20 MB 500 MB โ€“ 4+ GB 50 MB โ€“ 200 MB Transient (spikes per execution)
Idle CPU Usage ~0% (no continuous decoding) High (constant decoding/AI) Lowโ€“Moderate 0% until script triggers
Hardware Strain Protection Yes (Single-flight coalescing + cache) None (pulls continuous 24/7 stream) None (passes connections through) No (concurrent runs crash camera)
ONVIF PTZ REST API Yes (Simple JSON POST /ptz) Rare / Complex integration Limited / None Manual SOAP XML scripting
Camera Event Bridge Yes (ONVIF PullPoint โ†’ MQTT) Via internal events RTSP metadata only Not supported
Home Assistant Discovery Zero-Config (MQTT Auto-Discovery) Via custom integration Via go2rtc integration Manual YAML configuration
CORS & Web Browser Ready Yes (Built-in CORS middleware) Usually behind reverse proxy WebRTC / WS focused Requires reverse proxy
Dependency Footprint Zero (Single static binary, CGO-free) Heavy (Python, OpenCV, TensorRT) Moderate Requires ffmpeg, bash, curl

Decision Guide

Selecting the right tool for your camera architecture.

โœ…

When should you use cam-proxy?

  • โœ” Snapshots on dashboards & smart displays: Wall tablets, Home Assistant Lovelace cards, MagicMirrors, e-ink picture frames, or smartwatch notifications.
  • โœ” Camera events without cloud lock-in: Instant motion, tamper, and line-crossing alerts pushed to Home Assistant or Node-RED via MQTT.
  • โœ” Low-power edge hardware: Raspberry Pi Zero, 3, 4, 5, thin clients, NAS devices, or edge routers where every megabyte of RAM matters.
  • โœ” Eliminating camera crashes: Your camera drops offline when multiple clients or automations request snapshots simultaneously.
๐Ÿ’ก

When should you use something else?

  • โžœ Continuous 24/7 video recording: If you need to store weeks of continuous video footage on hard drives, use a dedicated NVR like Frigate, Scrypted, or Blue Iris (you can still run cam-proxy alongside them for lightweight dashboard snapshots!).
  • โžœ Low-latency live video streaming: If you want to stream 30fps live video in a browser over WebRTC, tools like go2rtc or MediaMTX are purpose-built for video re-streaming.

Engineered for Hardware Resilience

Low-cost IP cameras have fragile web servers that crash under concurrent dashboard requests. cam-proxy protects them.

๐Ÿ›ก๏ธ

Single-Flight Coalescing

Concurrently arriving snapshot requests are coalesced into a single outbound request using singleflight.Group. 50 dashboard clients trigger exactly 1 camera fetch.

โšก

Sub-100ms HTTP Snapshots

Extracts JPEG snapshots natively from the camera's ONVIF HTTP endpoint in under 100ms. Configurable in-memory TTL caching prevents camera hardware flooding.

๐ŸŽฅ

Multipart MJPEG Streaming

Continuous multipart/x-mixed-replace live streams at /mjpeg with automatic PTZ cache invalidation and zero browser buffering issues.

๐Ÿ”„

PTZ Proxy & Eviction

Continuous move, stop, and preset positioning via ONVIF SOAP. Any pan, tilt, or zoom immediately evicts stale frame caches so dashboards stay in sync.

๐Ÿ“ก

ONVIF PullPoint to MQTT

Subscribes to camera motion, tamper, and line-crossing event streams, publishing normalized JSON states to MQTT with Home Assistant auto-discovery.

๐Ÿฅง

Raspberry Pi & Edge Optimized

Pure zero-CGO Go binary. Runs as an unprivileged Systemd service or scratch Docker container, idling at less than 15MB RAM and 0% CPU.

Home Assistant Integration

Eliminate dashboard lag and camera crashes. Serve sub-100ms snapshots, PTZ D-pad controls, and automatic MQTT motion sensors directly into Lovelace.

๐Ÿ 

Official Add-on Ready

Install directly from your Home Assistant Add-on Store with auto-configuration for the Mosquitto MQTT broker.

โšก

Sub-100ms Snapshots

Feed Lovelace picture-glance cards via native Generic Camera without freezing low-cost camera SOCs.

๐ŸŽฎ

PTZ REST Controls

Pan, tilt, zoom, and recall presets right from your dashboard buttons with clean HTTP POST commands.

๐Ÿ“ก

Zero-Config MQTT Discovery

ONVIF PullPoint events automatically appear as binary_sensor entities in Home Assistant.

Add the cam-proxy repository in Settings โž” Add-ons โž” Add-on Store โž” Repositories:

https://github.com/smford/cam-proxy

When using the official Mosquitto broker add-on, cam-proxy auto-discovers broker credentials and provisions MQTT entities automatically.

Add your camera via Settings โž” Devices & Services โž” Generic Camera:

# Still Image URL (sub-100ms with hardware coalescing)
http://localhost:8080/api/v1/cameras/front-door/snapshot

# Stream Source (RTSP or MJPEG)
rtsp://192.168.1.50:554/live/ch0
# or: http://localhost:8080/api/v1/cameras/front-door/stream.mjpg

# Framerate: 2 fps (keeps Lovelace tablets fast and cool)

Define REST commands in configuration.yaml to drive camera movements:

rest_command:
  cam_ptz_move:
    url: "http://localhost:8080/api/v1/cameras/{{ camera_id }}/ptz"
    method: POST
    headers:
      Content-Type: "application/json"
    payload: '{"action":"move","pan":{{ pan | default(0) }},"tilt":{{ tilt | default(0) }},"zoom":{{ zoom | default(0) }}}'

  cam_ptz_stop:
    url: "http://localhost:8080/api/v1/cameras/{{ camera_id }}/ptz"
    method: POST
    headers:
      Content-Type: "application/json"
    payload: '{"action":"stop"}'

Display camera snapshots with auto-discovered motion sensor status:

type: picture-glance
title: Front Door
camera_image: camera.front_door
entities:
  - binary_sensor.front_door_motion
  - binary_sensor.front_door_tamper

View Complete Home Assistant Guide (with D-Pad & Automations) โž”

Quick Installation

Install with Homebrew, Home Assistant Add-on, Docker, or standalone binary in seconds.

Install directly on macOS or Linux via the official Homebrew tap:

brew tap smford/tap
brew install cam-proxy

# Start the gateway with your configuration
cam-proxy -config cam-proxy.yaml

Install the official add-on in Home Assistant OS / Supervised:

# 1. In Home Assistant: Settings -> Add-ons -> Add-on Store -> Repositories
# 2. Add repository:
https://github.com/smford/cam-proxy

# 3. Locate 'cam-proxy', click 'Install', configure cameras, and click 'Start'

Run the minimal multi-arch container with host networking for ONVIF discovery:

docker run -d \
  --name cam-proxy \
  --restart unless-stopped \
  --network host \
  -v $(pwd)/cam-proxy.yaml:/etc/cam-proxy/cam-proxy.yaml:ro \
  ghcr.io/smford/cam-proxy:latest

Install as an isolated, sandboxed Systemd daemon with DynamicUser security:

# Download latest Linux ARM64 binary for Raspberry Pi
curl -sL https://github.com/smford/cam-proxy/releases/download/v0.4.0/cam-proxy_0.4.0_linux_arm64.tar.gz | tar -xz
sudo mv cam-proxy /usr/local/bin/

# Install systemd unit and start service
sudo cp systemd/cam-proxy.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now cam-proxy

Discover cameras and generate a complete YAML configuration interactively:

# Probe local subnet for ONVIF cameras via WS-Discovery
cam-proxy --scan

# Launch the interactive terminal setup wizard
cam-proxy --tui

HTTP REST API

Clean, low-latency endpoints ready for Home Assistant, Scrypted, Frigate, or web dashboards.

Method Endpoint Description Headers / Type
GET /api/v1/cameras/{id}/snapshot Coalesced, TTL-cached JPEG snapshot (< 100ms) image/jpeg
GET /api/v1/cameras/{id}/mjpeg Continuous multipart MJPEG video stream multipart/x-mixed-replace
POST /api/v1/cameras/{id}/ptz Pan/Tilt/Zoom continuous move, stop, or preset recall application/json
GET /api/v1/status Gateway uptime, configured cameras, and operational health application/json
GET /metrics Prometheus metrics (snapshots, latencies, cache hits) text/plain
GET /openapi.yaml Complete OpenAPI 3.1.0 specification application/yaml