Skip to main content

This tutorial will enable you to install Zoneminder 35.16 on Ubuntu 20.04 using a Docker container. Docker, in my opinion, represents a further abstraction of the software architecture and thus makes a simple operation more complex. But while it is tricky to initially set up, once you do it, it works well. Anecdotally, I have noticed on two BHYVE virtual servers I have built this project on, I find the Docker version runs much more efficiently that a traditional install and that the server load is less than half when run inside the Docker container.

Firstly, I created this version on TrueNAS v. 12 using a virtual BHYVE instance which, having worked with KVM vm’s previously, I find the FreeNAS/TrueNAS virtual servers MUCH easier to use, snapshot and work with. Though if you are using other platforms, this tutorial should work for you as well. This tutorial assumes you have created an instance with one cpu and eight GB of ram and a 100gb virtual disk for the OS and a 500 GB or greater volume for camera storage (use ‘virtio’ if you’re using BHYVE). This how-to works with Ubuntu 20.04, though it should work on other distros/UB versions, ymmv. It assumes that you have Docker installed and properly tested. If you are new to Docker, click on this link for a quick tutorial to get you up and running. So let’s get started:

Here are the steps I followed to get Zoneminder 35.16 on Ubuntu 20.04:

1 – Pull docker image:

 docker pull dlandon/zoneminder.master

2 – Open a ssh command prompt and run the command below to create the Zoneminder container. For more information on the different options set below click here. Copy the command below as one block of text and paste it into the command window (change the timezone option and the /mnt/ option to suit your environment (**see step 6 below for more info about mounting external drives before you press enter):

docker run -d --name="Zoneminder" \
--net="bridge" \
--privileged="true" \
-p 8080:80/tcp \
-p 8443:443/tcp \
-p 9000:9000/tcp \
-e TZ="America/Toronto" \
-e SHMEM="50%" \
-e PUID="99" \
-e PGID="100" \
-e NO_START_ZM="1" \
-v "/mnt/Zoneminder":"/config":rw \
-v "/var/cache/zoneminder":"/var/cache/zoneminder":rw \
docker logs -f Zoneminder 'check progress of install

3 – After the Zoneminder container is installed we need to fix the MariaDB instance, which on my installation at least, didn’t run and generated an error, resulting in Zoneminder not starting. So enter bash shell on your docker instance:

docker exec -it Zoneminder /bin/bash

Remove the zm database:

    mysql -u root -p 'enter mysql 
	MariaDB [(none)]> SHOW DATABASES; 'list databases
	MariaDB [(none)]> DROP DATABASE IF EXISTS zm; 'delete existing zm db
	MariaDB [(none)]> exit;

4 – Now create new zm db (root password is empty, but you can change it if you wish) and start mysql and Zoneminder

mysql -uroot -p < /usr/share/zoneminder/db/zm_create.sql
service mysql start
service zoneminder start
exit 'quit the bash shell

5 – Now we need to adjust the NO_START_ZM=”1″ environment variable so Zoneminder will start automagically when the container in started. I know you can spawn a new container with the modified variable and delete the old one AND rename the modified one, etc. But I prefer to edit the json and just modify the existing container (see my abstraction comment in the preamble). Find your container and edit it as follows to remove: ,”NO_START_ZM=1″ to “NO_START_ZM=0” from the “Env”:[] section and save.

docker container ls -a  'list containers
docker container stop Zoneminder '[CONTAINER ID] or [container name]  'stop your container
nano /var/lib/docker/containers/[your container]/config.v2.json

6 – If you adjusted the variables in step 2 above you can skip this step, but I just wanted to provide readers with some context as to why we set these particular settings and what they do. Zoneminder, by its design uses a lot of disk space which is stored by default in the ‘/var/cache/zoneminder/events’ folder. Now it is not a good idea to put this folder on the same drive as your ‘/’ folder due to the fact that if your hard drive fills up completely, your system will die. So I like to mount an additional drive just to store the camera recordings and associated data.

The json syntax is as follows: {“Source”:”[/my_external_drive]”,”Destination”:”/var/cache/zoneminder” *remember, /mnt/zoneminder is mounted internally inside your container by default so you want to change that line to your external drive which you have previously mounted to your vm. Change the line: ,”MountPoints”: and change {“Source”:”/mnt/zoneminder”,”Destination”:”/var/cache/zoneminder” to {“Source”:”/var/cache/zoneminder”,”Destination”:”/var/cache/zoneminder” Also, using this step will allow those of you who need to mount more than one storage volume to your container do so easily by adding more mount points.

 docker container ls -a  'stop your container
nano config.v2.json 'See editing details above 
service docker restart 'restart docker service and check your newly mounted volume for zm directories
docker container start Zoneminder 'start it up
docker logs -f Zoneminder 'check logs for errors

7 – Now we have Zoneminder up and running we need to make it reachable from the outside world. To do this we are going to set up apache2 outside the container, configure a Let’s Encrypt certificate for it and establish a proxy connection to our webserver inside the Docker container which we have set up to listen on ports 8080 and 8443.

sudo apt install apache2 'install apache2
sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod rewrite
sudo a2enmod ssl
sudo a2enmod proxy_balancer
sudo a2enmod lbmethod_byrequests 'install needed apache mods
sudo a2ensite 'put your domain here
sudo systemctl restart apache2

8 – Create a Let’s Encrypt Certificate.

# Install certbot:
sudo apt install python3-certbot-apache
# Issue the following command to create e certificate:
sudo certbot --apache 'Follow the prompts. Certbot will find our domain and create a cert.

9 – Set up the file. Paste the following below into replacing existing text. Adjust servername and your local host’s IP (don’t use ‘localhost’)

‹VirtualHost *:80›

RewriteEngine on
RewriteCond %{SERVER_NAME}
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
‹VirtualHost *:443 *:30001 *:30002 *:30003 *:30004 *:30005›

            SSLEngine On
        	SSLProxyEngine On
            Order deny,allow
            Allow from all
    ProxyRequests On
    ProxyPreserveHost On
        ProxyPass /zm/
        ProxyPassReverse /zm/
        ProxyPass /
        ProxyPassReverse /

ProxyPreserveHost On

10 – Enable ssmtp for sending mail from Zoneminder

docker exec -it Zoneminder /bin/bash 'get into the shell
sudo nano /etc/ssmtp/revaliases 'edit ssmtp options

Add the following below to your revaliases file (change your settings to suit)

		# sSMTP aliases
# Format:	local_account:outgoing_address:mailhub
# Example: root:your_login@your.domain:mailhub.your.domain[:port]
# where [:port] is an optional port number that defaults to 25.

Now edit your ssmtp file.

# Are users allowed to set their own From: address?
# YES - Allow the user to specify their own From: address
# NO - Use the system generated From: address

Test your mail.

sudo echo "Subject: sendmail test" | sendmail -v 'send a test
sudo ln -s /usr/bin/ssmtp /usr/lib/sendmail 'sym link for zm

Still not working as you expect? Check out the log files by running #docker logs -f Zoneminder before you post a comment. Still not working?  Just telling me, ‘it’s not working’, does not provide enough information to troubleshoot your problem. You wouldn’t take your car into the garage and say, “my car doesn’t work!” – you need to give me some clues to help you fix your problem. Check your steps carefully, every command has to be issued as it is shown in the how to. If you find any mistakes please let me know and I will fix them right away.


5 1 vote
Article Rating
Notify of

1 Comment
Oldest Most Voted
Inline Feedbacks
View all comments
Blake Drumm
3 years ago

Thanks for the guide!