mirror of
https://github.com/scottlamb/moonfire-nvr.git
synced 2024-12-27 07:35:56 -05:00
981cee0706
SelectView::set_selection doesn't seem to be working properly. The symptom is editing an existing camera will clear the sample file dir, and thus hitting edit without making any changes will fail.
296 lines
11 KiB
Markdown
296 lines
11 KiB
Markdown
# Installing Moonfire NVR <!-- omit in toc -->
|
||
|
||
* [Downloading, installing, and configuring Moonfire NVR with Docker](#downloading-installing-and-configuring-moonfire-nvr-with-docker)
|
||
* [Dedicated hard drive setup](#dedicated-hard-drive-setup)
|
||
* [Completing configuration through the UI](#completing-configuration-through-the-ui)
|
||
* [Starting it up](#starting-it-up)
|
||
|
||
## Downloading, installing, and configuring Moonfire NVR with Docker
|
||
|
||
This document describes how to download, install, and configure Moonfire NVR
|
||
via the prebuilt Docker images available for x86-64, arm64, and arm. If you
|
||
instead want to build Moonfire NVR yourself, see the [Build
|
||
instructions](build.md).
|
||
|
||
First, install [Docker](https://www.docker.com/) if you haven't already,
|
||
and verify `sudo docker run --rm hello-world` works.
|
||
|
||
<details>
|
||
<summary><tt>sudo</tt> or not?</summary>
|
||
|
||
If you prefer to save typing by not prefixing all `docker` and `nvr` commands
|
||
with `sudo`, see [Docker docs: Manage Docker as a non-root
|
||
user](https://docs.docker.com/engine/install/linux-postinstall/#manage-docker-as-a-non-root-user).
|
||
Note `docker` access is equivalent to root access security-wise.
|
||
</details>
|
||
|
||
Next, you'll need to set up your filesystem and the Moonfire NVR user.
|
||
|
||
Moonfire NVR keeps two kinds of state:
|
||
|
||
* a SQLite database, typically <1 GiB. It should be stored on flash if
|
||
available. In most cases your root filesystem is on flash, so the
|
||
default location of `/var/lib/moonfire-nvr/db` will be fine.
|
||
* the "sample file directories", which hold the actual samples/frames of
|
||
H.264 video. These should be quite large and are typically stored on hard
|
||
drives. More below.
|
||
|
||
(See [schema.md](schema.md) for more information.)
|
||
|
||
On most Linux systems, you can create the user as follows:
|
||
|
||
```console
|
||
$ sudo useradd --user-group --create-home --home /var/lib/moonfire-nvr moonfire-nvr
|
||
```
|
||
|
||
and create a script called `nvr` to run Moonfire NVR as the intended host user.
|
||
This script supports running Moonfire NVR's various administrative commands interactively
|
||
and managing a long-lived Docker container for its web interface.
|
||
|
||
As you set up this script, adjust the `tz` variable as appropriate for your
|
||
time zone.
|
||
|
||
Use your favorite editor to create `/usr/local/bin/nvr`, starting from the
|
||
configuration below:
|
||
|
||
```console
|
||
$ sudo nano /usr/local/bin/nvr
|
||
(see below for contents)
|
||
$ sudo chmod a+rx /usr/local/bin/nvr
|
||
```
|
||
|
||
`/usr/local/bin/nvr`:
|
||
```bash
|
||
#!/bin/bash -e
|
||
|
||
# Set your timezone here.
|
||
tz="America/Los_Angeles"
|
||
|
||
# or eg "scottlamb/moonfire-nvr:v0.7.1" to specify a particular version.
|
||
image_name="scottlamb/moonfire-nvr:latest"
|
||
container_name="moonfire-nvr"
|
||
common_docker_run_args=(
|
||
--mount=type=bind,source=/var/lib/moonfire-nvr,destination=/var/lib/moonfire-nvr
|
||
|
||
# Add additional mount lines here for each sample file directory
|
||
# outside of /var/lib/moonfire-nvr, eg:
|
||
# --mount=type=bind,source=/media/nvr/sample,destination=/media/nvr/sample
|
||
|
||
--user="$(id -u moonfire-nvr):$(id -g moonfire-nvr)"
|
||
|
||
# This avoids errors with broken seccomp on Raspberry Pi OS.
|
||
--security-opt=seccomp:unconfined
|
||
|
||
# docker's default log driver won't rotate logs properly, and will throw
|
||
# away logs when you destroy and recreate the container. Using journald
|
||
# solves these problems.
|
||
# https://docs.docker.com/config/containers/logging/configure/
|
||
--log-driver=journald
|
||
--log-opt="tag=moonfire-nvr"
|
||
|
||
--env=RUST_BACKTRACE=1
|
||
--env=TZ=":${tz}"
|
||
)
|
||
|
||
case "$1" in
|
||
run)
|
||
shift
|
||
exec docker run \
|
||
--detach=true \
|
||
--restart=unless-stopped \
|
||
"${common_docker_run_args[@]}" \
|
||
|
||
# This is the simplest way of configuring networking, although
|
||
# you can use eg --publish=8080:8080 if you prefer.
|
||
--network=host \
|
||
|
||
--name="${container_name}" \
|
||
"${image_name}" \
|
||
run \
|
||
|
||
# Add any additional `moonfire-nvr run` arguments here, eg
|
||
# "--rtsp-library=ffmpeg" if the default "--rtsp-library=retina"
|
||
# isn't working.
|
||
--allow-unauthenticated-permissions='view_video: true' \
|
||
|
||
"$@"
|
||
;;
|
||
start|stop|logs|rm)
|
||
exec docker "$@" "${container_name}"
|
||
;;
|
||
pull)
|
||
exec docker pull "${image_name}"
|
||
;;
|
||
*)
|
||
exec docker run \
|
||
--interactive=true \
|
||
--tty \
|
||
--rm \
|
||
"${common_docker_run_args[@]}" \
|
||
"${image_name}" \
|
||
"$@"
|
||
;;
|
||
esac
|
||
```
|
||
|
||
then try it out by initializing the database:
|
||
|
||
```console
|
||
$ sudo nvr init
|
||
```
|
||
|
||
This will create a directory `/var/lib/moonfire-nvr/db` with a SQLite3 database
|
||
within it.
|
||
|
||
### Dedicated hard drive setup
|
||
|
||
If a dedicated hard drive is available, set it up now.
|
||
|
||
If you haven't yet created the filesystem, consider using
|
||
`mkfs.ext4 -T largefile -m 1`, as described in more detail [on the
|
||
wiki](https://github.com/scottlamb/moonfire-nvr/wiki/System-setup). If you're
|
||
using a USB SATA bridge, this is also a good time to ensure you're not
|
||
using UAS, as described there. UAS has been linked to filesystem corruption.
|
||
|
||
Set up the mount point and sample file directory:
|
||
|
||
```console
|
||
$ sudo vim /etc/fstab
|
||
$ sudo mkdir /media/nvr
|
||
$ sudo mount /media/nvr
|
||
$ sudo install -d -o moonfire-nvr -g moonfire-nvr -m 700 /media/nvr/sample
|
||
```
|
||
|
||
In `/etc/fstab`, add a line similar to this:
|
||
|
||
```
|
||
UUID=23d550bc-0e38-4825-acac-1cac8a7e091f /media/nvr ext4 nofail,noatime,lazytime,data=writeback,journal_async_commit 0 2
|
||
```
|
||
|
||
You can look up the correct uuid for your disk via `blkid`.
|
||
|
||
If you use the `nofail` attribute in `/etc/fstab` as described above, your
|
||
system will boot successfully even when the hard drive is unavailable (such as
|
||
when your external USB storage is unmounted). This can be helpful when
|
||
recovering from problems.
|
||
|
||
Create the sample directory.
|
||
|
||
```console
|
||
$ sudo mkdir /media/nvr/sample
|
||
$ sudo chown -R moonfire-nvr:moonfire-nvr /media/nvr
|
||
```
|
||
|
||
Add a new `--mount` line to your Docker wrapper script `/usr/local/bin/nvr`
|
||
to expose this new volume to the Docker container, right where a comment
|
||
mentions "Additional mount lines".
|
||
|
||
### Completing configuration through the UI
|
||
|
||
Once your system is set up, it's time to initialize an empty database
|
||
and add the cameras and sample directories. You can do this
|
||
by using the `moonfire-nvr` binary's text-based configuration tool.
|
||
|
||
```console
|
||
$ sudo nvr config 2>debug-log
|
||
```
|
||
|
||
<details>
|
||
<summary>Did it return without doing anything?</summary>
|
||
|
||
If `nvr config` returns you to the console prompt right away, look in the
|
||
`debug-log` file for why. One common reason is that you have Moonfire NVR
|
||
running; you'll need to shut it down first. Try `nvr stop` before `nvr config`
|
||
and `nvr start` afterward.
|
||
</details>
|
||
|
||
In the user interface,
|
||
|
||
1. add your sample file dir(s) under "Directories and retention".
|
||
(Many streams can share a directory. It's recommended to have just one
|
||
directory per hard drive.)
|
||
|
||
If you used a dedicated hard drive, use the directory you precreated
|
||
(eg `/media/nvr/sample`). Otherwise, try
|
||
`/var/lib/moonfire-nvr/sample`. Moonfire NVR will create the directory as
|
||
long as it has the required permissions on the parent directory.
|
||
|
||
2. add cameras under "Cameras and streams".
|
||
|
||
* See the [wiki](https://github.com/scottlamb/moonfire-nvr/wiki) for notes
|
||
about specific camera models. The [Configuring cameras](https://github.com/scottlamb/moonfire-nvr/wiki/Configuring-cameras)
|
||
page mentions a couple tools that can autodetect RTSP URLs.
|
||
|
||
* There's a "Test" button to verify your settings directly from the add/edit
|
||
camera dialog.
|
||
|
||
* Be sure to assign each stream you want to capture to a sample file
|
||
directory and check the "record" box.
|
||
|
||
* `flush_if_sec` should typically be 120 seconds. This causes the database to
|
||
be flushed when the first instant of one of this stream's completed
|
||
recordings is 2 minutes old. A "recording" is a segment of a video
|
||
stream that is 60–120 seconds when first establishing the stream,
|
||
about 60 seconds midstream, and shorter when an error or server
|
||
shutdown terminates the stream. Thus, a value just below 60 will
|
||
cause the database to be flushed once per minute per stream in the
|
||
steady state. A value around 180 will cause the database to be once
|
||
every 3 minutes per stream, or less frequently if other streams cause
|
||
flushes first. Lower values cause less video to be lost on power
|
||
loss. Higher values reduce wear on the SSD holding the SQLite
|
||
database, particularly when you have many cameras and when you record
|
||
both the "main" and "sub" streams of each camera.
|
||
|
||
3. Assign disk space to your cameras back in "Directories and retention".
|
||
Leave a little slack between the total limit and the filesystem capacity,
|
||
even if you store nothing else on the disk. 1 GiB of slack per camera should
|
||
be plenty. This is needed for a few reasons:
|
||
|
||
* Up to `max(120, flush_if_sec)` seconds of video can be written before
|
||
being counted toward the usage because the recording doesn't count until
|
||
it's fully written, and old recordings can't be deleted until the
|
||
next database flush. So a 8 Mbps video stream with `flush_if_sec=300`
|
||
will take up to (8 Mbps * 300 sec / 8 bits/byte) = 300 MB ~= 286 MiB
|
||
of extra disk space.
|
||
* If a file is open when it is deleted (such as if a HTTP client is
|
||
downloading it), it stays around until the file is closed. Moonfire NVR
|
||
currently doesn't account for this.
|
||
* Smaller factors: deletion isn't instantaneous, and directories
|
||
themselves take up some disk space.
|
||
|
||
4. Add a user for yourself (and optionally others) under "Users". You'll need
|
||
this to access the web UI once you enable authentication.
|
||
|
||
### Starting it up
|
||
|
||
Note that at this stage, Moonfire NVR's web interface is **insecure**: it
|
||
doesn't use `https` and doesn't require you to authenticate
|
||
to it. You might be comfortable starting it in this configuration to try it
|
||
out, particularly if the machine it's running on is behind a home router's
|
||
firewall. You might not; in that case read through [secure the
|
||
system](secure.md) first.
|
||
|
||
This command will start a detached Docker container for the web interface.
|
||
It will automatically restart when your system does.
|
||
|
||
```console
|
||
$ sudo nvr run
|
||
```
|
||
|
||
You can temporarily disable the service via `nvr stop` and restart it later via
|
||
`nvr start`. You'll need to do this before and after using `nvr config`.
|
||
|
||
The HTTP interface is accessible on port 8080; if your web browser is running
|
||
on the same machine, you can access it at
|
||
[http://localhost:8080/](http://localhost:8080/).
|
||
|
||
If the system isn't working, see the [Troubleshooting
|
||
guide](troubleshooting.md).
|
||
|
||
See also the [system setup guide](https://github.com/scottlamb/moonfire-nvr/wiki/System-setup)
|
||
on the wiki, which has additional advice on configuring a Linux system which
|
||
runs Moonfire NVR.
|
||
|
||
Once the web interface seems to be working, read through [securing Moonfire
|
||
NVR](secure.md).
|