From 1c904b925aff136a9bdaf5374f3086a59286d11c Mon Sep 17 00:00:00 2001 From: Scott Lamb Date: Tue, 9 Jul 2019 23:48:06 -0700 Subject: [PATCH] many improvements to install docs/procedures * in markdown files, use code fences rather than indented blocks. This is harder to screw up (one of them was off by a space so didn't render properly) and allows me to add info strings. * uniformly use "useradd" to create the user and group in all three places (install-manual.md, script-functions.sh, Dockerfile) rather than addgroup + adduser. Create a full home dir, which I suspect was the problem in #67. Don't allow customizing group name; it's always the same as the user. * install the sqlite3 package so that the "moonfire-nvr sql" command works properly. * remove "setup_db" function, which was out of place. Since the creation of the "moonfire-nvr init" command, this has to happen after installation of the binary. install.md gives instructions on this part anyway so remove it from the script. * give a proper command to create the db dir. It was creating it within the current directory, not within /var/lib/moonfire-nvr. Don't bother creating sample directory; "moonfire-nvr config" will do this. * when setting owners on a newly created directory, use a single "install -d" command rather than "mkdir" + "chown". * address confusion about whether sample file dirs need to be precreated. (Only when Moonfire NVR doesn't have write permissions on the parent.) * always just install the packaged version of ffmpeg rather than building our own. This has been usable since Debian/Raspbian 9 Stretch; Debian/Raspbian 10 Buster is out now so there's no excuse for still running Debian/Raspbian 8 Jessie. * don't chown the UI directory; it can be owned by root as with the binary. * in scripts/install.sh, don't enable/start the service yet. It hasn't been configured. --- Dockerfile | 7 ++- guide/install-manual.md | 98 ++++++++++++++++++++----------------- guide/install-scripted.md | 1 - guide/install.md | 65 ++++++++++++++---------- scripts/install.sh | 14 +----- scripts/script-functions.sh | 61 ++--------------------- scripts/setup-ubuntu.sh | 55 ++------------------- 7 files changed, 104 insertions(+), 197 deletions(-) diff --git a/Dockerfile b/Dockerfile index 2e873a7..cd74cba 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,13 +6,12 @@ RUN apt-get update && \ apt-get install -y apt-utils && \ apt-get install -y apt-transport-https tzdata git curl sudo vim && \ rm -rf /var/lib/apt/lists/* -RUN groupadd -r moonfire-nvr && \ - useradd moonfire-nvr --no-log-init -m -r -g moonfire-nvr && \ +RUN useradd --no-log-init --home-dir /var/lib/moonfire-nvr --system --user-group moonfire-nvr && \ echo 'moonfire-nvr ALL=(ALL) NOPASSWD: ALL' >>/etc/sudoers -ENV HOME /home/moonfire-nvr +ENV HOME /var/lib/moonfire-nvr COPY --chown=moonfire-nvr:moonfire-nvr . /home/moonfire-nvr/moonfire-nvr USER moonfire-nvr -WORKDIR /home/moonfire-nvr/moonfire-nvr +WORKDIR /var/lib/moonfire-nvr/moonfire-nvr RUN whoami && ls -l && \ ./scripts/setup-ubuntu.sh && \ ./scripts/setup-ubuntu.sh && \ diff --git a/guide/install-manual.md b/guide/install-manual.md index f49cbe9..bdc2131 100644 --- a/guide/install-manual.md +++ b/guide/install-manual.md @@ -33,17 +33,20 @@ You will need the following C libraries installed: On recent Ubuntu or Raspbian, the following command will install all non-Rust dependencies: - $ sudo apt-get install \ - build-essential \ - libavcodec-dev \ - libavformat-dev \ - libavutil-dev \ - libncurses5-dev \ - libncursesw5-dev \ - libsqlite3-dev \ - libssl-dev \ - pkgconf \ - tzdata +``` +$ sudo apt-get install \ + build-essential \ + libavcodec-dev \ + libavformat-dev \ + libavutil-dev \ + libncurses5-dev \ + libncursesw5-dev \ + libsqlite3-dev \ + libssl-dev \ + pkgconf \ + sqlite3 \ + tzdata +``` Next, you need Rust 1.33+ and Cargo. The easiest way to install them is by following the instructions at [rustup.rs](https://www.rustup.rs/). @@ -52,60 +55,65 @@ Finally, building the UI requires [yarn](https://yarnpkg.com/en/). Once prerequisites are installed, Moonfire NVR can be built as follows: - $ yarn - $ yarn build - $ cargo test - $ cargo build --release - $ sudo install -m 755 target/release/moonfire-nvr /usr/local/bin - $ sudo mkdir /usr/local/lib/moonfire-nvr - $ sudo cp -R ui-dist /usr/local/lib/moonfire-nvr/ui +``` +$ yarn +$ yarn build +$ cargo test +$ cargo build --release +$ sudo install -m 755 target/release/moonfire-nvr /usr/local/bin +$ sudo mkdir /usr/local/lib/moonfire-nvr +$ sudo cp -R ui-dist /usr/local/lib/moonfire-nvr/ui +``` ## Creating the user and database You can create Moonfire NVR's dedicated user and SQLite database with the following commands: - $ sudo addgroup --system moonfire-nvr - $ sudo adduser --system moonfire-nvr --home /var/lib/moonfire-nvr - $ sudo mkdir /var/lib/moonfire-nvr - $ sudo chown moonfire-nvr:moonfire-nvr /var/lib/moonfire-nvr - $ sudo -u moonfire-nvr -H mkdir db sample - $ sudo -u moonfire-nvr moonfire-nvr init +``` +$ sudo useradd --system --user-group --create-home --home /var/lib/moonfire-nvr moonfire-nvr +$ sudo -u moonfire-nvr -H sh -c 'cd && mkdir --mode=700 db' +$ sudo -u moonfire-nvr moonfire-nvr init +``` ## System Service Moonfire NVR can be run as a systemd service. Create `/etc/systemd/system/moonfire-nvr.service`: - [Unit] - Description=Moonfire NVR - After=network-online.target +``` +[Unit] +Description=Moonfire NVR +After=network-online.target - [Service] - ExecStart=/usr/local/bin/moonfire-nvr run \ - --db-dir=/var/lib/moonfire-nvr/db \ - --http-addr=0.0.0.0:8080 - Environment=TZ=:/etc/localtime - Environment=MOONFIRE_FORMAT=google-systemd - Environment=MOONFIRE_LOG=info - Environment=RUST_BACKTRACE=1 - Type=simple - User=moonfire-nvr - Nice=-20 - Restart=on-abnormal - CPUAccounting=true - MemoryAccounting=true - BlockIOAccounting=true +[Service] +ExecStart=/usr/local/bin/moonfire-nvr run \ + --db-dir=/var/lib/moonfire-nvr/db \ + --http-addr=0.0.0.0:8080 +Environment=TZ=:/etc/localtime +Environment=MOONFIRE_FORMAT=google-systemd +Environment=MOONFIRE_LOG=info +Environment=RUST_BACKTRACE=1 +Type=simple +User=moonfire-nvr +Nice=-20 +Restart=on-failure +CPUAccounting=true +MemoryAccounting=true +BlockIOAccounting=true - [Install] - WantedBy=multi-user.target +[Install] +WantedBy=multi-user.target +``` Note that the HTTP port currently has no authentication, encryption, or logging; it should not be directly exposed to the Internet. Tell `systemd` to look for the new file: - $ sudo systemctl daemon-reload +``` +$ sudo systemctl daemon-reload +``` See the [systemd](http://www.freedesktop.org/wiki/Software/systemd/) documentation for more information. The [manual diff --git a/guide/install-scripted.md b/guide/install-scripted.md index 048ff00..8e9d70b 100644 --- a/guide/install-scripted.md +++ b/guide/install-scripted.md @@ -89,7 +89,6 @@ Although not all listed in the default `prep.config` file, these are the available configuration variable and their defaults. NVR_USER=moonfire-nvr - NVR_GROUP=$NVR_USER NVR_PORT=8080 NVR_HOME_BASE=/var/lib DB_NAME=db diff --git a/guide/install.md b/guide/install.md index 0be18bb..ef37479 100644 --- a/guide/install.md +++ b/guide/install.md @@ -13,7 +13,9 @@ See the [github page](https://github.com/scottlamb/moonfire-nvr) (in case you're not reading this text there already). You can download the bleeding-edge version from the commandline via git: - $ git clone https://github.com/scottlamb/moonfire-nvr.git +``` +$ git clone https://github.com/scottlamb/moonfire-nvr.git +``` ## Building and installing from source @@ -39,26 +41,29 @@ Moonfire NVR keeps two kinds of state: By now Moonfire NVR's dedicated user and database should have been created for you. Next you need to create a sample file directory. -## Creating a sample file directory - -### ...on a dedicated hard drive +## Dedicated hard drive seutp If a dedicated hard drive is available, set up the mount point: - $ sudo vim /etc/fstab - $ sudo mkdir /media/nvr - $ sudo mount /media/nvr - $ sudo mkdir /media/nvr/sample - $ sudo chown moonfire-nvr:moonfire-nvr /media/nvr/sample +``` +$ 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 the fstab you'd add a line similar to this: +In `/etc/fstab`, add a line similar to this: - /dev/disk/by-uuid/23d550bc-0e38-4825-acac-1cac8a7e091f /media/nvr ext4 defaults,noatime,nofail 0 2 +``` +/dev/disk/by-uuid/23d550bc-0e38-4825-acac-1cac8a7e091f /media/nvr ext4 defaults,noatime,nofail 0 2 +``` You'll have to lookup the correct uuid for your disk. One way to do that is via the following command: - $ ls -l /dev/disk/by-uuid +``` +$ ls -l /dev/disk/by-uuid +``` 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 @@ -66,19 +71,18 @@ when your external USB storage is unmounted). This is convenient, but you likely want to ensure the `moonfire-nvr` service only starts when the mounting is successful. Edit the systemd configuration to do so: - $ sudo vim /etc/systemd/system/moonfire-nvr.service - $ sudo systemctl daemon-reload +``` +$ sudo vim /etc/systemd/system/moonfire-nvr.service +$ sudo systemctl daemon-reload +``` -You'll want to add a line like `Requires=media-nvr.mount` to the `[Unit]` -section of the file. +You'll want to add lines similar to the following to the `[Unit]` section of +the file: -### ...without a dedicated hard drive - -If you don't have a dedicated hard drive available, simply create a directory -owned by the dedicated user. It's convenient to place it within the -installation's directory (typically `/var/lib/moonfire-nvr`): - - $ sudo -u moonfire-nvr -H mkdir sample +``` +After=media.nvr.mount +Requires=media-mvr.mount +``` ## Completing configuration through the UI @@ -87,11 +91,18 @@ configurations to the database. You can configure the system's database through a text-based user interface: - $ sudo -u moonfire-nvr moonfire-nvr config 2>debug-log +``` +$ sudo -u moonfire-nvr moonfire-nvr config 2>debug-log +``` In the user interface, 1. add your sample file dir(s) under "Directories and retention". + If you used a dedicated hard drive, use the directory you precreated + (`/media/surveillance/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". * There's a "Test" button to verify your settings directly from the add/edit @@ -135,8 +146,10 @@ system](secure.md) first. The following commands will start Moonfire NVR and enable it for following boots, respectively: - $ sudo systemctl start moonfire-nvr - $ sudo systemctl enable moonfire-nvr +``` +$ sudo systemctl start moonfire-nvr +$ sudo systemctl enable moonfire-nvr +``` The HTTP interface is accessible on port 8080; if your web browser is running on the same machine, you can access it at diff --git a/scripts/install.sh b/scripts/install.sh index 995e71d..b6d5aa8 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -67,7 +67,6 @@ fi if [ -d "ui-dist" ]; then sudo mkdir -p "${LIB_DIR}/ui" sudo cp -R ui-dist/. "${LIB_DIR}/ui/" - sudo chown -R ${NVR_USER}:${NVR_GROUP} "${LIB_DIR}/ui/" echo_info -x "Server UI installed..." else echo_fatal -x "Server UI failed to build or install..." @@ -114,7 +113,7 @@ Environment=RUST_BACKTRACE=1 Type=simple User=${NVR_USER} Nice=-20 -Restart=on-abnormal +Restart=on-failure CPUAccounting=true MemoryAccounting=true BlockIOAccounting=true @@ -123,13 +122,4 @@ BlockIOAccounting=true WantedBy=multi-user.target NVR_EOF -# Configure and start service -# -if [ -f "${SERVICE_PATH}" ]; then - echo_info -x 'Configuring system daemon...' - sudo systemctl daemon-reload - sudo systemctl enable ${SERVICE_NAME} - sudo systemctl restart ${SERVICE_NAME} - echo_info -x 'Getting system daemon status...' - sudo systemctl status ${SERVICE_NAME} -fi +sudo systemctl daemon-reload diff --git a/scripts/script-functions.sh b/scripts/script-functions.sh index 0ee8fb1..980d055 100755 --- a/scripts/script-functions.sh +++ b/scripts/script-functions.sh @@ -41,8 +41,6 @@ NODE_MIN_VERSION="8" YARN_MIN_VERSION="1.0" CARGO_MIN_VERSION="0.2" RUSTC_MIN_VERSION="1.33" -FFMPEG_MIN_VERSION="55.1.101" -FFMPEG_RELEASE_VERSION="3.4" normalizeDirPath() { @@ -80,11 +78,6 @@ catPrefix() sed -e "s/^/$2/" < "$1" } -mkdir_moonfire() -{ - sudo -u "${NVR_USER}" -H mkdir "$@" -} - echo_multi() { local prefix='' @@ -151,7 +144,6 @@ initEnvironmentVars() . "${MOONFIRE_DIR}/prep.config" fi NVR_USER="${NVR_USER:-moonfire-nvr}" - NVR_GROUP="${NVR_GROUP:-$NVR_USER}" NVR_PORT="${NVR_PORT:-8080}" NVR_HOME_BASE="${NVR_HOME_BASE:-/var/lib}" NVR_HOME="${NVR_HOME_BASE}/${NVR_USER}" @@ -244,23 +236,6 @@ userExists() return $(id -u "$1" >/dev/null 2>&1) } -groupExists() -{ - return $(id -g "$1" >/dev/null 2>&1) -} - -moonfire() -{ - case "$1" in - start) - sudo systemctl start "$2" - ;; - stop) - sudo systemctl stop "$2" - ;; - esac -} - sudo_warn() { echo_warn -x -p '!!!!! ' \ @@ -271,48 +246,18 @@ sudo_warn() '------------------------------------------------------------------------------' } - -# Prepare for sqlite directory and set schema into db -# -setup_db() -{ - if [ ! -d "${DB_DIR}" ]; then - echo_info -x 'Create database directory...' - mkdir_moonfire -p "${DB_DIR}" - fi - echo_info -x 'Ensure database is initialized...' - sudo -u "${NVR_USER}" -H -- "${SERVICE_BIN}" init --db-dir="${DB_DIR}" -} - -# Make sure all sample directories and files owned by moonfire -# -fix_ownership() -{ - sudo chown -R ${NVR_USER}:${NVR_USER} "$1" - echo_info -x "Fix ownership of files in \"$1\"..." -} - -# Create user and groups if not there +# Create user, group, and database directory if not there # prep_moonfire_user() { echo_info -x "Create user/group and directories we need..." - if ! groupExists "${NVR_GROUP}"; then - sudo addgroup --quiet --system ${NVR_GROUP} - fi if ! userExists "${NVR_USER}"; then - sudo adduser --quiet --system ${NVR_USER} \ - --ingroup "${NVR_GROUP}" --home "${NVR_HOME}" + sudo useradd --system ${NVR_USER} --user-group --create-home --home-dir "${NVR_HOME}" fi - if [ ! -d "${NVR_HOME}" ]; then - sudo mkdir "${NVR_HOME}" - sudo chown "${NVR_USER}:${NVR_GROUP}" "${NVR_HOME}" - fi - sudo chown ${NVR_USER}:${NVR_GROUP} "${NVR_HOME}" + sudo -u ${NVR_USER} -H sh -c 'cd && test -d db || mkdir --mode=700 db' } pre_install_prep() { prep_moonfire_user - setup_db } diff --git a/scripts/setup-ubuntu.sh b/scripts/setup-ubuntu.sh index 6f05fe8..ba9d19c 100755 --- a/scripts/setup-ubuntu.sh +++ b/scripts/setup-ubuntu.sh @@ -38,32 +38,21 @@ makePrepConfig export DEBIAN_FRONTEND=noninteractive -# Process command line options -# -while getopts ":f" opt; do - case $opt in - f) DONT_BUILD_FFMPEG=1 - ;; - :) - echo_fatal "Option -$OPTARG requires an argument." - ;; - \?) - echo_fatal -x "Invalid option: -$OPTARG" - ;; - esac -done - sudo_warn # Setup all apt packages we need # echo_info -x 'Preparing and downloading packages we need...' PKGS="build-essential \ + libavcodec-dev \ + libavformat-dev \ + libavutil-dev \ libncurses5-dev \ libncursesw5-dev \ libsqlite3-dev \ libssl-dev \ pkgconf \ + sqlite3 \ tzdata" # Add yarn before NodeSource so it can all go in one update @@ -102,42 +91,6 @@ sudo apt-get install -y $PKGS sudo apt-get autoremove -y echo_info -x -# Check for ffmpeg and install by building if necessary -# This needs to be done before building moonfire so it can -# find the right versions of the libraries. -# -ffv=`ffmpeg -version 2>/dev/null | extractVersion libavutil` -ffv=${ffv:-0} -if ! versionAtLeast "$ffv" "$FFMPEG_MIN_VERSION"; then - if [ "${DONT_BUILD_FFMPEG:-0}" -ne 0 ]; then - echo_warn -x "ffmpeg version (${ffv}) installed is too old for moonfire." \ - "Suggest you manually install at least version $FFMPEG_MIN_VERSION of libavutil." \ - "ffmpeg versions 2.x and 3.x all should work." - else - OLDDIR=`pwd` - cd .. - if [ -d FFmpeg ]; then - echo_info -x "Removing older FFmpeg directory..." - rm -fr FFmpeg - fi - echo_info -x "Fetching FFmpeg source..." - git clone --depth 1 -b "release/${FFMPEG_RELEASE_VERSION}" https://github.com/FFmpeg/FFmpeg.git - cd FFmpeg - pt=`uname -p 2>/dev/null` - if [ -z "${pt##*86*}" ]; then - DEBIAN_FRONTEND=noninteractive sudo apt-get install -y yasm - fi - ./configure --enable-shared - make - sudo make install - sudo ldconfig - cd "$OLDDIR" - OLDDIR= - fi -else - echo_info -x "FFmpeg is already usable..." -fi - # If cargo appears installed, initialize for using it so rustc can be found # initCargo