scottlamb / moonfire-nvr

Moonfire NVR, a security camera network video recorder
Other
1.22k stars 137 forks source link

Proxy server for camera admin #154

Open clydebarrow opened 3 years ago

clydebarrow commented 3 years ago

Remote access to the admin panel of connected cameras would be a very useful feature. Right now this requires direct network access to the camera, which should be difficult - ideally the cameras will be on a dedicated subnet with no access to the outside world.

If the Moonfire server provides a suitable secured proxy this could enable camera admin from anywhere the server itself is available. This could be an Nginx instance inside the Docker container, with dynamic configuration as cameras are added or deleted.

How would the proxy map the camera ports (all typically going to be port 80) to the client? Allocating a random port on the server for each camera would work locally and through a VPN, but not with port mapping through a NAT router, unless UPNP was used. Is there another way?

scottlamb commented 3 years ago

This would be very convenient, and @JasonKleban had a similar idea in #118.

How would the proxy map the camera ports (all typically going to be port 80) to the client? Allocating a random port on the server for each camera would work locally and through a VPN, but not with port mapping through a NAT router, unless UPNP was used. Is there another way?

What about name-based virtual serving?

If the Moonfire server provides a suitable secured proxy

The most interesting word in that sentence IMHO is "secured". Especially from the WAN, I don't want to directly proxy unauthenticated requests to cameras, as I don't trust them to handle authentication properly. Do we use HTTP digest authentication with credentials from Moonfire's database? Require our own cookie (and redirect to a login page when it's absent)? Either might conflict with something the camera is doing, so I'm not really sure.

This could be an Nginx instance inside the Docker container, with dynamic configuration as cameras are added or deleted.

I don't think it's too hard to support HTTP proxying in Rust with hyper, so we could do this directly in the moonfire-nvr server, not have to mess with other software's configs, and support either:

Or a totally different approach: run up a SOCKS proxy with username/password that allows connecting to configured cameras. It wouldn't be as slick on the client side (you'd have to adjust your proxy settings), but it's probably not hard to do.

scottlamb commented 3 years ago

Or a totally different approach: run up a SOCKS proxy with username/password that allows connecting to configured cameras. It wouldn't be as slick on the client side (you'd have to adjust your proxy settings), but it's probably not hard to do.

btw, this is close to what I do now (not through Moonfire NVR). openssh supports both fixed port forwards and "dynamic forwards" (SOCKS proxy), so I ssh in to my router and use one or the other of those. iirc some cameras have somehow broken SOCKS support in their web UI with their crappy custom plugins though.

scottlamb commented 3 years ago

Speaking of crappy cameras and broken web UIs, another caveat is that for some cameras, their Windows/macOS software is that uses a custom non-HTTP protocol is more functional than their web UIs. (This is particularly true since the Adobe Flash end of life date.) So HTTP proxying would be useful for some but not all cameras.

clydebarrow commented 3 years ago

I thought of using SOCKS but that isn't a zero-configuration approach. Same with virtual hosts and custom DNS. Along with broken camera UIs I am sure this will end up being a best-effort, no guarantees feature, but still one that would be very useful where it works. I have to use a VPN to access my system from outside, since I'm behind three layers of NAT, so the port-based approach could work fine for me and any access from a local network. UPNP is still an option for NAT tunneling.

WRT to authentication if you implemented a proxy in the server itself that should be easy to link with the user login. But bundling Nginx would also be an easy path to HTTPS support. Nginx has so many features that I would not be surprised if it were relatively easy for it to query the Moonfire server to validate credentials.

scottlamb commented 3 years ago

I'd think the name-based setup would be pretty easy if well-implemented in Moonfire. I'm assuming if you're you're setting up access from outside, you're setting up some kind of DNS entry (via DDNS unless you have a static IP). I'd expect most providers support wildcard DDNS or wildcard CNAME to DDNS. So if you want to use Moonfire NVR directly, you add one of those and configure the same name in Moonfire NVR. If you want to use nginx for https, you tell it about the domain also. (Maybe you'd tell it about each camera's name, as on closer inspection letsencrypt wildcards require the ACME-01 challenge, likely more of a barrier.)

The port way also seems doable. One thing to consider is that cookies aren't port-specific so I'd imagine it'd be impossible to have sessions to two same-brand cameras open at once. [edit: on the other hand, this means if we use the s= cookie for authentication, then once you're authenticated to the NVR, you're authenticated to everything, which is convenient.] [edit: Also, I'm skeptical too many Moonfire NVR users have UPnP enabled on their routers, so I don't think it's really zero-configuration.]

WRT to authentication if you implemented a proxy in the server itself that should be easy to link with the user login. But bundling Nginx would also be an easy path to HTTPS support.

Those aren't mutually exclusive. I think if people want to use nginx for https, we'd just do browser->nginx->moonfire->camera. There aren't enough bytes going through that the inefficiency of the extra layer would be significant.