How to turn a Raspberry Pi into a surveillance system with ZoneMinder

ZoneMinder is a free and open source closed-circuit television software we can install on our Raspberry Pi (or any other Linux system) to monitor and protect our home, or whatever we deem valuable. ZoneMinder is easy to install, supports a vast selection of cameras, and has also APIs for third party software integration.

In this tutorial we install ZoneMinder on the latest version of Raspberry Pi OS, and learn how to turn our RPI into a surveillance system using a simple USB webcam.

In this tutorial you will learn:

  • How to install ZoneMinder on RaspberryPi OS
  • How to define a monitor and add a video source
How to turn a Raspberry PI into a surveillance system with ZoneMinder
How to turn a Raspberry Pi into a surveillance system with ZoneMinder – Original image by macrovector on Freepik
Software Requirements and Linux Command Line Conventions
Category Requirements, Conventions or Software Version Used
System Raspberry Pi OS or Debian Bookworm
Software ZoneMinder
Other Root privileges
Conventions # – requires given linux-commands to be executed with root privileges either directly as a root user or by use of sudo command
$ – requires given linux-commands to be executed as a regular non-privileged user


ZoneMinder is available in the official repository of Debian 12 Bookworm, and therefore also on the latest version Raspberry Pi OS, which is based on it. The command below installs the “zoneminder” package and all its dependencies, which include Apache and MariaDB:

$ sudo apt-get update && sudo apt-get -y install zoneminder

During this tutorial, I will assume we are setting ZoneMinder inside a Local Area Network (LAN) protected by a router firewall: this is the typical home setup. If you want to be able to access ZoneMinder externally, you should install and configure a VPN (Virtual Private Network) like Wireguard.

Setting up the database

Once ZoneMinder installation is complete, we can create the database. ZoneMinder comes with a SQL script we can use to generate the database and all its tables: /usr/share/zoneminder/db/zm_create.sql. To execute the SQL instructions in the script, we need to log in as the root database user:

$ sudo mysql

We execute the “mysql” command as root because Debian comes with the MariaDB unix_activation_socket plugin active by default. This plugin allows the use of operating system credentials to login into the database. In other words, if the user we execute the “mysql” command as, corresponds to a database user, it is allowed to log in without providing a password. This is considered good for security, because it eliminates the need to store a secret, and relies on the strength of the access to the Unix user.

From the MariaDB console, we source the SQL script:

MariaDB [(none)]> source /usr/share/zoneminder/db/zm_create.sql

By default, ZoneMinder tries to access the database as the “zmuser” user, with “zmpass” as password. Those values are set in the /etc/zm/zm.conf configuration file, and can be changed via the ZM_DB_USER and ZM_DB_PASS variables. Here, for the sake of simplicity, we stick to default values. To create the user and grant it full privileges on the database, we run:

MariaDB [zm]> GRANT ALL PRIVILEGES ON zm.* TO 'zmuser'@'localhost' IDENTIFIED BY 'zmpass';

All done. In the next step, we configure Apache and PHP.

Setting up Apache and PHP

As part of the ZoneMinder installation, an Apache configuration is automatically installed as /etc/apache2/conf-available/zoneminder.conf. To activate it, we run:

$ sudo a2enconf zoneminder.conf

We must also enable required modules:

$ sudo a2enmod rewrite headers expires cgi

Finally, we must ensure the Apache web server is able to read ZoneMinder configuration file, by changing the file group ownership to “www-data” (the user and primary group of the Apache web server):

$ sudo chgrp www-data /etc/zm/zm.conf

To ensure the PHP timezone is the same as the one used by the system, which in my case is “Europe/Rome”, we edit the /etc/php/8.2/apache2/php.ini file, and, under line 979, we add the appropriate entry:

; Defines the default timezone used by the date functions
date.timezone = Europe/Rome

Finally, we restart Apache:

$ sudo systemctl restart apache2

Starting the zoneminder service

For the sake of this article, we will use a local USB webcam as a video source. For this to work, we need to add the www-data user to the “video” group, which owns the /dev/video0 device:

$ sudo usermod -aG video www-data

Finally, we can start and enable the “zoneminder” service:

$ sudo systemctl enable --now zoneminder.service

Accessing the web interface

Once the “zoneminder” service is up and running, we should be able to reach its web interface by opening our browser and navigating to the <SERVER_IP>/zm address. The first time we access the page, we will see a privacy disclaimer with information about the telemetry data collected:

ZoneMinder privacy disclaimer
ZoneMinder privacy disclaimer

The project is open source, and doesn’t collect images from cameras. Anyway, if we don’t want to accept telemetry, we can select “decline” in the dropdown menu at the bottom of the page. To confirm our choice, we click on the “APPLY” button on the right:

As soon as we do it, we will be redirected to the ZoneMinder dashboard:

ZoneMinder dashboard
ZoneMinder dashboard

Defining a monitor and adding a video source

We are not going to delve into the ZoneMinder application details here; we will just see how to add a local video source. To configure a “monitor”, we click on the “ADD” button in the ZoneMinder dashboard; in the “General” page form, we set the “Source Type” to “Local”:

Monitor general settings
Monitor general settings

ZoneMinder can work in different modes. In this case, we chose the “Record” function: it allows us to stream the video and records it to disk, without enabling motion detection. To get to know the other ZoneMinder modes, take a look at the official documentation.

Now, to configure the video source, we click “Source” in the left vertical menu. In the “Capture Method” form, we provide the path of the video device, its format and resolution. When ready, we click on the “Save” button:

Setting up the video source
Setting up the video source

We will be redirected to the dashboard. If everything goes as expected, the capturing process should start. We should be able to visualize a thumbnail of the current scene:

The monitor preview
The monitor preview

By clicking on it, we can reach the stream page:

Nothing interesting, just a printer
Nothing interesting, just a printer.

Closing thoughts

ZoneMinder is a free and open source closed-circuit television software. In this tutorial, we learned how to install it on the latest version of Raspberry Pi OS, and how to create a surveillance system by using a simple USB webcam. In the article, I assumed the use of ZoneMinder in a protected LAN; in order to access the video stream externally, setting up a VPN is highly recommended. I absolutely discourage exposing the web service directly in this case, even using SSL encryption, since, in order to access the local video source, the www-data user is made part of the “video” group, so it has additional access to system resources.

Comments and Discussions
Linux Forum