This is a project to build docker containers for Network Optix Nx Witness VMS, and Network Optix Nx Meta VMS, the developer test and preview version of Nx Witness, and Digital Watchdog DW Spectrum IPVMS, the US licensed and OEM branded version of Nx Witness.
Code:
My initial inspiration to convert my DW Spectrum system running on a VM to docker came from The Home Repot NxWitness project. I started with one GitHub docker project repository, then two, then four, and by five I decided to consolidate the various, but very similar, repositories into a single project.
The Network Optix reference docker project is located here.
The biggest outstanding docker challenges are hardware bound licensing, and lack of admin defined storage locations.
The project supports three product variants:
- Network Optix Nx Witness VMS.
- Network Optix Nx Meta VMS, the developer test and preview version of Nx Witness.
- Digital Watchdog DW Spectrum IPVMS, the US licensed and OEM branded version of Nx Witness.
The project create two variants of each product using different base images:
- Ubuntu using ubuntu:bionic base image.
- LinuxServer using lsiobase/ubuntu:bionic base image.
Note, I can use smaller base images like alpine, but the mediaserver officially supports Ubuntu Bionic.
The LinuxServer (LSIO) base images provide valuable functionality:
- The LSIO images are based on s6-overlay, and LSIO produces containers for many popular open source apps.
- LSIO allows us to specify the user account to use when running the container process.
- This is desired if we do not want to run as root, or required if we need user specific permissions when accessing mapped volumes.
- We could achieve a similar outcome by using Docker's --user option, but it is often more convenient to modify environment variables vs. controlling how a container runs.
The docker configuration is reasonably simple, requiring just two volume mappings for configuration files and media storage.
/config
: Configuration files.
/media
: Recording files.
/archive
: Backup files. (Optional)
The Nx Witness backup implementation is not very useful, as it only makes a copy of the recordings, it does not extend the retention period.
The mediaserver filters filesystems by type, and the /media
mapping must point to a supported filesytem.
ZFS and Unraid's FUSE filesystems are by default not supported, and requires the advanced additionalLocalFsTypes
setting to be configured, see the notes section for details.
An alternatively for Unraid is to use the Unassigned Devices plugin and assign storage to e.g. a XFS formatted SSD drive.
7001
: Default server port.
PUID
: User Id (LSIO only, see docs for usage).
PGID
: Group Id (LSIO only).
TZ
: Timezone, e.g. Americas/Los_Angeles
.
Any network mode can be used, but due to the hardware bound licensing, host
mode is preferred.
docker create \
--name=dwspectrum-lsio-test-container \
--hostname=dwspectrum-lsio-test-host \
--domainname=foo.bar.net \
--restart=unless-stopped \
--network=host \
--env TZ=Americas/Los_Angeles \
--volume /mnt/dwspectrum/config:/config:rw \
--volume /mnt/dwspectrum/media:/media:rw \
ptr727/dwspectrum-lsio
docker start dwspectrum-lsio-test-container
version: "3.7"
services:
dwspectrum:
image: ptr727/dwspectrum-lsio
container_name: dwspectrum-lsio-test-container
restart: unless-stopped
network_mode: host
environment:
- TZ=Americas/Los_Angeles
volumes:
- /mnt/dwspectrum/config:/config
- /mnt/dwspectrum/media:/media
- Add the template URL
https://github.com/ptr727/NxWitness/tree/master/Unraid
to the "Template Repositories" section, at the bottom of the "Docker" configuration tab, and click "Save". - Create a new container by clicking the "Add Container" button, select the desired product template from the dropdown.
- If using Unassigned Devices for media storage, use
RW/Slave
access mode. - Use
nobody
andusers
identifiers,PUID=99
andPGID=100
.
Product releases and updates can be found at the following locations:
- I have not found a single location that lists the latest versions, nor a way to be automatically notified of a new versions.
- Nx Witness Downloads
- Nx Witness Beta Downloads
- Newer builds are sometimes listed in the "Patches" section.
- Nx Meta Downloads
- Nx Meta Early Access Signup
- Newer builds are sometimes listed in the Patches or Releases sections.
- DW Spectrum Downloads
- The latest DW Spectrum versions are often not listed, but sometimes do match the same version as used by Nx Witness.
- Use the latest NX Witness URL, and substitute the "default" string for "digitalwatchdog", e.g.:
With three products and two base images we end up with six different dockerfiles, that all basically look the same. Unfortunately Docker does not support an include
directive, but we can use a Makefile
to dynamically create a Dockerfile
for us.
I use Docker Hub Automated Builds to automatically trigger, build, and publish images to Docker Hub. I kept the Docker Hub repositories and image names separate, but it would be possible to publish different products using different tags for one image, it just does not seem natural.
I am considering using GitHub Actions to automatically build the containers, but I've not yet figured out how to have GitHub Actions automatically rebuild the container when the upstream base image changes, this functionality is included in Docker Hub Automated Builds.
I should also figure out how to automatically detect newly released versions, and automatically rebuild when a new version is detected. This could possibly be done using page change notifiers and webhooks, with some code to extract the relevant version and URL attributes from the web pages. For now I'm manually updating as I notice the versions changing.
The biggest outstanding docker challenges are hardware bound licensing, and lack of admin defined storage locations.
The camera license keys are activated using hardware attributes of the server, that is not docker friendly, and occasionally results in activation failures. I would much prefer a modern approach to apply licenses to my cloud account, allowing me to run on whatever hardware I want. Living in the US, I have to buy my licenses from Digital Watchdog, and in my experience their license enforcement policy is "draconian", three activations and you have to buy a new license. That really means that the Lifetime Upgrades and No Annual Agreements license is the lifetime of the hardware on which the license was activated. So let's say hardware is replaced every two years, three activations, lifetime is about six years, not much of a lifetime compared to other products that are license flexible but require maintenance or renewals.
As for storage, the mediaserver attempts to automatically decide what storage to use, applies filesystem type and instance filtering, and blindly creates files on any storage it deems fit. This overly complicated logic does not work in docker, and a much simpler and reliable approach would be to allow an admin to be in control and specify exactly what storage to be used. I really do not understand what the reasons were for building complicated decision logic, instead of being like all other servers that use storage and let the admin define the storage locations.
All in, Nx Witness is in my experience still the lightest on resources with good features VMS/NVR I've used, and with docker support, is great to run in my home lab.
My wishlist for better docker support:
- Publish always up to date and ready to use docker images on Docker Hub.
- Use the cloud account for license enforcement.
- Allow the administrator to specify and use any storage location.
- Allow the administrator to specify the bound network adapter.
- Implement a more useful recording archive management system, allowing for separate high speed recording, and high capacity playback storage volumes.
- Version 4.1 includes the ability to specify additional storage filesystem types. This is particularly useful when running on Unraid or ZFS storage that is by default not supported.
- Access the server storage page at
http://hostname:7001/static/index.html#/info
and verify that all mounted storage is listed. - If storage is not listed, attach to the container console and run
cat /proc/mounts
to get a list of all the mounted filesystem types. - Access the advanced settings page at
http://hostname:7001/static/index.html#/advanced
and setadditionalLocalFsTypes
to include the filesystem type. - Add
fuse.grpcfuse
for Docker for Windows,fuse.shfs
for Unraid, andzfs
for ZFS, e.g.fuse.grpcfuse,fuse.shfs,zfs
. - Save the settings, restart the server, and verify that storage is now available.
- Access the server storage page at
- The calculation of
VMS_DIR=$(dirname $(dirname "${BASH_SOURCE[0]}"))
in../bin/mediaserver
can result in bad paths when called from the same directory, e.g.start-stop-daemon: unable to stat ./bin/./bin/mediaserver-bin (No such file or directory)
. - The filesystem filter logic incorrectly considers some volumes to be duplicates, turn on verbose logging (logLevel=DEBUG2) :
2020-05-18 10:13:55.964 422 VERBOSE nx::vms::server::fs: shfs /archive fuse.shfs - duplicate
. - There is no way to configure the
additionalLocalFsTypes
types at deployment time, it can only be done post deployment from thehttp://hostname:7001/static/index.html#/advanced
web interface or viahttp://admin:<passsword>@hostname:7001/api/systemSettings?additionalLocalFsTypes=fuse.grpcfuse,fuse.shfs
.- Some debugging shows the setting is stored in the
var/ecs.sqlite
DB file, in thevms_kvpair
table,name=additionalLocalFsTypes
,value=fuse.grpcfuse,fuse.shfs,zfs
. - This DB table contains lots of other information, so it seems unfeasible to pre-seed the system with this DB file, and modifying it at runtime is as complex as calling the web service.
- Some debugging shows the setting is stored in the
- The mediaserver pollutes the filesystem by blindly creating a
Nx MetaVMS Media
folder and DB files in any storage it finds. - The mediaserver will bind to any network adapter it discovers, including virtual adapters used by other containers. There is no way to disable auto binding. All the bound network adapters are displayed in the performance graph, and makes it near impossible to use due.
- The download CDN SSL certificates are not trusted on all systems, and we need to disable certificate checks when using HTTPS for downloads.
ERROR: cannot verify updates.networkoptix.com's certificate, issued by 'CN=Amazon,OU=Server CA 1B,O=Amazon,C=US': Unable to locally verify the issuer's authority. To connect to updates.networkoptix.com insecurely, use --no-check-certificate