Home security cameras have a dirty secret: the software is the weak link. You buy a decent ONVIF camera and then you're locked into the vendor's app, or you sign up for a cloud service that bills per camera, or you stand up an NVR that wants a dedicated machine with a Coral TPU before it does anything interesting.
I wanted the opposite. One binary I could drop on a Raspberry Pi, a web UI that doesn't feel like 2005, cameras that get discovered instead of configured, and no monthly fee. That project became MiBee NVR. It runs on a 512MB memory budget and the README's claim, which I stand by, is that a Pi 3B is the minimum baseline. The repo is at github.com/Mi-Bee-Studio/MiBeeNvr, current version 0.11.0.
The pitch in one line: single Go binary, zero dependencies (CGO_ENABLED=0), an embedded Svelte 5 SPA, no cloud, no subscriptions. Install is one curl piped to bash, or a prebuilt binary for amd64, arm64, or armv7, or Docker from ghcr.io/mi-bee-studio/mibeenvr. The UI runs on port 9090 and comes with dark/light themes and English/Chinese out of the box.
ONVIF that behaves
The thing I'm proudest of is the ONVIF handling, because it fixes the pain I kept hitting with real cameras. Cameras on WiFi roam between access points and come back with a new IP. Your NVR still has the old one stored, the feed dies, and you go digging through the router's DHCP table to fix it. MiBee NVR instead enrolls ONVIF cameras automatically in the background when they join the LAN, the way a Hikvision NVR does. No manual scan.
Two details I like:
- Unauthenticated cameras start recording immediately. If it's open, it's in.
- Authenticated cameras are added as pending until you supply credentials.
And the IP self-healing: when a camera changes IP, the NVR relocates it by serial number and reconnects. The unicast probing works across routed subnets, so it isn't limited to one broadcast domain.
Browser-side AI, no Coral required
Most NVR setups push detection to a separate box, often a USB Coral or an Nvidia card. MiBee NVR runs inference in the browser tab instead. ONNX Runtime Web with WebGPU acceleration, a 5.4MB yolo11n model by default (squeezenet is there as a fallback). The backend does zero inference, so the Pi never breaks a sweat, and the video never leaves the device to get "analyzed" somewhere else. If your browser supports WebGPU you get object detection; if it doesn't, you still get a fully working NVR.
One real constraint worth knowing: without crossOriginIsolated there's no SharedArrayBuffer, so the runtime is single-threaded. Fine for one camera, something to remember if you plan to run several detections at once.
The war story: model files kept coming back corrupted and ORT threw INVALID_PROTOBUF. Root cause was our own gzip middleware. Calling Close() on a gzip.Writer that never wrote anything appends an empty gzip member, about 20 bytes, to the end of binary responses. The ONNX file was fine except for those 20 bytes. The fix tracks whether the writer ever wrote and only calls Close()/Flush() after the first Write(). That's issue #109 if you want the details.
Every protocol, in and out
NVR is a messy word because it covers two directions: getting streams in and getting streams out.
Inbound, MiBee NVR speaks RTSP (H.264, H.265, MJPEG), HTTP JPEG snapshots, RTMP ingest, SRT ingest, and WHIP, which is WebRTC push. The WHIP support is the headline feature of v0.11.0 and it's fun: you can publish from a browser tab or OBS with a stream key mapped to a camera, no extra software.
Outbound to your browser: WebRTC via WHEP for sub-second latency, HLS with LL-HLS for on-demand, HTTP-FLV, and raw WebSocket frames. If you need to push somewhere else, there's a native Go relay that forwards any camera to a remote RTMP or RTSP target. Point it at a streaming platform and you have a cheap live production pipeline.
Recording, the part people forget
An NVR that can't scrub is a paperweight. Recordings are MP4 segments with per-camera retention policies, audio capture (AAC, G.711, Opus), and a timelapse mode. Playback chains segments with double buffering so there's no gap when you're watching back, and the VOD timeline covers a full day, so you can drag across recordings and the gaps between them. There's also an AVI frame-browse mode when you need to step through frame by frame.
Built for the homelab, not around it
This was a design goal, so the integration list is deliberately boring: MQTT for trigger-based recording (Home Assistant people know what to do), WebDAV and FTP for pulling files off the box, a Prometheus metrics endpoint with full docs, a REST API with BasicAuth and bcrypt, and a stable device_id in /api/health so your automation has something to hold onto. Discovery is mDNS (_mibee-nvr._tcp) with a UDP responder as fallback for networks that block multicast.
Remote access is your choice: Tailscale, Cloudflare Tunnel, or WebRTC ICE/STUN/TURN configuration. The docs cover all three.
Deployment story
- One-liner:
curl -fsSL https://raw.githubusercontent.com/Mi-Bee-Studio/MiBeeNvr/main/install.sh | sudo bash, which creates a systemd service, a system user, and a config. - Binaries for amd64, arm64, and armv7 from GitHub Releases.
- Docker images on GHCR with exact, minor, major, and
latesttags. - NAS guides for unRAID, Synology, and QNAP, plus fnOS, iStoreOS, and 极空间 if you're in the Chinese NAS ecosystem.
The China-market side, in one paragraph
MiBee NVR also speaks GB/T 28181, the Chinese national standard for video surveillance, as an experimental SIP platform, and it can adopt Xiaomi cloud cameras (CS2 and legacy TUTK models). If you're not in China, ignore both of those; they exist because the home market runs on them. Everything else in this post is the same code path.
Engineering hygiene and licensing
The repo has 3991 Go tests, 389 frontend tests, and 13 Playwright E2E tests, with golangci-lint v2 (gofumpt, perfsprint) enforced in CI. One honest note on licensing: versions up to v0.10.1 are MIT. From v0.11.0 the project moved to AGPL-3.0-only, with a linking exception for pkg/ so you can build against the extension interfaces without triggering AGPL obligations. Running it, recording cameras, watching streams: no obligations, commercial use included.
Quick start
curl -fsSL https://raw.githubusercontent.com/Mi-Bee-Studio/MiBeeNvr/main/install.sh | sudo bash
Or grab a binary:
wget https://github.com/Mi-Bee-Studio/MiBeeNvr/releases/latest/download/mibee-nvr-arm64
chmod +x mibee-nvr-arm64
./mibee-nvr-arm64 init --password yourpassword
./mibee-nvr-arm64 -config mibee-nvr.yaml
Then open http://localhost:9090.
There's documentation for everything mentioned here: getting started, a full configuration reference, the REST API, an ONVIF guide, transcoding, metrics, and per-NAS deployment. The architecture doc is a good place to start if you want to read the code with a map.
If you run it and something breaks, the issues tracker is open. I read everything, and the WHIP ingest that just landed came straight out of user requests.












