mirror of
				https://github.com/scottlamb/moonfire-nvr.git
				synced 2025-10-29 15:55:01 -04:00 
			
		
		
		
	no more Docker!
* use `termion` rather than `ncurses` to limit runtime deps * cross-compile with `cross` instead of our own dockerfiles/scripts * update instructions * update release procedure and GitHub actions to match * prep changelog for `v0.7.8` Fixes #160 Closes #265
This commit is contained in:
		
							parent
							
								
									faf0201b52
								
							
						
					
					
						commit
						ee98bf5236
					
				
							
								
								
									
										3
									
								
								.github/ISSUE_TEMPLATE/bug_report.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.github/ISSUE_TEMPLATE/bug_report.md
									
									
									
									
										vendored
									
									
								
							| @ -24,8 +24,7 @@ A clear and concise description of what you expected to happen. | ||||
| If applicable, add screenshots to help explain your problem. | ||||
| 
 | ||||
| **Server (please complete the following information):** | ||||
|   - If using Docker: `docker ps` + `docker images` | ||||
|   - If building from git: `moonfire-nvr --version` | ||||
|   - `moonfire-nvr --version` | ||||
|   - Attach a [log file](https://github.com/scottlamb/moonfire-nvr/blob/master/guide/troubleshooting.md#viewing-moonfire-nvrs-logs). Run with the `RUST_BACKTRACE=1` environment variable set if possible. | ||||
| 
 | ||||
| **Camera (please complete the following information):** | ||||
|  | ||||
							
								
								
									
										19
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										19
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							| @ -1,6 +1,10 @@ | ||||
| name: CI | ||||
| on: [push, pull_request] | ||||
| 
 | ||||
| defaults: | ||||
|   run: | ||||
|     shell: bash | ||||
| 
 | ||||
| env: | ||||
|   CARGO_TERM_COLOR: always | ||||
|   MOONFIRE_COLOR: always | ||||
| @ -37,11 +41,7 @@ jobs: | ||||
|           restore-keys: | | ||||
|             cargo-${{ matrix.rust }}- | ||||
|             cargo- | ||||
|       - name: Install dependencies | ||||
|         # The retry here is to work around "Unable to connect to azure.archive.ubuntu.com" errors. | ||||
|         # https://github.com/actions/runner-images/issues/6894 | ||||
|         run: sudo apt-get --option=APT::Acquire::Retries=3 update && sudo apt-get --option=APT::Acquire::Retries=3 install libncurses-dev libsqlite3-dev pkgconf | ||||
|       - uses: actions/setup-node@v2 | ||||
|       - uses: actions/setup-node@v3 | ||||
|         with: | ||||
|           node-version: 18 | ||||
|       - name: Install Rust | ||||
| @ -51,13 +51,10 @@ jobs: | ||||
|           toolchain: ${{ matrix.rust }} | ||||
|           override: true | ||||
|           components: ${{ matrix.extra_components }} | ||||
|       - run: cd ui && npm ci | ||||
|       - run: cd ui && npm run build | ||||
|       - name: Test | ||||
|         run: | | ||||
|           cd server | ||||
|           cargo test ${{ matrix.extra_args }} --all | ||||
|           cargo test --features=bundled-ui ${{ matrix.extra_args }} --all | ||||
|           cargo test --features=rusqlite/bundled ${{ matrix.extra_args }} --all | ||||
|         continue-on-error: ${{ matrix.rust == 'nightly' }} | ||||
|       - name: Check formatting | ||||
|         if: matrix.rust == 'stable' | ||||
| @ -70,7 +67,7 @@ jobs: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - uses: actions/checkout@v4 | ||||
|       - uses: actions/setup-node@v2 | ||||
|       - uses: actions/setup-node@v3 | ||||
|         with: | ||||
|           node-version: ${{ matrix.node }} | ||||
|       - run: cd ui && npm ci | ||||
| @ -83,5 +80,5 @@ jobs: | ||||
|     runs-on: ubuntu-20.04 | ||||
|     steps: | ||||
|       - name: Checkout | ||||
|         uses: actions/checkout@v2 | ||||
|         uses: actions/checkout@v4 | ||||
|       - run: find . -type f -print0 | xargs -0 .github/workflows/check-license.py | ||||
|  | ||||
							
								
								
									
										104
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										104
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							| @ -1,19 +1,109 @@ | ||||
| name: Release | ||||
| 
 | ||||
| defaults: | ||||
|   run: | ||||
|     shell: bash | ||||
| 
 | ||||
| on: | ||||
|   push: | ||||
|     tags: | ||||
|       - v[0-9]+.* | ||||
| 
 | ||||
| jobs: | ||||
|   create-release: | ||||
|   base: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - uses: actions/checkout@v3 | ||||
|       - uses: taiki-e/create-gh-release-action@v1 | ||||
|       - name: Checkout | ||||
|         uses: actions/checkout@v4 | ||||
|       - uses: taiki-e/install-action@v2 | ||||
|         with: | ||||
|           # (Optional) Path to changelog. | ||||
|           changelog: CHANGELOG.md | ||||
|           tool: parse-changelog | ||||
|       - name: Generate changelog | ||||
|         run: | | ||||
|           VERSION_MINUS_V=${GITHUB_REF_NAME/#v/} | ||||
|           parse-changelog CHANGELOG.md $VERSION_MINUS_V > CHANGELOG-$GITHUB_REF_NAME.md | ||||
|       - uses: actions/setup-node@v3 | ||||
|         with: | ||||
|           node-version: 18 | ||||
|       - run: cd ui && npm ci | ||||
|       - run: cd ui && npm run build | ||||
|       - run: cd ui && npm run test | ||||
|       # Upload the UI and changelog as *job* artifacts (not *release* artifacts), used below. | ||||
|       - uses: actions/upload-artifact@v3 | ||||
|         with: | ||||
|           name: moonfire-nvr-ui-${{ github.ref_name }} | ||||
|           path: ui/build | ||||
|           if-no-files-found: error | ||||
|       - uses: actions/upload-artifact@v3 | ||||
|         with: | ||||
|           name: CHANGELOG-${{ github.ref_name }} | ||||
|           path: CHANGELOG-${{ github.ref_name }}.md | ||||
|           if-no-files-found: error | ||||
| 
 | ||||
|   cross: | ||||
|     needs: base # for bundled ui | ||||
|     strategy: | ||||
|       matrix: | ||||
|         include: | ||||
|         - target: x86_64-unknown-linux-musl | ||||
|         - target: aarch64-unknown-linux-musl | ||||
|         - target: armv7-unknown-linux-musleabihf | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - name: Checkout | ||||
|         uses: actions/checkout@v4 | ||||
|       - name: Download UI | ||||
|         uses: actions/download-artifact@v3 | ||||
|         with: | ||||
|           name: moonfire-nvr-ui-${{ github.ref_name }} | ||||
|           path: ui/build | ||||
| 
 | ||||
|       # actions-rust-cross doesn't actually use cross for x86_64. | ||||
|       # Install the needed musl-tools in the host. | ||||
|       - name: Install musl-tools | ||||
|         run: sudo apt-get --option=APT::Acquire::Retries=3 update && sudo apt-get --option=APT::Acquire::Retries=3 install musl-tools | ||||
|         if: matrix.target == 'x86_64-unknown-linux-musl' | ||||
|       - name: Build | ||||
|         uses: houseabsolute/actions-rust-cross@v0 | ||||
|         env: | ||||
|           # (Required) GitHub token for creating GitHub Releases. | ||||
|           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||||
|           UI_BUILD_DIR: ../ui/build | ||||
| 
 | ||||
|           # cross doesn't install `git` within its Docker container, so plumb | ||||
|           # the version through rather than try `git describe` from `build.rs`. | ||||
|           VERSION: ${{ github.ref_name }} | ||||
|         with: | ||||
|           working-directory: server | ||||
|           target: ${{ matrix.target }} | ||||
|           command: build | ||||
|           args: --release --features bundled | ||||
|       # Upload as a *job* artifact (not *release* artifact), used below. | ||||
|       - name: Upload | ||||
|         uses: actions/upload-artifact@v3 | ||||
|         with: | ||||
|           name: moonfire-nvr-${{ github.ref_name }}-${{ matrix.target }} | ||||
|           path: server/target/${{ matrix.target }}/release/moonfire-nvr | ||||
|           if-no-files-found: error | ||||
| 
 | ||||
|   release: | ||||
|     needs: [ base, cross ] | ||||
|     runs-on: ubuntu-latest | ||||
|     permissions: | ||||
|       contents: write | ||||
|     steps: | ||||
|       - uses: actions/download-artifact@v3 | ||||
|         with: | ||||
|           path: artifacts | ||||
|       - name: ls before rearranging | ||||
|         run: find . -ls | ||||
|       - name: Rearrange | ||||
|         run: | | ||||
|           (cd artifacts/moonfire-nvr-ui-${GITHUB_REF_NAME} && zip -r ../../moonfire-nvr-ui-${GITHUB_REF_NAME}.zip .) | ||||
|           (cd artifacts; for i in moonfire-nvr-*/moonfire-nvr; do mv $i "../$(dirname $i)"; done) | ||||
|       - name: ls after rearranging | ||||
|         run: find . -ls | ||||
|       - name: Create GitHub release | ||||
|         uses: softprops/action-gh-release@v1 | ||||
|         with: | ||||
|           body_path: artifacts/CHANGELOG-${{ github.ref_name }}/CHANGELOG-${{ github.ref_name }}.md | ||||
|           files: | | ||||
|             moonfire-nvr-* | ||||
|  | ||||
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -1,4 +1,5 @@ | ||||
| .DS_Store | ||||
| *.swp | ||||
| /release-* | ||||
| /server/target | ||||
| .idea | ||||
|  | ||||
							
								
								
									
										49
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										49
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @ -1,17 +1,22 @@ | ||||
| # Moonfire NVR change log | ||||
| 
 | ||||
| Below are some highlights in each release. For a full description of all | ||||
| changes, see Git history. | ||||
| 
 | ||||
| Each release is tagged in Git and on the Docker repository | ||||
| [`scottlamb/moonfire-nvr`](https://hub.docker.com/r/scottlamb/moonfire-nvr). | ||||
| changes, see Git history. Each release is tagged in git. | ||||
| 
 | ||||
| Backwards-incompatible database schema changes happen on on major version | ||||
| upgrades, e.g. `0.6.x` -> `0.7.x`. The config file format and | ||||
| upgrades, e.g. `v0.6.x` -> `v0.7.x`. The config file format and | ||||
| [API](ref/api.md) currently have no stability guarantees, so they may change | ||||
| even on minor releases, e.g. `0.7.5` -> `0.7.6`. | ||||
| even on minor releases, e.g. `v0.7.5` -> `v0.7.6`. | ||||
| 
 | ||||
| ## 0.7.7 (2023-08-03) | ||||
| ## v0.7.8 (2023-10-18) | ||||
| 
 | ||||
| *  release as self-contained Linux binaries (for `x86_64`, `aarch64`, and | ||||
|    `armv8` architectures) rather than Docker images. This minimizes hassle and | ||||
|    total download size. Along the way, we switched libc to from `glibc` to | ||||
|    `musl` in the process. Please report any problems with the build or | ||||
|    instructions! | ||||
| 
 | ||||
| ## v0.7.7 (2023-08-03) | ||||
| 
 | ||||
| *  fix [#289](https://github.com/scottlamb/moonfire-nvr/issues/289): crash on | ||||
|    pressing the `Add` button in the sample file directory dialog | ||||
| @ -19,7 +24,7 @@ even on minor releases, e.g. `0.7.5` -> `0.7.6`. | ||||
| *  experimental (off by default) support for bundling UI files into the | ||||
|    executable. | ||||
| 
 | ||||
| ## 0.7.6 (2023-07-08) | ||||
| ## v0.7.6 (2023-07-08) | ||||
| 
 | ||||
| *   new log formats using `tracing`. This will allow richer context information. | ||||
| *   bump minimum Rust version to 1.70. | ||||
| @ -53,7 +58,7 @@ even on minor releases, e.g. `0.7.5` -> `0.7.6`. | ||||
| *   improvements to `moonfire-nvr config`, | ||||
|     thanks to [@sky1e](https://github.com/sky1e). | ||||
| 
 | ||||
| ## 0.7.5 (2022-05-09) | ||||
| ## v0.7.5 (2022-05-09) | ||||
| 
 | ||||
| *   [#219](https://github.com/scottlamb/moonfire-nvr/issues/219): fix | ||||
|     live stream failing with `ws close: 1006` on URLs with port numbers. | ||||
| @ -63,7 +68,7 @@ even on minor releases, e.g. `0.7.5` -> `0.7.6`. | ||||
|     Retina 0.3.10, improving compatibility with OMNY M5S2A 2812 cameras that | ||||
|     send invalid `rtptime` values. | ||||
| 
 | ||||
| ## 0.7.4 (2022-04-13) | ||||
| ## v0.7.4 (2022-04-13) | ||||
| 
 | ||||
| *   upgrade to Retina 0.3.9, improving camera interop and diagnostics. | ||||
|     Fixes [#213](https://github.com/scottlamb/moonfire-nvr/issues/213), | ||||
| @ -74,13 +79,13 @@ even on minor releases, e.g. `0.7.5` -> `0.7.6`. | ||||
| *   [#206](https://github.com/scottlamb/moonfire-nvr/issues/206#issuecomment-1086442543): | ||||
|     fix `teardown Sender shouldn't be dropped: RecvError(())` errors on shutdown. | ||||
| 
 | ||||
| ## 0.7.3 (2022-03-22) | ||||
| ## v0.7.3 (2022-03-22) | ||||
| 
 | ||||
| *   security fix: check the `Origin` header on live stream WebSocket requests | ||||
|     to avoid cross-site WebSocket hijacking (CSWSH). | ||||
| *   RTSP connections always use the Retina library rather than FFmpeg. | ||||
| 
 | ||||
| ## 0.7.2 (2022-03-16) | ||||
| ## v0.7.2 (2022-03-16) | ||||
| 
 | ||||
| *   introduce a configuration file `/etc/moonfire-nvr.toml`; you will need | ||||
|     to create one when upgrading. | ||||
| @ -97,13 +102,13 @@ even on minor releases, e.g. `0.7.5` -> `0.7.6`. | ||||
| *   progress on [#70](https://github.com/scottlamb/moonfire-nvr/issues/184): | ||||
|     shrink the binary from 154 MiB to 70 MiB by reducing debugging information. | ||||
| 
 | ||||
| ## 0.7.1 (2021-10-27) | ||||
| ## v0.7.1 (2021-10-27) | ||||
| 
 | ||||
| *   bugfix: editing a camera from `nvr config` would erroneously clear the | ||||
|     sample file directory associated with its streams. | ||||
| *   RTSP transport (TCP or UDP) can be set per-stream from `nvr config`. | ||||
| 
 | ||||
| ## 0.7.0 (2021-10-27) | ||||
| ## v0.7.0 (2021-10-27) | ||||
| 
 | ||||
| *   [schema version 7](guide/schema.md#version-7) | ||||
| *   Changes to the [API](guide/api.md): | ||||
| @ -130,7 +135,7 @@ even on minor releases, e.g. `0.7.5` -> `0.7.6`. | ||||
|             currently may be either absent or the string `record`. | ||||
|     *   Added `POST /api/users/<id>` for altering a user's UI preferences. | ||||
| 
 | ||||
| ## 0.6.7 (2021-10-20) | ||||
| ## v0.6.7 (2021-10-20) | ||||
| 
 | ||||
| *   trim whitespace when detecting time zone by reading `/etc/timezone`. | ||||
| *   (Retina 0.3.2) better `TEARDOWN` handling with the default | ||||
| @ -142,7 +147,7 @@ even on minor releases, e.g. `0.7.5` -> `0.7.6`. | ||||
|     `--rtsp-library=retina` (see | ||||
|     [scottlamb/retina#25](https://github.com/scottlamb/retina/25)). | ||||
| 
 | ||||
| ## 0.6.6 (2021-09-23) | ||||
| ## v0.6.6 (2021-09-23) | ||||
| 
 | ||||
| *   fix [#146](https://github.com/scottlamb/moonfire-nvr/issues/146): "init | ||||
|     segment fetch error" when browsers have cached data from `v0.6.4` and | ||||
| @ -167,7 +172,7 @@ even on minor releases, e.g. `0.7.5` -> `0.7.6`. | ||||
|     impatient to get fast results with ctrl-C when running interactively, rather | ||||
|     than having to use `SIGKILL` from another terminal. | ||||
| 
 | ||||
| ## 0.6.5 (2021-08-13) | ||||
| ## v0.6.5 (2021-08-13) | ||||
| 
 | ||||
| *   UI: improve video aspect ratio handling. Live streams formerly worked | ||||
|     around a Firefox pixel aspect ratio bug by forcing all videos to 16:9, which | ||||
| @ -181,7 +186,7 @@ even on minor releases, e.g. `0.7.5` -> `0.7.6`. | ||||
|     `GET_PARAMETERS` as a RTSP keepalive. GW Security cameras would ignored | ||||
|     the latter, causing Moonfire NVR to drop the connection every minute. | ||||
| 
 | ||||
| ## 0.6.4 (2021-06-28) | ||||
| ## v0.6.4 (2021-06-28) | ||||
| 
 | ||||
| *   Default to a new pure-Rust RTSP library, `retina`. If you hit problems, you | ||||
|     can switch back via `--rtsp-library=ffmpeg`. Please report a bug if this | ||||
| @ -189,7 +194,7 @@ even on minor releases, e.g. `0.7.5` -> `0.7.6`. | ||||
| *   Correct the pixel aspect ratio of 9:16 sub streams (eg a standard 16x9 | ||||
|     camera rotated 90 degrees) in the same way as 16:9 sub streams. | ||||
| 
 | ||||
| ## 0.6.3 (2021-03-31) | ||||
| ## v0.6.3 (2021-03-31) | ||||
| 
 | ||||
| *   New user interface! Besides a more modern appearance, it has better | ||||
|     error handling and an experimental live view UI. | ||||
| @ -199,7 +204,7 @@ even on minor releases, e.g. `0.7.5` -> `0.7.6`. | ||||
|     not calculated properly there might be unexpected gaps or overlaps in | ||||
|     playback. | ||||
| 
 | ||||
| ## 0.6.2 (2021-03-12) | ||||
| ## v0.6.2 (2021-03-12) | ||||
| 
 | ||||
| *   Fix panics when a stream's PTS has extreme jumps | ||||
|     ([#113](https://github.com/scottlamb/moonfire-nvr/issues/113)) | ||||
| @ -209,7 +214,7 @@ even on minor releases, e.g. `0.7.5` -> `0.7.6`. | ||||
|     `moonfire-nvr check --delete-orphan-rows` command from actually deleting | ||||
|     rows. | ||||
| 
 | ||||
| ## 0.6.1 (2021-02-16) | ||||
| ## v0.6.1 (2021-02-16) | ||||
| 
 | ||||
| *   Improve the server's error messages on the console and in logs. | ||||
| *   Switch the UI build from the `yarn` package manager to `npm`. | ||||
| @ -221,7 +226,7 @@ even on minor releases, e.g. `0.7.5` -> `0.7.6`. | ||||
| *   Fix mangled favicons | ||||
|     ([#105](https://github.com/scottlamb/moonfire-nvr/issues/105)) | ||||
| 
 | ||||
| ## 0.6.0 (2021-01-22) | ||||
| ## v0.6.0 (2021-01-22) | ||||
| 
 | ||||
| This is the first tagged version and first Docker image release. I chose the | ||||
| version number 0.6.0 to match the current schema version 6. | ||||
|  | ||||
| @ -1,75 +0,0 @@ | ||||
| # syntax=docker/dockerfile:1.2.1 | ||||
| # This file is part of Moonfire NVR, a security camera network video recorder. | ||||
| # Copyright (C) 2021 The Moonfire NVR Authors; see AUTHORS and LICENSE.txt. | ||||
| # SPDX-License-Identifier: GPL-v3.0-or-later WITH GPL-3.0-linking-exception. | ||||
| 
 | ||||
| # See documentation here: | ||||
| # https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/reference.md | ||||
| 
 | ||||
| # "dev-common" is the portion of "dev" (see below) which isn't specific to the | ||||
| # target arch. It's sufficient for building the non-arch-specific webpack. | ||||
| FROM --platform=$BUILDPLATFORM ubuntu:20.04 AS dev-common | ||||
| LABEL maintainer="slamb@slamb.org" | ||||
| ARG BUILD_UID=1000 | ||||
| ARG BUILD_GID=1000 | ||||
| ARG INVALIDATE_CACHE_DEV_COMMON= | ||||
| ENV LC_ALL=C.UTF-8 | ||||
| COPY docker/dev-common.bash / | ||||
| RUN --mount=type=cache,id=var-cache-apt,target=/var/cache/apt,sharing=locked \ | ||||
|     /dev-common.bash | ||||
| CMD [ "/bin/bash", "--login" ] | ||||
| 
 | ||||
| # "dev" is a full development environment, suitable for shelling into or | ||||
| # using with the VS Code container plugin. | ||||
| FROM --platform=$BUILDPLATFORM dev-common AS dev | ||||
| LABEL maintainer="slamb@slamb.org" | ||||
| ARG BUILDARCH | ||||
| ARG TARGETARCH | ||||
| ARG INVALIDATE_CACHE_DEV= | ||||
| COPY docker/dev.bash / | ||||
| RUN --mount=type=cache,id=var-cache-apt,target=/var/cache/apt,sharing=locked \ | ||||
|     /dev.bash | ||||
| USER moonfire-nvr:moonfire-nvr | ||||
| WORKDIR /var/lib/moonfire-nvr | ||||
| 
 | ||||
| # Build the UI with node_modules and ui-dist outside the src dir. | ||||
| FROM --platform=$BUILDPLATFORM dev-common AS build-ui | ||||
| ARG INVALIDATE_CACHE_BUILD_UI= | ||||
| LABEL maintainer="slamb@slamb.org" | ||||
| WORKDIR /var/lib/moonfire-nvr/src/ui | ||||
| COPY docker/build-ui.bash / | ||||
| COPY ui /var/lib/moonfire-nvr/src/ui | ||||
| RUN --mount=type=tmpfs,target=/var/lib/moonfire-nvr/src/ui/node_modules \ | ||||
|     /build-ui.bash | ||||
| 
 | ||||
| # Build the Rust components. Note that dev.sh set up an environment variable | ||||
| # in .buildrc that similarly changes the target dir path. | ||||
| FROM --platform=$BUILDPLATFORM dev AS build-server | ||||
| LABEL maintainer="slamb@slamb.org" | ||||
| ARG INVALIDATE_CACHE_BUILD_SERVER= | ||||
| COPY docker/build-server.bash / | ||||
| COPY --from=build-ui /var/lib/moonfire-nvr/src/ui/build /var/lib/moonfire-nvr/src/ui/build | ||||
| RUN --mount=type=cache,id=target,target=/var/lib/moonfire-nvr/target,sharing=locked,mode=777 \ | ||||
|     --mount=type=cache,id=cargo,target=/cargo-cache,sharing=locked,mode=777 \ | ||||
|     --mount=type=bind,source=server,target=/var/lib/moonfire-nvr/src/server,readonly \ | ||||
|     /build-server.bash | ||||
| 
 | ||||
| # Deployment environment, now in the target platform. | ||||
| FROM --platform=$TARGETPLATFORM ubuntu:20.04 AS deploy | ||||
| LABEL maintainer="slamb@slamb.org" | ||||
| ARG INVALIDATE_CACHE_BUILD_DEPLOY= | ||||
| ENV LC_ALL=C.UTF-8 | ||||
| COPY docker/deploy.bash / | ||||
| RUN --mount=type=cache,id=var-cache-apt,target=/var/cache/apt,sharing=locked \ | ||||
|     /deploy.bash | ||||
| COPY --from=dev-common /docker-build-debug/dev-common/ /docker-build-debug/dev-common/ | ||||
| COPY --from=dev /docker-build-debug/dev/ /docker-build-debug/dev/ | ||||
| COPY --from=build-server /docker-build-debug/build-server/ /docker-build-debug/build-server/ | ||||
| COPY --from=build-server /usr/local/bin/moonfire-nvr /usr/local/bin/moonfire-nvr | ||||
| COPY --from=build-ui /docker-build-debug/build-ui /docker-build-debug/build-ui | ||||
| 
 | ||||
| # The install instructions say to use --user in the docker run commandline. | ||||
| # Specify a non-root user just in case someone forgets. | ||||
| USER 10000:10000 | ||||
| WORKDIR /var/lib/moonfire-nvr | ||||
| ENTRYPOINT [ "/usr/local/bin/moonfire-nvr" ] | ||||
| @ -1,37 +0,0 @@ | ||||
| #!/bin/bash | ||||
| # This file is part of Moonfire NVR, a security camera network video recorder. | ||||
| # Copyright (C) 2021 The Moonfire NVR Authors; see AUTHORS and LICENSE.txt. | ||||
| # SPDX-License-Identifier: GPL-v3.0-or-later WITH GPL-3.0-linking-exception. | ||||
| 
 | ||||
| # Build the "build-server" target. See Dockerfile. | ||||
| 
 | ||||
| set -o errexit | ||||
| set -o pipefail | ||||
| set -o xtrace | ||||
| 
 | ||||
| mkdir /docker-build-debug/build-server | ||||
| exec > >(tee -i /docker-build-debug/build-server/output) 2>&1 | ||||
| date | ||||
| uname -a | ||||
| find /cargo-cache -ls > /docker-build-debug/build-server/cargo-cache-before | ||||
| find ~/target -ls > /docker-build-debug/build-server/target-before | ||||
| 
 | ||||
| source ~/.buildrc | ||||
| 
 | ||||
| # The "mode" argument to cache mounts doesn't seem to work reliably | ||||
| # (as of Docker version 20.10.5, build 55c4c88, using a docker-container | ||||
| # builder), thus the chmod command. | ||||
| sudo chmod 777 /cargo-cache /var/lib/moonfire-nvr/target | ||||
| mkdir -p /cargo-cache/{git,registry} | ||||
| ln -s /cargo-cache/{git,registry} ~/.cargo | ||||
| 
 | ||||
| build_profile=release-lto | ||||
| cd src/server | ||||
| time cargo test --features=bundled-ui | ||||
| time cargo build --features=bundled-ui --profile=$build_profile | ||||
| find /cargo-cache -ls > /docker-build-debug/build-server/cargo-cache-after | ||||
| find ~/target -ls > /docker-build-debug/build-server/target-after | ||||
| sudo install -m 755 \ | ||||
|     ~/platform-target/$build_profile/moonfire-nvr \ | ||||
|     /usr/local/bin/moonfire-nvr | ||||
| date | ||||
| @ -1,24 +0,0 @@ | ||||
| #!/bin/bash | ||||
| # This file is part of Moonfire NVR, a security camera network video recorder. | ||||
| # Copyright (C) 2021 The Moonfire NVR Authors; see AUTHORS and LICENSE.txt. | ||||
| # SPDX-License-Identifier: GPL-v3.0-or-later WITH GPL-3.0-linking-exception. | ||||
| 
 | ||||
| # Build the "build-ui" target. See Dockerfile. | ||||
| 
 | ||||
| set -o errexit | ||||
| set -o pipefail | ||||
| set -o xtrace | ||||
| 
 | ||||
| mkdir /docker-build-debug/build-ui | ||||
| exec > >(tee -i /docker-build-debug/build-ui/output) 2>&1 | ||||
| 
 | ||||
| date | ||||
| uname -a | ||||
| node --version | ||||
| npm --version | ||||
| time npm ci | ||||
| time npm run build | ||||
| 
 | ||||
| find /var/lib/moonfire-nvr/src/ui/node_modules -ls \ | ||||
|     > /docker-build-debug/build-ui/node_modules-after | ||||
| date | ||||
| @ -1,32 +0,0 @@ | ||||
| #!/bin/bash | ||||
| # This file is part of Moonfire NVR, a security camera network video recorder. | ||||
| # Copyright (C) 2021 The Moonfire NVR Authors; see AUTHORS and LICENSE.txt. | ||||
| # SPDX-License-Identifier: GPL-v3.0-or-later WITH GPL-3.0-linking-exception. | ||||
| 
 | ||||
| # Build the "deploy" target. See Dockerfile. | ||||
| 
 | ||||
| set -o errexit | ||||
| set -o pipefail | ||||
| set -o xtrace | ||||
| 
 | ||||
| mkdir -p /docker-build-debug/deploy | ||||
| exec > >(tee -i /docker-build-debug/deploy/output) 2>&1 | ||||
| find /var/cache/apt -ls > /docker-build-debug/deploy/var-cache-apt-before | ||||
| 
 | ||||
| date | ||||
| uname -a | ||||
| export DEBIAN_FRONTEND=noninteractive | ||||
| time apt-get update | ||||
| time apt-get install --assume-yes --no-install-recommends \ | ||||
|     libncurses6 \ | ||||
|     libncursesw6 \ | ||||
|     locales \ | ||||
|     sudo \ | ||||
|     sqlite3 \ | ||||
|     tzdata \ | ||||
|     vim-nox | ||||
| rm -rf /var/lib/apt/lists/* | ||||
| ln -s moonfire-nvr /usr/local/bin/nvr | ||||
| 
 | ||||
| find /var/cache/apt -ls > /docker-build-debug/deploy/var-cache-apt-after | ||||
| date | ||||
| @ -1,82 +0,0 @@ | ||||
| #!/bin/bash | ||||
| # This file is part of Moonfire NVR, a security camera network video recorder. | ||||
| # Copyright (C) 2021 The Moonfire NVR Authors; see AUTHORS and LICENSE.txt. | ||||
| # SPDX-License-Identifier: GPL-v3.0-or-later WITH GPL-3.0-linking-exception. | ||||
| 
 | ||||
| # Build the "dev" target. See Dockerfile. | ||||
| 
 | ||||
| set -o errexit | ||||
| set -o pipefail | ||||
| set -o xtrace | ||||
| 
 | ||||
| mkdir --mode=1777 /docker-build-debug | ||||
| mkdir /docker-build-debug/dev-common | ||||
| exec > >(tee -i /docker-build-debug/dev-common/output) 2>&1 | ||||
| 
 | ||||
| date | ||||
| uname -a | ||||
| find /var/cache/apt -ls > /docker-build-debug/dev-common/var-cache-apt-before | ||||
| 
 | ||||
| export DEBIAN_FRONTEND=noninteractive | ||||
| 
 | ||||
| # This file cleans apt caches after every invocation. Instead, we use a | ||||
| # buildkit cachemount to avoid putting them in the image while still allowing | ||||
| # some reuse. | ||||
| rm /etc/apt/apt.conf.d/docker-clean | ||||
| 
 | ||||
| packages=() | ||||
| 
 | ||||
| # Install all packages necessary for building (and some for testing/debugging). | ||||
| packages+=( | ||||
|     build-essential | ||||
|     curl | ||||
|     pkgconf | ||||
|     locales | ||||
|     sudo | ||||
|     sqlite3 | ||||
|     tzdata | ||||
|     vim-nox | ||||
| ) | ||||
| time apt-get update | ||||
| time apt-get install --assume-yes --no-install-recommends "${packages[@]}" | ||||
| 
 | ||||
| # Install a more recent nodejs/npm than in the universe repository. | ||||
| time curl -sL https://deb.nodesource.com/setup_14.x | bash - | ||||
| time apt-get install nodejs | ||||
| 
 | ||||
| # Create the user. On the dev environment, allow sudo. | ||||
| groupadd \ | ||||
|     --gid="${BUILD_GID}" \ | ||||
|     moonfire-nvr | ||||
| useradd \ | ||||
|     --no-log-init \ | ||||
|     --home-dir=/var/lib/moonfire-nvr \ | ||||
|     --uid="${BUILD_UID}" \ | ||||
|     --gid=moonfire-nvr \ | ||||
|     --shell=/bin/bash \ | ||||
|     --create-home \ | ||||
|     moonfire-nvr | ||||
| echo 'moonfire-nvr ALL=(ALL) NOPASSWD: ALL' >>/etc/sudoers | ||||
| 
 | ||||
| # Install Rust. Note curl was already installed for yarn above. | ||||
| time su moonfire-nvr -lc " | ||||
|     curl --proto =https --tlsv1.2 -sSf https://sh.rustup.rs | | ||||
|     sh -s - -y" | ||||
| 
 | ||||
| # Put configuration for the Rust build into a new ".buildrc" which is used | ||||
| # both (1) interactively from ~/.bashrc when logging into the dev container | ||||
| # and (2) from a build-server RUN command. In particular, the latter can't | ||||
| # use ~/.bashrc because that script immediately exits when run from a | ||||
| # non-interactive shell. | ||||
| echo 'source $HOME/.buildrc' >> /var/lib/moonfire-nvr/.bashrc | ||||
| cat >> /var/lib/moonfire-nvr/.buildrc <<EOF | ||||
| source \$HOME/.cargo/env | ||||
| 
 | ||||
| # Set the target directory to be outside the src bind mount. | ||||
| # https://doc.rust-lang.org/cargo/reference/config.html#buildtarget-dir | ||||
| export CARGO_BUILD_TARGET_DIR=/var/lib/moonfire-nvr/target | ||||
| EOF | ||||
| chown moonfire-nvr:moonfire-nvr /var/lib/moonfire-nvr/.buildrc | ||||
| 
 | ||||
| find /var/cache/apt -ls > /docker-build-debug/dev-common/var-cache-apt-after | ||||
| date | ||||
							
								
								
									
										122
									
								
								docker/dev.bash
									
									
									
									
									
								
							
							
						
						
									
										122
									
								
								docker/dev.bash
									
									
									
									
									
								
							| @ -1,122 +0,0 @@ | ||||
| #!/bin/bash | ||||
| # This file is part of Moonfire NVR, a security camera network video recorder. | ||||
| # Copyright (C) 2021 The Moonfire NVR Authors; see AUTHORS and LICENSE.txt. | ||||
| # SPDX-License-Identifier: GPL-v3.0-or-later WITH GPL-3.0-linking-exception. | ||||
| 
 | ||||
| # Build the "dev" target. See Dockerfile. | ||||
| 
 | ||||
| set -o errexit | ||||
| set -o pipefail | ||||
| set -o xtrace | ||||
| 
 | ||||
| mkdir /docker-build-debug/dev | ||||
| exec > >(tee -i /docker-build-debug/dev/output) 2>&1 | ||||
| 
 | ||||
| date | ||||
| uname -a | ||||
| find /var/cache/apt -ls > /docker-build-debug/dev/var-cache-apt-before | ||||
| 
 | ||||
| export DEBIAN_FRONTEND=noninteractive | ||||
| 
 | ||||
| packages=() | ||||
| 
 | ||||
| if [[ "${BUILDARCH}" != "${TARGETARCH}" ]]; then | ||||
|     # Set up cross compilation. | ||||
|     case "${TARGETARCH}" in | ||||
|     arm64) | ||||
|       dpkg_arch=arm64 | ||||
|       gcc_target=aarch64-linux-gnu | ||||
|       rust_target=aarch64-unknown-linux-gnu | ||||
|       target_is_port=1 | ||||
|       ;; | ||||
|     arm) | ||||
|       dpkg_arch=armhf | ||||
|       gcc_target=arm-linux-gnueabihf | ||||
|       rust_target=arm-unknown-linux-gnueabihf | ||||
|       target_is_port=1 | ||||
|       ;; | ||||
|     amd64) | ||||
|       dpkg_arch=amd64 | ||||
|       gcc_target=x86_64-linux-gnu | ||||
|       rust_target=x86_64-unknown-linux-gnu | ||||
|       target_is_port=0 | ||||
|       ;; | ||||
|     *) | ||||
|       echo "Unsupported cross-compile target ${TARGETARCH}." >&2 | ||||
|       exit 1 | ||||
|     esac | ||||
|     apt_target_suffix=":${dpkg_arch}" | ||||
|     case "${BUILDARCH}" in | ||||
|     amd64|386) host_is_port=0 ;; | ||||
|     *) host_is_port=1 ;; | ||||
|     esac | ||||
| 
 | ||||
|     time dpkg --add-architecture "${dpkg_arch}" | ||||
| 
 | ||||
|     if [[ $target_is_port -ne $host_is_port ]]; then | ||||
|         # Ubuntu stores non-x86 architectures at a different URL, so futz the | ||||
|         # sources file to allow installing both host and target. | ||||
|         # See https://github.com/rust-embedded/cross/blob/master/docker/common.sh | ||||
|         perl -pi.bak -e ' | ||||
|             s{^deb (http://.*.ubuntu.com/ubuntu/) (.*)} | ||||
|              {deb [arch=amd64,i386] \1 \2\ndeb [arch-=amd64,i386] http://ports.ubuntu.com/ubuntu-ports \2}; | ||||
|             s{^deb (http://ports.ubuntu.com/ubuntu-ports/) (.*)} | ||||
|              {deb [arch=amd64,i386] http://archive.ubuntu.com/ubuntu \2\ndeb [arch-=amd64,i386] \1 \2}' \ | ||||
|             /etc/apt/sources.list | ||||
|         cat /etc/apt/sources.list | ||||
|     fi | ||||
| 
 | ||||
|     packages+=( | ||||
|         g++-${gcc_target/_/-} | ||||
|         libc6-dev-${dpkg_arch}-cross | ||||
|         qemu-user | ||||
|     ) | ||||
| fi | ||||
| 
 | ||||
| time apt-get update | ||||
| 
 | ||||
| # Install the packages for the target architecture. | ||||
| packages+=( | ||||
|     libncurses-dev"${apt_target_suffix}" | ||||
|     libsqlite3-dev"${apt_target_suffix}" | ||||
| ) | ||||
| time apt-get update | ||||
| time apt-get install --assume-yes --no-install-recommends "${packages[@]}" | ||||
| 
 | ||||
| # Set environment variables for cross-compiling. | ||||
| # Also set up a symlink that points to the output platform's target dir, because | ||||
| # the target directory layout varies when cross-compiling, as described here: | ||||
| # https://doc.rust-lang.org/cargo/guide/build-cache.html | ||||
| if [[ -n "${rust_target}" ]]; then | ||||
|     su moonfire-nvr -lc "rustup target install ${rust_target} && | ||||
|                          ln -s target/${rust_target} platform-target" | ||||
|     underscore_rust_target="${rust_target//-/_}" | ||||
|     uppercase_underscore_rust_target="${underscore_rust_target^^}" | ||||
|     cat >> /var/lib/moonfire-nvr/.buildrc <<EOF | ||||
| 
 | ||||
| # https://doc.rust-lang.org/cargo/reference/config.html | ||||
| export CARGO_BUILD_TARGET=${rust_target} | ||||
| export CARGO_TARGET_${uppercase_underscore_rust_target}_LINKER=${gcc_target}-gcc | ||||
| 
 | ||||
| # Use a pkg-config wrapper for the target architecture. This wrapper was | ||||
| # automatically created on "dpkg --add-architecture"; see | ||||
| # /etc/dpkg/dpkg.cfg.d/pkgconf-hook-config. | ||||
| # | ||||
| # https://github.com/rust-lang/pkg-config-rs uses the "PKG_CONFIG" | ||||
| # variable to to select the pkg-config binary to use. As of pkg-config 0.3.19, | ||||
| # it unfortunately doesn't understand the <target>_ prefix that the README.md | ||||
| # describes for other vars. Fortunately Moonfire NVR doesn't have any host tools | ||||
| # that need pkg-config. | ||||
| export PKG_CONFIG=${gcc_target}-pkg-config | ||||
| 
 | ||||
| # https://github.com/alexcrichton/cc-rs uses these variables to decide what | ||||
| # compiler to invoke. | ||||
| export CC_${underscore_rust_target}=${gcc_target}-gcc | ||||
| export CXX_${underscore_rust_target}=${gcc_target}-g++ | ||||
| EOF | ||||
| else | ||||
|     su moonfire-nvr -lc "ln -s target platform-target" | ||||
| fi | ||||
| 
 | ||||
| find /var/cache/apt -ls > /docker-build-debug/dev/var-cache-apt-after | ||||
| date | ||||
							
								
								
									
										239
									
								
								guide/build.md
									
									
									
									
									
								
							
							
						
						
									
										239
									
								
								guide/build.md
									
									
									
									
									
								
							| @ -2,7 +2,7 @@ | ||||
| 
 | ||||
| This document has notes for software developers on building Moonfire NVR from | ||||
| source code for development. If you just want to install precompiled | ||||
| binaries, see the [Docker installation instructions](install.md) instead. | ||||
| binaries, see the [installation instructions](install.md) instead. | ||||
| 
 | ||||
| This document doesn't spell out as many details as the installation | ||||
| instructions. Please ask on Moonfire NVR's [issue | ||||
| @ -11,11 +11,9 @@ tracker](https://github.com/scottlamb/moonfire-nvr/issues) or | ||||
| stuck. Please also send pull requests to improve this doc. | ||||
| 
 | ||||
| * [Downloading](#downloading) | ||||
| * [Docker builds](#docker-builds) | ||||
|     * [Release procedure](#release-procedure) | ||||
| * [Non-Docker setup](#non-docker-setup) | ||||
| * [Building](#building) | ||||
|     * [Running interactively straight from the working copy](#running-interactively-straight-from-the-working-copy) | ||||
|     * [Running as a `systemd` service](#running-as-a-systemd-service) | ||||
| * [Release procedure](#release-procedure) | ||||
| 
 | ||||
| ## Downloading | ||||
| 
 | ||||
| @ -28,152 +26,16 @@ $ git clone https://github.com/scottlamb/moonfire-nvr.git | ||||
| $ cd moonfire-nvr | ||||
| ``` | ||||
| 
 | ||||
| ## Docker builds | ||||
| ## Building | ||||
| 
 | ||||
| This command should prepare a deployment image for your local machine: | ||||
| 
 | ||||
| ```console | ||||
| $ sudo docker buildx build --load --tag=moonfire-nvr -f docker/Dockerfile . | ||||
| ``` | ||||
| 
 | ||||
| <details> | ||||
|   <summary>Common errors</summary> | ||||
| 
 | ||||
| *   `docker: 'buildx' is not a docker command.`: You shouldn't see this with | ||||
|     Docker 20.10. With Docker version 19.03 you'll need to prepend | ||||
|     `DOCKER_CLI_EXPERIMENTAL=enabled` to `docker buildx build` commands. If | ||||
|     your Docker version is older than 19.03, you'll need to upgrade. | ||||
| *   `At least one invalid signature was encountered.`: this is likely | ||||
|     due to an error in `libseccomp`, as described [in this askubuntu.com answer](https://askubuntu.com/a/1264921/1365248). | ||||
|     Try running in a privileged builder. As described in [`docker buildx build` documentation](https://docs.docker.com/engine/reference/commandline/buildx_build/#allow), | ||||
|     run this command once: | ||||
|     ```console | ||||
|     $ sudo docker buildx create --use --name insecure-builder --buildkitd-flags '--allow-insecure-entitlement security.insecure' | ||||
|     ``` | ||||
|     then add `--allow security.insecure` to your `docker buildx build` commandlines. | ||||
| </details> | ||||
| 
 | ||||
| If you want to iterate on code changes, doing a full Docker build from | ||||
| scratch every time will be painfully slow. You will likely find it more | ||||
| helpful to use the `dev` target. This is a self-contained developer environment | ||||
| which you can use from its shell via `docker run` or via something like | ||||
| Visual Studio Code's Docker plugin. | ||||
| 
 | ||||
| ```console | ||||
| $ sudo docker buildx build \ | ||||
|         --load --tag=moonfire-dev --target=dev -f docker/Dockerfile . | ||||
| ... | ||||
| $ sudo docker run \ | ||||
|         --rm --interactive=true --tty \ | ||||
|         --mount=type=bind,source=$(pwd),destination=/var/lib/moonfire-nvr/src \ | ||||
|         moonfire-dev | ||||
| ``` | ||||
| 
 | ||||
| The development image overrides cargo's output directory to | ||||
| `/var/lib/moonfire-nvr/target`. (See `~moonfire-nvr/.buildrc`.) This avoids | ||||
| using a bind filesystem for build products, which can be slow on macOS. It | ||||
| also means that if you sometimes compile directly on the host and sometimes | ||||
| within Docker, they don't trip over each other's target directories. | ||||
| 
 | ||||
| You can also cross-compile to a different architecture. Adding a | ||||
| `--platform=linux/arm64/v8,linux/arm/v7,linux/amd64` argument will compile | ||||
| Moonfire NVR for all supported platforms. (Note: this has been used | ||||
| successfully for building on x86-64 and compiling to arm but not the | ||||
| reverse.) For the `dev` target, this prepares a build which executes on your | ||||
| local architecture and is capable of building a binary for your desired target | ||||
| architecture. | ||||
| 
 | ||||
| On the author's macOS machine with Docker desktop 3.0.4, building for | ||||
| multiple platforms at once will initially fail with the following error: | ||||
| 
 | ||||
| ```console | ||||
| $ sudo docker buildx build ... --platform=linux/arm64/v8,linux/arm/v7,linux/amd64 | ||||
| [+] Building 0.0s (0/0) | ||||
| error: multiple platforms feature is currently not supported for docker driver. Please switch to a different driver (eg. "docker buildx create --use") | ||||
| ``` | ||||
| 
 | ||||
| Running `docker buildx create --use` once solves this problem, with a couple | ||||
| caveats: | ||||
| 
 | ||||
| *   you'll need to specify an additional `--load` argument to make builds | ||||
|     available to run locally. | ||||
| *   the `--load` argument only works for one platform at a time. With multiple | ||||
|     platforms, it gives an error like the following: | ||||
|     ``` | ||||
|     error: failed to solve: rpc error: code = Unknown desc = docker exporter does not currently support exporting manifest lists | ||||
|     ``` | ||||
|     [A comment on docker/buildx issue | ||||
|     #59](https://github.com/docker/buildx/issues/59#issuecomment-667548900) | ||||
|     suggests a workaround of building all three then using caching to quickly | ||||
|     load the one of immediate interest: | ||||
|     ``` | ||||
|     $ sudo docker buildx build --platform=linux/arm64/v8,linux/arm/v7,linux/amd64 ... | ||||
|     $ sudo docker buildx build --load --platform=arm64/v8 ... | ||||
|     ``` | ||||
| 
 | ||||
| On Linux hosts (as opposed to when using Docker Desktop on macOS/Windows), | ||||
| you'll likely see errors like the ones below. The solution is to [install | ||||
| emulators](https://github.com/tonistiigi/binfmt#installing-emulators). | ||||
| You may need to reinstall emulators on each boot of the host. | ||||
| 
 | ||||
| ``` | ||||
| Exec format error | ||||
| 
 | ||||
| Error while loading /usr/sbin/dpkg-split: No such file or directory | ||||
| Error while loading /usr/sbin/dpkg-deb: No such file or directory | ||||
| ``` | ||||
| 
 | ||||
| Moonfire NVR's `Dockerfile` has some built-in debugging tools: | ||||
| 
 | ||||
| *   Each stage saves some debug info to `/docker-build-debug/<stage>`, and | ||||
|     the `deploy` stage preserves the output from previous stages. The debug | ||||
|     info includes: | ||||
|     *    output (stdout + stderr) from the build script, running long operations | ||||
|          through the `time` command. | ||||
|     *    `find -ls` output on cache mounts before and after. | ||||
| *   Each stage accepts a `INVALIDATE_CACHE_<stage>` argument. You can use eg | ||||
|     `--build-arg=INVALIDATE_CACHE_BUILD_SERVER=$(date +%s)` to force the | ||||
|     `build-server` stage to be rebuilt rather than use cached Docker layers. | ||||
| 
 | ||||
| ### Release procedure | ||||
| 
 | ||||
| Releases are currently a bit manual. From a completely clean git work tree, | ||||
| 
 | ||||
| 1.  manually verify the current commit is pushed to github's master branch and | ||||
|     has a green checkmark indicating CI passed. | ||||
| 2.  update version in `CHANGELOG.md`. | ||||
| 3.  run commands: | ||||
|     ```bash | ||||
|     VERSION=x.y.z | ||||
|     git commit -am "prepare version ${VERSION}" | ||||
|     git tag -a "v${VERSION}" -m "version ${VERSION}" | ||||
|     ./release.bash | ||||
|     git push | ||||
|     git push origin "v${VERSION}" | ||||
|     ``` | ||||
| 
 | ||||
| The `release.bash` script needs [`jq`](https://stedolan.github.io/jq/) | ||||
| installed to work. | ||||
| 
 | ||||
| ## Non-Docker setup | ||||
| 
 | ||||
| You may prefer building without Docker on the host. Moonfire NVR should run | ||||
| natively on any Unix-like system. It's been tested on Linux and macOS. | ||||
| (In theory [Windows Subsystem for | ||||
| Moonfire NVR should run natively on any Unix-like system. It's been tested on | ||||
| Linux, macOS, and FreeBSD. (In theory [Windows Subsystem for | ||||
| Linux](https://docs.microsoft.com/en-us/windows/wsl/about) should also work. | ||||
| Please speak up if you try it.) | ||||
| 
 | ||||
| On macOS systems native builds may be noticeably faster than using Docker's | ||||
| Linux VM and filesystem overlay. | ||||
| 
 | ||||
| To build the server, you will need the following C libraries installed: | ||||
| 
 | ||||
| *   [SQLite3](https://www.sqlite.org/), at least version 3.8.2. | ||||
|     (You can skip this if you compile with `--features=bundled` and | ||||
|     don't mind the `moonfire-nvr sql` command not working.) | ||||
| 
 | ||||
| *   [`ncursesw`](https://www.gnu.org/software/ncurses/), the UTF-8 version of | ||||
|     the `ncurses` library. | ||||
| To build the server, you will need [SQLite3](https://www.sqlite.org/). You | ||||
| can skip this if compiling with `--features=rusqlite/bundled` and don't | ||||
| mind the `moonfire-nvr sql` command not working. | ||||
| 
 | ||||
| To build the UI, you'll need a [nodejs](https://nodejs.org/en/download/) release | ||||
| in "Maintenance" or "LTS" status: currently v14, v16, or v18. | ||||
| @ -184,7 +46,6 @@ most non-Rust dependencies: | ||||
| ```console | ||||
| $ sudo apt-get install \ | ||||
|                build-essential \ | ||||
|                libncurses-dev \ | ||||
|                libsqlite3-dev \ | ||||
|                pkgconf \ | ||||
|                sqlite3 \ | ||||
| @ -253,72 +114,24 @@ $ nvr run | ||||
| with `cargo build` rather than `cargo build --release`, for a faster build | ||||
| cycle and slower performance.) | ||||
| 
 | ||||
| Note this `nvr` is a little different than the `nvr` shell script you create | ||||
| when following the [install instructions](install.md). With that shell wrapper, | ||||
| `nvr run` will create and run a detached Docker container with some extra | ||||
| arguments specified in the script. This `nvr run` will directly run from the | ||||
| terminal, with no extra arguments, until you abort with Ctrl-C. Likewise, | ||||
| some of the shell script's subcommands that wrap Docker (`start`, `stop`, and | ||||
| `logs`) have no parallel with this `nvr`. | ||||
| ## Release procedure | ||||
| 
 | ||||
| ### Running as a `systemd` service | ||||
| Releases are currently a bit manual. From a completely clean git work tree, | ||||
| 
 | ||||
| If you want to deploy a non-Docker build on Linux, you may want to use | ||||
| `systemd`. Create `/etc/systemd/system/moonfire-nvr.service`: | ||||
| 
 | ||||
| ```ini | ||||
| [Unit] | ||||
| Description=Moonfire NVR | ||||
| After=network-online.target | ||||
| 
 | ||||
| [Service] | ||||
| ExecStart=/usr/local/bin/moonfire-nvr run | ||||
| Environment=TZ=:/etc/localtime | ||||
| Environment=MOONFIRE_FORMAT=google-systemd | ||||
| Environment=MOONFIRE_LOG=info | ||||
| Environment=RUST_BACKTRACE=1 | ||||
| Type=simple | ||||
| User=moonfire-nvr | ||||
| Restart=on-failure | ||||
| CPUAccounting=true | ||||
| MemoryAccounting=true | ||||
| BlockIOAccounting=true | ||||
| 
 | ||||
| [Install] | ||||
| WantedBy=multi-user.target | ||||
| 1.  manually verify the current commit is pushed to github's master branch and | ||||
|     has a green checkmark indicating CI passed. | ||||
| 2.  update versions: | ||||
|     *   update `server/Cargo.toml` version by hand; run `cargo test --workspace` | ||||
|         to update `Cargo.lock`. | ||||
|     *   ensure `README.md` and `CHANGELOG.md` refer to the new version. | ||||
| 3.  run commands: | ||||
|     ```bash | ||||
|     VERSION=x.y.z | ||||
|     git commit -am "prepare version ${VERSION}" | ||||
|     git tag -a "v${VERSION}" -m "version ${VERSION}" | ||||
|     git push origin "v${VERSION}" | ||||
|     ``` | ||||
| 
 | ||||
| You'll also need a `/etc/moonfire-nvr.toml`: | ||||
| 
 | ||||
| ```toml | ||||
| [[binds]] | ||||
| ipv4 = "0.0.0.0:8080" | ||||
| allowUnauthenticatedPermissions = { viewVideo = true } | ||||
| 
 | ||||
| [[binds]] | ||||
| unix = "/var/lib/moonfire-nvr/sock" | ||||
| ownUidIsPrivileged = true | ||||
| ``` | ||||
| 
 | ||||
| Note this configuration is insecure. You can change that via replacing the | ||||
| `allowUnauthenticatedPermissions` here as described in [Securing Moonfire NVR | ||||
| and exposing it to the Internet](secure.md). | ||||
| 
 | ||||
| See [ref/config.md](../ref/config.md) for more about `/etc/moonfire-nvr.toml`. | ||||
| 
 | ||||
| Some handy commands: | ||||
| 
 | ||||
| ```console | ||||
| $ sudo systemctl daemon-reload                                  # reload configuration files | ||||
| $ sudo systemctl start moonfire-nvr                             # start the service now | ||||
| $ sudo systemctl stop moonfire-nvr                              # stop the service now (but don't wait for it finish stopping) | ||||
| $ sudo systemctl status moonfire-nvr                            # show if the service is running and the last few log lines | ||||
| $ sudo systemctl enable moonfire-nvr                            # start the service on boot | ||||
| $ sudo systemctl disable moonfire-nvr                           # don't start the service on boot | ||||
| $ sudo journalctl --unit=moonfire-nvr --since='-5 min' --follow # look at recent logs and await more | ||||
| ``` | ||||
| 
 | ||||
| See the [systemd](http://www.freedesktop.org/wiki/Software/systemd/) | ||||
| documentation for more information. The [manual | ||||
| pages](http://www.freedesktop.org/software/systemd/man/) for `systemd.service` | ||||
| and `systemctl` may be of particular interest. | ||||
| The rest should happen automatically—the tag push will fire off a GitHub | ||||
| Actions workflow which creates a release, cross-compiles statically compiled | ||||
| binaries for three different platforms, and uploads them to the release. | ||||
|  | ||||
							
								
								
									
										182
									
								
								guide/install.md
									
									
									
									
									
								
							
							
						
						
									
										182
									
								
								guide/install.md
									
									
									
									
									
								
							| @ -1,14 +1,14 @@ | ||||
| # Installing Moonfire NVR <!-- omit in toc --> | ||||
| 
 | ||||
| * [Downloading, installing, and configuring Moonfire NVR with Docker](#downloading-installing-and-configuring-moonfire-nvr-with-docker) | ||||
| * [Downloading, installing, and configuring Moonfire NVR](#downloading-installing-and-configuring-moonfire-nvr) | ||||
|     * [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 | ||||
| ## Downloading, installing, and configuring Moonfire NVR | ||||
| 
 | ||||
| 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 | ||||
| via the prebuilt Linux binaries available for x86-64, arm64, and arm. If you | ||||
| instead want to build Moonfire NVR yourself, see the [Build | ||||
| instructions](build.md). | ||||
| 
 | ||||
| @ -18,17 +18,16 @@ left, and pick the [latest tagged version](https://github.com/scottlamb/moonfire | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| Next, install [Docker](https://www.docker.com/) if you haven't already, | ||||
| and verify `sudo docker run --rm hello-world` works. | ||||
| Download the binary for your platform from the matching GitHub release. | ||||
| Install it as `/usr/local/bin/moonfire-nvr` and ensure it is executable, e.g. | ||||
| for version `v0.7.8` on Intel machines: | ||||
| 
 | ||||
| <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> | ||||
| ```console | ||||
| $ VERSION=v0.7.8 | ||||
| $ ARCH=x86_64-unknown-linux-musl | ||||
| $ curl -OL "https://github.com/scottlamb/moonfire-nvr/releases/download/$VERSION/moonfire-nvr-$VERSION-$ARCH" | ||||
| $ sudo install -m 755 "moonfire-nvr-$VERSION-$ARCH" /usr/local/bin/moonfire-nvr | ||||
| ``` | ||||
| 
 | ||||
| Next, you'll need to set up your filesystem and the Moonfire NVR user. | ||||
| 
 | ||||
| @ -49,22 +48,12 @@ On most Linux systems, you can create the user as follows: | ||||
| $ 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 `/etc/moonfire-nvr.toml` and | ||||
| `/usr/local/bin/nvr`, starting from the configurations below: | ||||
| Use your favorite editor to create `/etc/moonfire-nvr.toml`, | ||||
| starting from the configurations below: | ||||
| 
 | ||||
| ```console | ||||
| $ sudo nano /etc/moonfire-nvr.toml | ||||
| (see below for contents) | ||||
| $ sudo nano /usr/local/bin/nvr | ||||
| (see below for contents) | ||||
| $ sudo chmod a+rx /usr/local/bin/nvr | ||||
| ``` | ||||
| 
 | ||||
| `/etc/moonfire-nvr.toml` (see [ref/config.md](../ref/config.md) for more explanation): | ||||
| @ -78,79 +67,10 @@ unix = "/var/lib/moonfire-nvr/sock" | ||||
| ownUidIsPrivileged = true | ||||
| ``` | ||||
| 
 | ||||
| `/usr/local/bin/nvr`: | ||||
| ```bash | ||||
| #!/bin/bash -e | ||||
| 
 | ||||
| # Set your timezone here. | ||||
| tz="America/Los_Angeles" | ||||
| 
 | ||||
| image_name="scottlamb/moonfire-nvr:v0.7.7" | ||||
| container_name="moonfire-nvr" | ||||
| common_docker_run_args=( | ||||
|         --mount=type=bind,source=/var/lib/moonfire-nvr,destination=/var/lib/moonfire-nvr | ||||
|         --mount=type=bind,source=/etc/moonfire-nvr.toml,destination=/etc/moonfire-nvr.toml | ||||
| 
 | ||||
|         # Add additional mount lines here for each sample file directory | ||||
|         # outside of /var/lib/moonfire-nvr, e.g.: | ||||
|         # --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 older 32-bit hosts. | ||||
|         # https://github.com/moby/moby/issues/40734 | ||||
|         --security-opt=seccomp:unconfined | ||||
| 
 | ||||
|         # This is the simplest way of configuring networking, although | ||||
|         # you can use e.g. --publish=8080:8080 in the run) case below if you | ||||
|         # prefer. | ||||
|         --network=host | ||||
| 
 | ||||
|         # 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[@]}" \ | ||||
|                 --name="${container_name}" \ | ||||
|                 "${image_name}" \ | ||||
|                 run \ | ||||
|                 "$@" | ||||
|         ;; | ||||
| 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: | ||||
| Then initialize the database: | ||||
| 
 | ||||
| ```console | ||||
| $ sudo nvr init | ||||
| $ sudo -u moonfire-nvr moonfire-nvr init | ||||
| ``` | ||||
| 
 | ||||
| This will create a directory `/var/lib/moonfire-nvr/db` with a SQLite3 database | ||||
| @ -189,10 +109,6 @@ 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. | ||||
| 
 | ||||
| Add a new `--mount` line to your Docker wrapper script `/usr/local/bin/nvr` | ||||
| to expose the new sample directory `/media/nvr/sample` 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 | ||||
| @ -200,16 +116,17 @@ 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 | ||||
| $ sudo -u moonfire-nvr moonfire-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. | ||||
| If `moonfire-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. If you are running a systemd | ||||
| service as described below, try `sudo systemctl stop moonfire-nvr` before | ||||
| editing the config and `sudo systemctl start moonfire-nvr` after. | ||||
| </details> | ||||
| 
 | ||||
| In the user interface, | ||||
| @ -277,15 +194,58 @@ 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. | ||||
| Assuming you want to proceed, you can launch Moonfire NVR through `systemd`. | ||||
| Create `/etc/systemd/system/moonfire-nvr.service`: | ||||
| 
 | ||||
| ```console | ||||
| $ sudo nvr run | ||||
| ```ini | ||||
| [Unit] | ||||
| Description=Moonfire NVR | ||||
| After=network-online.target | ||||
| 
 | ||||
| # If you use an external hard drive, uncomment this with a reference to the | ||||
| # mount point as written in `/etc/fstab`. | ||||
| # RequiresMountsFor=/media/nvr | ||||
| 
 | ||||
| [Service] | ||||
| ExecStart=/usr/local/bin/moonfire-nvr run | ||||
| Environment=TZ=:/etc/localtime | ||||
| Environment=MOONFIRE_FORMAT=systemd | ||||
| Environment=MOONFIRE_LOG=info | ||||
| Environment=RUST_BACKTRACE=1 | ||||
| Type=simple | ||||
| User=moonfire-nvr | ||||
| Restart=on-failure | ||||
| CPUAccounting=true | ||||
| MemoryAccounting=true | ||||
| BlockIOAccounting=true | ||||
| 
 | ||||
| [Install] | ||||
| WantedBy=multi-user.target | ||||
| ``` | ||||
| 
 | ||||
| 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`. | ||||
| Then start it up as follows: | ||||
| 
 | ||||
| ```console | ||||
| $ sudo systemctl daemon-reload              # read in the new config file | ||||
| $ sudo systemctl enable --now moonfire-nvr  # start the service now and on boot | ||||
| ``` | ||||
| 
 | ||||
| Some handy commands: | ||||
| 
 | ||||
| ```console | ||||
| $ sudo systemctl daemon-reload                                  # reload configuration files | ||||
| $ sudo systemctl start moonfire-nvr                             # start the service now without enabling on boot | ||||
| $ sudo systemctl stop moonfire-nvr                              # stop the service now (but don't wait for it finish stopping) | ||||
| $ sudo systemctl status moonfire-nvr                            # show if the service is running and the last few log lines | ||||
| $ sudo systemctl enable moonfire-nvr                            # start the service on boot | ||||
| $ sudo systemctl disable moonfire-nvr                           # don't start the service on boot | ||||
| $ sudo journalctl --unit=moonfire-nvr --since='-5 min' --follow # look at recent logs and await more | ||||
| ``` | ||||
| 
 | ||||
| See the [systemd](http://www.freedesktop.org/wiki/Software/systemd/) | ||||
| documentation for more information. The [manual | ||||
| pages](http://www.freedesktop.org/software/systemd/man/) for `systemd.service` | ||||
| and `systemctl` may be of particular interest. | ||||
| 
 | ||||
| The HTTP interface is accessible on port 8080; if your web browser is running | ||||
| on the same machine, you can access it at | ||||
|  | ||||
| @ -62,11 +62,11 @@ SQLite database: | ||||
|         no longer in the dangerous mode. | ||||
| 
 | ||||
| Next ensure Moonfire NVR is not running and does not automatically restart if | ||||
| the system is rebooted during the upgrade. If you followed the Docker | ||||
| the system is rebooted during the upgrade. If you followed the standard | ||||
| instructions, you can do this as follows: | ||||
| 
 | ||||
| ```console | ||||
| $ sudo nvr stop | ||||
| $ sudo systemctl disable --now moonfire-nvr | ||||
| ``` | ||||
| 
 | ||||
| Then back up your SQLite database. If you are using the default path, you can | ||||
| @ -92,34 +92,27 @@ manual for write-ahead logging](https://www.sqlite.org/wal.html): | ||||
| 
 | ||||
| Run the upgrade procedure using the new software binary. | ||||
| 
 | ||||
| ```console | ||||
| $ sudo nvr pull     # updates the docker image to the latest binary | ||||
| $ sudo nvr upgrade  # runs the upgrade | ||||
| ``` | ||||
| 
 | ||||
| As a rule of thumb, on a Raspberry Pi 4 with a 1 GiB database, an upgrade might | ||||
| take about four minutes for each schema version and for the final vacuum. | ||||
| 
 | ||||
| Next, you can run the system in read-only mode, although you'll find this only | ||||
| works in the "insecure" setup. (Authorization requires writing the database.) | ||||
| To just run directly within the console until you hit ctrl-C, use the following | ||||
| command: | ||||
| 
 | ||||
| ```console | ||||
| $ sudo nvr rm | ||||
| $ sudo nvr run --read-only | ||||
| $ sudo -u moonfire-nvr moonfire-nvr run --read-only | ||||
| ``` | ||||
| 
 | ||||
| Go to the web interface and ensure the system is operating correctly. If | ||||
| you detect a problem now, you can copy the old database back over the new one | ||||
| and edit your `nvr` script to use the corresponding older Docker image. If | ||||
| you detect a problem after enabling read-write operation, a restore will be | ||||
| more complicated. | ||||
| and go back to the prior release. If you detect a problem after enabling | ||||
| read-write operation, a restore will be more complicated. | ||||
| 
 | ||||
| Once you're satisfied, restart the system in read-write mode: | ||||
| Once you're satisfied, ctrl-C and start the system in read-write mode: | ||||
| 
 | ||||
| ```console | ||||
| $ sudo nvr stop | ||||
| $ sudo nvr rm | ||||
| $ sudo nvr run | ||||
| $ sudo systemctl enable --now moonfire-nvr | ||||
| ``` | ||||
| 
 | ||||
| Hopefully your system is functioning correctly. If not, there are two options | ||||
| @ -137,7 +130,8 @@ for restore; neither are easy: | ||||
| *  undo the changes by hand. There's no documentation on this; you'll need | ||||
|     to read the code and come up with a reverse transformation. | ||||
| 
 | ||||
| The `nvr check` command will show you what problems exist on your system. | ||||
| The `sudo -u moonfire-nvr moonfire-nvr check` command will show you what | ||||
| problems exist on your system. | ||||
| 
 | ||||
| ### Unversioned to version 0 | ||||
| 
 | ||||
|  | ||||
| @ -161,8 +161,8 @@ your browser. See [How to secure Nginx with Let's Encrypt on Ubuntu | ||||
| 
 | ||||
| ## 6. Reconfigure Moonfire NVR | ||||
| 
 | ||||
| If you follow the recommended Docker setup, your `/etc/moonfire-nvr.toml` | ||||
| will contain this line: | ||||
| If you follow the recommended setup, your `/etc/moonfire-nvr.toml` will contain | ||||
| this line: | ||||
| 
 | ||||
| ```toml | ||||
| allowUnauthenticatedPermissions = { viewVideo = true } | ||||
| @ -185,18 +185,16 @@ This change has two effects: | ||||
| See also [ref/config.md](../ref/config.md) for more about the configuration file. | ||||
| 
 | ||||
| If the webserver is running on the same machine as Moonfire NVR, you might | ||||
| also change `--publish=8080:8080` to `--publish=127.0.0.1:8080:8080` in your | ||||
| `/usr/local/bin/nvr` script, preventing other machines on the network from | ||||
| impersonating the proxy, effectively allowing them to lie about the client's IP | ||||
| and protocol. | ||||
| also change the `ipv4 = "0.0.0.0:8080"` line in `/etc/moonfire-nvr/toml` to | ||||
| `ipv4 = "127.0.0.1:8080"`, so that only the local host can directly connect to | ||||
| Moonfire NVR. If other machines can connect directly, they can impersonate | ||||
| the proxy, which would effectively allow them to lie about the client's IP and | ||||
| protocol. | ||||
| 
 | ||||
| To make this take effect, you'll need to stop the running Docker container, | ||||
| delete it, and create/run a new one: | ||||
| To make this take effect, you'll need to restart Moonfire NVR: | ||||
| 
 | ||||
| ```console | ||||
| $ sudo nvr stop | ||||
| $ sudo nvr rm | ||||
| $ sudo nvr run | ||||
| $ sudo systemctl restart moonfire-nvr | ||||
| ``` | ||||
| 
 | ||||
| ## 7. Configure the webserver | ||||
|  | ||||
| @ -11,7 +11,6 @@ need more help. | ||||
|     * [Camera stream errors](#camera-stream-errors) | ||||
| * [Problems](#problems) | ||||
|     * [Server errors](#server-errors) | ||||
|         * [`clock_gettime failed: EPERM: Operation not permitted`](#clock_gettime-failed-eperm-operation-not-permitted) | ||||
|         * [`Error: pts not monotonically increasing; got 26615520 then 26539470`](#error-pts-not-monotonically-increasing-got-26615520-then-26539470) | ||||
|         * [Out of disk space](#out-of-disk-space) | ||||
|         * [Database or filesystem corruption errors](#database-or-filesystem-corruption-errors) | ||||
| @ -29,9 +28,8 @@ While Moonfire NVR is running, logs will be written to stderr. | ||||
| *   When running the configuration UI, you typically should redirect stderr | ||||
|     to a text file to avoid poor interaction between the interactive stdout | ||||
|     output and the logging. If you use the recommended | ||||
|     `nvr config 2>debug-log` command, output will be in the `debug-log` file. | ||||
| *   When running detached through Docker, Docker saves the logs for you. | ||||
|     Try `nvr logs` or `docker logs moonfire-nvr`. | ||||
|     `moonfire-nvr config 2>debug-log` command, output will be in the | ||||
|     `debug-log` file. | ||||
| *   When running through systemd, stderr will be redirected to the journal. | ||||
|     Try `sudo journalctl --unit moonfire-nvr` to view the logs. You also | ||||
|     likely want to set `MOONFIRE_FORMAT=systemd` to format logs as | ||||
| @ -56,8 +54,6 @@ Logging options are controlled by environment variables: | ||||
|         consumption. | ||||
| *   Errors include a backtrace if `RUST_BACKTRACE=1` is set. | ||||
| 
 | ||||
| If you use Docker, set these via Docker's `--env` argument. | ||||
| 
 | ||||
| With `MOONFIRE_FORMAT` left unset, log events look as follows: | ||||
| 
 | ||||
| ```text | ||||
| @ -191,23 +187,6 @@ quickly enough. In the latter case, you'll likely see a | ||||
| 
 | ||||
| ### Server errors | ||||
| 
 | ||||
| #### `clock_gettime failed: EPERM: Operation not permitted` | ||||
| 
 | ||||
| If commands fail with an error like the following, you're likely running | ||||
| Docker with an overly restrictive `seccomp` setup. [This stackoverflow | ||||
| answer](https://askubuntu.com/questions/1263284/apt-update-throws-signature-error-in-ubuntu-20-04-container-on-arm/1264921#1264921) describes the | ||||
| problem in more detail. The simplest solution is to add | ||||
| `--security-opt=seccomp:unconfined` to your Docker commandline. | ||||
| If you are using the recommended `/usr/local/bin/nvr` wrapper script, | ||||
| add this option to the `common_docker_run_args` section. | ||||
| 
 | ||||
| ```console | ||||
| $ sudo docker run --rm -it moonfire-nvr:latest | ||||
| clock_gettime failed: EPERM: Operation not permitted | ||||
| 
 | ||||
| This indicates a broken environment. See the troubleshooting guide. | ||||
| ``` | ||||
| 
 | ||||
| #### `Error: pts not monotonically increasing; got 26615520 then 26539470` | ||||
| 
 | ||||
| If your streams cut out and you see error messages like this one in Moonfire | ||||
| @ -322,8 +301,7 @@ mechanism to fix old timestamps after the fact. Ideas and help welcome; see | ||||
| 
 | ||||
| #### `moonfire-nvr config` displays garbage | ||||
| 
 | ||||
| This happens if you're not using the premade Docker containers and have | ||||
| configured your machine is configured to a non-UTF-8 locale, due to | ||||
| This may happen if your machine is configured to a non-UTF-8 locale, due to | ||||
| gyscos/Cursive#13. As a workaround, try setting the environment variable | ||||
| `LC_ALL=C.UTF-8`. | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										51
									
								
								release.bash
									
									
									
									
									
								
							
							
						
						
									
										51
									
								
								release.bash
									
									
									
									
									
								
							| @ -1,51 +0,0 @@ | ||||
| #!/bin/bash | ||||
| # This file is part of Moonfire NVR, a security camera network video recorder. | ||||
| # Copyright (C) 2021 The Moonfire NVR Authors; see AUTHORS and LICENSE.txt. | ||||
| # SPDX-License-Identifier: GPL-v3.0-or-later WITH GPL-3.0-linking-exception | ||||
| 
 | ||||
| # Pushes a release to Docker. See guides/build.md#release-procedure. | ||||
| 
 | ||||
| set -o errexit | ||||
| set -o pipefail | ||||
| set -o xtrace | ||||
| 
 | ||||
| set_latest() { | ||||
|     # Our images are manifest lists (for multiple architectures). | ||||
|     # "docker tag" won't copy those. The technique below is adopted from here: | ||||
|     # https://github.com/docker/buildx/issues/459#issuecomment-750011371 | ||||
|     local image="$1" | ||||
|     local hashes=($(docker manifest inspect "${image}:${version}" | | ||||
|                     jq --raw-output '.manifests[].digest')) | ||||
|     time docker manifest rm "${image}:latest" || true | ||||
|     time docker manifest create \ | ||||
|         "${image}:latest" \ | ||||
|         "${hashes[@]/#/${image}@}" | ||||
|     time docker manifest push "${image}:latest" | ||||
| } | ||||
| 
 | ||||
| build_and_push() { | ||||
|     local image="$1" | ||||
|     local target="$2" | ||||
|     time docker buildx build \ | ||||
|         --push \ | ||||
|         --tag="${image}:${version}" \ | ||||
|         --target="${target}" \ | ||||
|         --platform=linux/amd64,linux/arm64/v8,linux/arm/v7 \ | ||||
|         -f docker/Dockerfile . | ||||
| } | ||||
| 
 | ||||
| version="$(git describe --dirty)" | ||||
| if [[ ! "${version}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then | ||||
|     echo "Expected a vX.Y.Z version tag, got ${version}." >&2 | ||||
|     exit 1 | ||||
| fi | ||||
| 
 | ||||
| if [[ -n "$(git status --porcelain)" ]]; then | ||||
|     echo "git status says there's extra stuff in this directory." >&2 | ||||
|     exit 1 | ||||
| fi | ||||
| 
 | ||||
| build_and_push scottlamb/moonfire-nvr deploy | ||||
| build_and_push scottlamb/moonfire-dev dev | ||||
| set_latest scottlamb/moonfire-nvr | ||||
| set_latest scottlamb/moonfire-dev | ||||
							
								
								
									
										46
									
								
								server/Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										46
									
								
								server/Cargo.lock
									
									
									
										generated
									
									
									
								
							| @ -303,10 +303,8 @@ dependencies = [ | ||||
|  "lazy_static", | ||||
|  "libc", | ||||
|  "log", | ||||
|  "maplit", | ||||
|  "ncurses", | ||||
|  "signal-hook", | ||||
|  "term_size", | ||||
|  "termion", | ||||
|  "unicode-segmentation", | ||||
|  "unicode-width", | ||||
| ] | ||||
| @ -982,12 +980,6 @@ dependencies = [ | ||||
|  "cfg-if", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "maplit" | ||||
| version = "1.0.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "matchers" | ||||
| version = "0.1.0" | ||||
| @ -1198,17 +1190,6 @@ version = "0.2.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "96a1fe2275b68991faded2c80aa4a33dba398b77d276038b8f50701a22e55918" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "ncurses" | ||||
| version = "5.101.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "5e2c5d34d72657dc4b638a1c25d40aae81e4f1c699062f72f467237920752032" | ||||
| dependencies = [ | ||||
|  "cc", | ||||
|  "libc", | ||||
|  "pkg-config", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "nix" | ||||
| version = "0.26.1" | ||||
| @ -1338,6 +1319,12 @@ dependencies = [ | ||||
|  "libc", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "numtoa" | ||||
| version = "0.1.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "odds" | ||||
| version = "0.4.0" | ||||
| @ -1581,6 +1568,15 @@ dependencies = [ | ||||
|  "bitflags 1.3.2", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "redox_termios" | ||||
| version = "0.1.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "8440d8acb4fd3d277125b4bd01a6f38aee8d814b3b5fc09b3f2b825d37d3fe8f" | ||||
| dependencies = [ | ||||
|  "redox_syscall", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "reffers" | ||||
| version = "0.7.0" | ||||
| @ -1994,13 +1990,15 @@ dependencies = [ | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "term_size" | ||||
| version = "0.3.2" | ||||
| name = "termion" | ||||
| version = "1.5.6" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "1e4129646ca0ed8f45d09b929036bafad5377103edd06e50bf574b353d2b08d9" | ||||
| checksum = "077185e2eac69c3f8379a4298e1e07cd36beb962290d4a51199acf0fdc10607e" | ||||
| dependencies = [ | ||||
|  "libc", | ||||
|  "winapi", | ||||
|  "numtoa", | ||||
|  "redox_syscall", | ||||
|  "redox_termios", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
|  | ||||
| @ -35,7 +35,7 @@ bpaf = { version = "0.9.1", features = ["autocomplete", "bright-color", "derive" | ||||
| bytes = "1" | ||||
| byteorder = "1.0" | ||||
| chrono = "0.4.23" | ||||
| cursive = "0.20.0" | ||||
| cursive = { version = "0.20.0", default-features = false, features = ["termion-backend"] } | ||||
| db = { package = "moonfire-db", path = "db" } | ||||
| futures = "0.3" | ||||
| fnv = "1.0" | ||||
|  | ||||
							
								
								
									
										14
									
								
								server/Cross.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								server/Cross.toml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,14 @@ | ||||
| [build.env] | ||||
| volumes = [ | ||||
|     # For the (optional) `bundled-ui` feature. | ||||
|     "UI_BUILD_DIR", | ||||
| 
 | ||||
|     # For tests which use the `America/Los_Angeles` zone. | ||||
|     "ZONEINFO=/usr/share/zoneinfo", | ||||
| ] | ||||
| 
 | ||||
| passthrough = [ | ||||
|     # Cross's default docker image doesn't install `git`, so `git_version!` doesn't work. | ||||
|     # Allow passing through the version via this environment variable. | ||||
|     "VERSION", | ||||
| ] | ||||
| @ -6,13 +6,17 @@ | ||||
| 
 | ||||
| use std::fmt::Write; | ||||
| use std::path::{Path, PathBuf}; | ||||
| use std::process::ExitCode; | ||||
| use std::process::Command; | ||||
| 
 | ||||
| const UI_DIR: &str = "../ui/build"; | ||||
| const UI_BUILD_DIR_ENV_VAR: &str = "UI_BUILD_DIR"; | ||||
| const DEFAULT_UI_BUILD_DIR: &str = "../ui/build"; | ||||
| 
 | ||||
| type BoxError = Box<dyn std::error::Error + Send + Sync + 'static>; | ||||
| 
 | ||||
| fn ensure_link(original: &Path, link: &Path) { | ||||
|     match std::fs::read_link(link) { | ||||
|         Ok(dst) if dst == original => return, | ||||
|         Ok(_) => std::fs::remove_file(link).expect("removing stale symlink should succeed"), | ||||
|         Err(e) if e.kind() != std::io::ErrorKind::NotFound => { | ||||
|             panic!("couldn't create link {link:?} to original path {original:?}: {e}") | ||||
|         } | ||||
| @ -67,37 +71,30 @@ fn stringify_files(files: &FileMap) -> Result<String, std::fmt::Error> { | ||||
|     Ok(buf) | ||||
| } | ||||
| 
 | ||||
| fn main() -> ExitCode { | ||||
|     // Explicitly declare dependencies, so this doesn't re-run if other source files change.
 | ||||
|     println!("cargo:rerun-if-changed=build.rs"); | ||||
| 
 | ||||
| fn handle_bundled_ui() -> Result<(), BoxError> { | ||||
|     // Nothing to do if the feature is off. cargo will re-run if features change.
 | ||||
|     if !cfg!(feature = "bundled-ui") { | ||||
|         return ExitCode::SUCCESS; | ||||
|         return Ok(()); | ||||
|     } | ||||
| 
 | ||||
|     let ui_dir = | ||||
|         std::env::var(UI_BUILD_DIR_ENV_VAR).unwrap_or_else(|_| DEFAULT_UI_BUILD_DIR.to_owned()); | ||||
| 
 | ||||
|     // If the feature is on, also re-run if the actual UI files change.
 | ||||
|     println!("cargo:rerun-if-changed={UI_DIR}"); | ||||
|     println!("cargo:rerun-if-env-changed={UI_BUILD_DIR_ENV_VAR}"); | ||||
|     println!("cargo:rerun-if-changed={ui_dir}"); | ||||
| 
 | ||||
|     let out_dir: PathBuf = std::env::var_os("OUT_DIR") | ||||
|         .expect("cargo should set OUT_DIR") | ||||
|         .into(); | ||||
| 
 | ||||
|     let abs_ui_dir = std::fs::canonicalize(UI_DIR) | ||||
|         .expect("ui dir should be accessible. Did you run `npm run build` first?"); | ||||
|     let abs_ui_dir = std::fs::canonicalize(&ui_dir).map_err(|e| format!("ui dir {ui_dir:?} should be accessible. Did you run `npm run build` first?\n\ncaused by:\n{e}"))?; | ||||
| 
 | ||||
|     let mut files = FileMap::default(); | ||||
|     for entry in walkdir::WalkDir::new(&abs_ui_dir) { | ||||
|         let entry = match entry { | ||||
|             Ok(e) => e, | ||||
|             Err(e) => { | ||||
|                 eprintln!( | ||||
|                     "walkdir failed. Did you run `npm run build` first?\n\n\ | ||||
|                     caused by:\n{e}" | ||||
|                 ); | ||||
|                 return ExitCode::FAILURE; | ||||
|             } | ||||
|         }; | ||||
|         let entry = entry.map_err(|e| { | ||||
|             format!("walkdir failed. Did you run `npm run build` first?\n\ncaused by:\n{e}") | ||||
|         })?; | ||||
|         if !entry.file_type().is_file() { | ||||
|             continue; | ||||
|         } | ||||
| @ -135,6 +132,13 @@ fn main() -> ExitCode { | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     if !files.contains_key("index.html") { | ||||
|         return Err(format!( | ||||
|             "No `index.html` within {ui_dir:?}. Did you run `npm run build` first?" | ||||
|         ) | ||||
|         .into()); | ||||
|     } | ||||
| 
 | ||||
|     let files = stringify_files(&files).expect("write to String should succeed"); | ||||
|     let mut out_rs_path = std::path::PathBuf::new(); | ||||
|     out_rs_path.push(&out_dir); | ||||
| @ -145,5 +149,49 @@ fn main() -> ExitCode { | ||||
|     out_link_path.push(&out_dir); | ||||
|     out_link_path.push("ui_files"); | ||||
|     ensure_link(&abs_ui_dir, &out_link_path); | ||||
|     return ExitCode::SUCCESS; | ||||
|     Ok(()) | ||||
| } | ||||
| 
 | ||||
| fn handle_version() -> Result<(), BoxError> { | ||||
|     println!("cargo:rerun-if-env-changed=VERSION"); | ||||
|     if std::env::var("VERSION").is_ok() { | ||||
|         return Ok(()); | ||||
|     } | ||||
| 
 | ||||
|     // Get version from `git describe`. Inspired by the `git-version` crate.
 | ||||
|     // We don't use that directly because `cross`'s default docker image doesn't install `git`,
 | ||||
|     // and thus we need the environment variable pass-through above.
 | ||||
| 
 | ||||
|     // Avoid reruns when the output doesn't meaningfully change. I don't think this is quite right:
 | ||||
|     // it won't recognize toggling between `-dirty` and not. But it'll do.
 | ||||
|     let dir = Command::new("git") | ||||
|         .arg("rev-parse") | ||||
|         .arg("--git-dir") | ||||
|         .output()? | ||||
|         .stdout; | ||||
|     let dir = String::from_utf8(dir).unwrap(); | ||||
|     let dir = dir.strip_suffix('\n').unwrap(); | ||||
|     println!("cargo:rerun-if-changed={dir}/logs/HEAD"); | ||||
|     println!("cargo:rerun-if-changed={dir}/index"); | ||||
| 
 | ||||
|     // Plumb the version through.
 | ||||
|     let version = Command::new("git") | ||||
|         .arg("describe") | ||||
|         .arg("--always") | ||||
|         .arg("--dirty") | ||||
|         .output()? | ||||
|         .stdout; | ||||
|     let version = String::from_utf8(version).unwrap(); | ||||
|     let version = version.strip_suffix('\n').unwrap(); | ||||
|     println!("cargo:rustc-env=VERSION={version}"); | ||||
| 
 | ||||
|     Ok(()) | ||||
| } | ||||
| 
 | ||||
| fn main() -> Result<(), BoxError> { | ||||
|     // Explicitly declare dependencies, so this doesn't re-run if other source files change.
 | ||||
|     println!("cargo:rerun-if-changed=build.rs"); | ||||
|     handle_bundled_ui()?; | ||||
|     handle_version()?; | ||||
|     Ok(()) | ||||
| } | ||||
|  | ||||
| @ -22,6 +22,7 @@ struct BuildFile { | ||||
|     encoding: FileEncoding, | ||||
| } | ||||
| 
 | ||||
| #[allow(unused)] // it's valid for a UI to have all uncompressed files or vice versa.
 | ||||
| #[derive(Copy, Clone)] | ||||
| enum FileEncoding { | ||||
|     Uncompressed, | ||||
|  | ||||
| @ -25,7 +25,8 @@ mod bundled_ui; | ||||
| 
 | ||||
| const DEFAULT_DB_DIR: &str = "/var/lib/moonfire-nvr/db"; | ||||
| 
 | ||||
| const VERSION: &str = git_version::git_version!(args = ["--always", "--dirty"]); | ||||
| // This is either in the environment when `cargo` is invoked or set from within `build.rs`.
 | ||||
| const VERSION: &str = env!("VERSION"); | ||||
| 
 | ||||
| /// Moonfire NVR: security camera network video recorder.
 | ||||
| #[derive(Bpaf, Debug)] | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user