Programster's Blog

Tutorials focusing on Linux, programming, and open-source

Ubuntu 22.04 - Install Zoneminder

Zoneminder is an open source web application that can be used for connecting to cameras (in my case network "IP" cameras), and setting up various security scenarios, such as automatic recording whenever motion is detected in a specific zone at certain times etc.

This tutorial will show you how install and configure Zoneminder 1.36 on an Ubuntu 22.04 server. Hopefully in the near future we will use Docker to make this much simpler, as there are quite a few steps and configurations.

Table Of Contents

  1. Requirements
  2. Install MySQL Server
    1. Setting SQL Mode
  3. Install Zoneminder
  4. Configure Apache
  5. Set Timezones
    1. Set Host TImezone
    2. Initialize Database
    3. Specify Timezone
  6. Freshen Zoneminder Database Configuration
  7. Optional Extra Steps
    1. Change Zoneminder Database Password
    2. Store Events On Separate Drive
  8. Start Zoneminder
  9. Testing
  10. Conclusion
  11. Appendix
    1. Initialize Database
  12. References

Requirements

  • CPU: The handling of multiple camera input streams and the corresponding image processing for motion detection, can take quite a bit of CPU horsepower. Luckily this works across multiple cores, so this is ideal for something like a Ryzen 5/7 CPU with 6+ cores.

  • Networking: For the best performance and quality, you will want to use Gigabit networking between your cameras and the computer running Zoneminder. I used a Netgear POE switch to power the cameras over the gigabit connection which made them easier to deploy around the outside of the house. If you are just using one Wifi camera with a moderate to low resolution, you will probably be fine with Wifi, especially if its a good 5Ghz signal.

Install MySQL Server

Zoneminder requires a MySQL or MariaDB server. For this tutorial, I am going to install MariaDB 10 onto this server, from the Ubuntu repositories. Alternatively, you could deploy or use an existing MySQL/MariaDB server on another node and hook Zoneminder up to that later.

Installing MySQL server is as easy as....

sudo apt-get install mariadb-server-10.6 -y

Setting SQL Mode - No Engine Substitution

Unfortunately, Zoneminder requires the sql_mode to have NO_ENGINE_SUBSTITUTION. Luckily for us, the stock installation of MariaDB 10 on Ubuntu 22 has this in the SQL mode, so if you followed the steps above, there is nothing you need to do here. However, sometimes people may choose to use a remote database they have already set up, so it is worth knowing how to check, and how to configure this just in case.

Check SQL Mode

To check the SQL mode, log into the database and run:

select @@sql_mode;

This should output something like:

+-------------------------------------------------------------------------------------------+
| @@sql_mode                                                                                |
+-------------------------------------------------------------------------------------------+
| STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |
+-------------------------------------------------------------------------------------------+
1 row in set (0.000 sec)

Configure SQL Mode

If you didn't see NO_ENGINE_SUBSTITUTION in the output, then you need to add the following line to the /etc/mysql/mariadb.conf.d/50-server.cnf or appropriate to your database (might be a different path if you installed MySQL rather than MariaDB.

editor /etc/mysql/mariadb.conf.d/50-server.cnf

I like to add the following line (if there isn't already one for setting the sql_mode, somewhere in the fine tuning section, but the important thing is that it is underneath the [mysqld] and before the next [somethingHere] that defines another section. (TOML format).

sql_mode = STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION

For the change to take effect, you will need to restart the MySQL service like so:

sudo service mysql restart

Install Zoneminder

For this tutorial, we are going to install Zoneminder from Isaac Conor's PPA.

sudo apt update \
  && sudo apt install software-properties-common software-properties-common -y \
  && sudo add-apt-repository ppa:iconnor/zoneminder-1.36 -y \
  && sudo apt update \
  && sudo apt install zoneminder -y

Configure Apache

After having installed Zoneminder, we need to get it configured to play with Apache by enabling the zoneminder virtual host configuration and setting the file permissions as required.

sudo chmod 740 /etc/zm/zm.conf \
  && sudo chown root:www-data /etc/zm/zm.conf \
  && sudo chown --recursive www-data:www-data /usr/share/zoneminder/ \
  && sudo a2enconf zoneminder

Then we need to enable CGI and rewrite mods in Apache before restarting the service for the changes to take effect.

sudo a2enmod cgi \
  && sudo a2enmod rewrite  \
  && sudo a2enmod expires \
  && sudo a2enmod headers \
  && sudo systemctl reload apache2

Set Timezones

Set Host TImezone

Set the timezone on the host by running:

sudo dpkg-reconfigure tzdata

Set Database Timezone

The database will default to UTC timezone, so to set it to something different one needs to perform the following steps:

Import the timezone info into the database:

mysql_tzinfo_to_sql /usr/share/zoneinfo | sudo mysql -u root mysql

Now edit the /etc/mysql/mariadb.conf.d/50-server.cnf config file:

sudo editor /etc/mysql/mariadb.conf.d/50-server.cnf

Find the [mysqld] section header and append the following underneath it:

default-time-zone = "Europe/London"
sudo service mysql restart

These steps can also be found here.

Set PHP Timezone

Finally, Zoneminder needs us to specify the timezone to use in the PHP.ini configuration filein the PHP.ini

sudo editor /etc/php/8.1/apache2/php.ini

Find the commented-out line:

;date.timezone =

... and replace it with your timezone. I am going to use the London Timezone (here is a nice list of timezone labels to refer to):

date.timezone = "Europe/London"

Freshen Zoneminder Database Configuration

Run the following command/script to "freshen" Zoneminder configuration in the database (reference). Without this, I found that I had undefined configuration variable defines, and Zoneminder would fail silently, resulting in Apache serving up a blank page with a 500 HTTP status code.

sudo /usr/bin/zmupdate.pl --freshen

Optional Extra Steps

Change Zoneminder Database Password

In older tutorials for setting up zoneminder, one had to manually initialize the database. This is also useful to know, should you lose access to your database and need to set it up again. Here is what you would need to do:

sudo mysql -e \
"grant select,insert,update,delete,create,alter,index,lock tables on zm.* to 'zmuser'@localhost identified by 'useRandomPasswordHere';"

Update the ZM_DB_PASS variable in the /etc/zm/zm.cnf file, to the database password you just set.

Store Events On Separate Drive

If you're like me, you want to store all the captured video footage on cheap HDD storage rather than your boot drive's SSD. This is easy enough to configure with symlinks.

The default setup will have Zoneminder write events to /var/cache/zoneminder/events. This means we can easily just change the pointer to wherever our hard drive is mounted to. In my case, I am using an NFS at /mnt/nfs so I will do:

NEW_LOCATION="/mnt/nfs/zoneminder/events"

sudo mkdir -p $NEW_LOCATION \
  && sudo rm -rf /var/cache/zoneminder/events \
  && sudo mkdir -p $NEW_LOCATION \
  && sudo chown --recursive www-data:www-data $NEW_LOCATION \
  && sudo ln -s $NEW_LOCATION /var/cache/zoneminder/events

It is important that www-data is the owner of this new folder, which gives it the ability to create and manage the files in that location.

sudo chown www-data:www-data -R /mnt/nfs

You can also repeat the steps above for images and temp but these should not require as much storage.

Start Zoneminder

Run the following commands to start zoneminder and configure it to automatically start on boot:

sudo systemctl start zoneminder.service \
  sudo systemctl enable zoneminder.service

Testing

You should now be able to go to your node's hostname or IP address in your browser and see the zoneminder web application. From this point on, you probably want to add some cameras, and setup authentication.

Conclusion

The UI looks a bit dated and could really do with implementing bootstrap, but it's pretty darn good functionally.

Appendix

Initialize Database

In older tutorials for setting up zoneminder, one had to manually initialize the database. This is also useful to know, should you lose access to your database and need to set it up again. Here is what you would need to do:

mysql -uroot -p < /usr/share/zoneminder/db/zm_create.sql

sudo mysql -e \
"grant select,insert,update,delete,create,alter,index,lock tables on zm.* to 'zmuser'@localhost identified by 'useRandomPasswordHere';"

References

Last updated: 19th March 2023
First published: 19th March 2023

This blog is created by Stuart Page

I'm a freelance web developer and technology consultant based in Surrey, UK, with over 10 years experience in web development, DevOps, Linux Administration, and IT solutions.

Need support with your infrastructure or web services?

Get in touch