Most self-hosted NVR setups end up exposing more than they mean to. You add a camera, go2rtc opens its signaling and media ports, and now youâre deciding which of three services to firewall. Argus collapses that surface to one port.
go2rtc handles the RTSP restreaming, one connection per camera, fanned out internally to the recorder and the detector. But browsers never talk to go2rtc directly. FastAPI reverse-proxies it, HTTP and WebSocket both, over port 8080. go2rtcâs own ports, 1984, 8554, 8555, stay bound to 127.0.0.1. The only thing that needs exposing to your LAN is the app itself.
Recording is split into two paths that donât compete for CPU. FFmpeg stream-copies straight to fragmented MP4, no re-encode, which means near-zero CPU load for continuous 24/7 capture and crash-safe segments if the box loses power mid-recording. Motion detection runs separately: frame-diff plus a scipy blob filter, with per-camera zones and sensitivity. Hikvision cameras skip frame-diff entirely and subscribe to the ISAPI alert stream for hardware VMD events instead.
Face recognition runs on InsightFaceâs buffalo_sc model, a 512-dimension ONNX model, CPU only. No GPU requirement, no cloud inference call. The embeddings themselves are stored as raw numpy float32 bytes rather than pickled objects, which closes off the deserialization RCE class of bug you get when a face-recognition pipeline unpickles stored vectors it doesnât fully trust.
Auth is JWT Bearer on every /api/* route except the health check. The one deliberate exception is media: /recordings/*/video, thumbnails, heatmaps, and snapshots also accept a ?token= query param, because <video> and <img> tags canât attach custom headers. Camera passwords are Fernet-encrypted at rest using the same secret key that signs the JWTs. RBAC gates the operations that matter: admin, operator, viewer, with user management, audit log access, and recording purges locked to admin. Every login, password reset, and camera change lands in the audit log with username, IP, and timestamp.
Webhooks get HMAC-SHA256 signatures in an X-Argus-Signature header, so a receiver can verify a notification actually came from your NVR before acting on it. And the README is blunt about the one thing it canât fix for you: donât put port 8080 on the public internet. Use Tailscale, or put TLS in front of it yourself.