Best and most secure way to expose Zoneminder with Caddy server

Forum for questions and support relating to the 1.32.x releases only.
Post Reply
royduin
Posts: 4
Joined: Mon Dec 17, 2018 5:09 pm

Best and most secure way to expose Zoneminder with Caddy server

Post by royduin »

Hi guys,

I'm running Zoneminder currently with Apache on Ubuntu, to secure it I've enabled basic authentication but that wasn't working with zmNinja so I've followed these steps: https://github.com/pliablepixels/zmNinj ... h-zms-urls. Working great, but I'm also running Home Assistant on the same server and like to expose that also (so I can access it from the internet) but I don't like to use Apache. Nginx is possible but came across Caddy server and want to go that way. Mainly because of the automatic HTTPS and the simplicity.

I could try to migrate the Apache config (or one of the many Nginx configs in the wiki and on the forums, why so many differences?) to a Caddy config but maybe someone did this already? Another option is to run Caddy as proxy in front of Apache but why should I run two webservers when just one can handle it all?

My other question is; is basic authentication the way to go? I came across this wiki: https://github.com/pliablepixels/zmNinj ... -ProxyPass, it looks like that's now the best way to set things up securely but that's for Apache Zoneminder does also have a build in authentication option. Is that really secure? Maybe that's a better option?

I hope you guys can give me some advice.
The-mop
Posts: 1
Joined: Mon Feb 24, 2025 11:35 am

Re: Best and most secure way to expose Zoneminder with Caddy server

Post by The-mop »

Tested on Ubuntu Nobel 24/2/2025

Useful stuff:

journalctl -u caddy --no-pager | less +G

ps aux | grep caddy



sudo apt install mysql-server

sudo mysql_secure_installation

Choose password below by password

sudo mysql

ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password by 'password';

exit



https://zoneminder.readthedocs.io/en/la ... buntu.html

For this one we are using the master branch

sudo apt-get update && sudo apt upgrade -y
sudo apt install -y software-properties-common
sudo add-apt-repository ppa:iconnor/zoneminder-master
sudo apt update
sudo apt install zoneminder -y

Warning this will uninstall apache, it can be skipped, but if you leave apache2 make sure port 80 is not being used

sudo apt purge apache2



sudo apt-get install devscripts

wget https://raw.githubusercontent.com/ZoneM ... package.sh

chmod a+x do_debian_package.sh

sudo apt-get update

./do_debian_package.sh --snapshot=NOW --branch=master --type=local



N.B should change database user and pass below

cd zoneminder_release

cmake -DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_SKIP_RPATH=ON \
-DCMAKE_VERBOSE_MAKEFILE=OFF \
-DCMAKE_COLOR_MAKEFILE=ON \
-DZM_DB_USER=zmusercaddy \
-DZM_DB_PASS=zmpasscaddy \
-DZM_DB_NAME=zm \
-DZM_RUNDIR=/run/zm \
-DZM_SOCKDIR=/run/zm \
-DZM_TMPDIR=/var/tmp/zm \
-DZM_LOGDIR=/var/log/zm \
-DZM_WEBDIR=/usr/share/zoneminder/www \
-DZM_CONTENTDIR=/var/cache/zoneminder \
-DZM_CACHEDIR=/var/cache/zoneminder/cache \
-DZM_CGIDIR=/usr/lib/zoneminder/cgi-bin \
-DZM_PATH_ZMS=/zm/cgi-bin/nph-zms \
-DZM_DIR_EVENTS=/var/cache/zoneminder/events \
-DZM_WEB_USER=caddy \
-DZM_WEB_GROUP=caddy \
-DCMAKE_INSTALL_SYSCONFDIR=etc/zm \
-DZM_CONFIG_DIR=/etc/zm \
-DCMAKE_BUILD_TYPE=Debug .

make

sudo make install

cd misc

make

sudo make install

sudo mv zoneminder-tmpfiles.conf /usr/lib/tmpfiles.d/zoneminder.conf

This mv sets the ownership and permissions for the /run/zm pid and camera sockets

cd ../
cd db

mysql -u root -p

DROP DATABASE zm;

DROP USER 'zmuser'@'localhost';

exit

mysql -u root -p < ./zm_create.sql

mysql -u root -p

CREATE USER 'zmusercaddy'@'localhost' IDENTIFIED WITH mysql_native_password by 'zmpasscaddy';

GRANT ALL PRIVILEGES ON zm.* TO 'zmusercaddy'@'localhost' WITH GRANT OPTION;

FLUSH PRIVILEGES;

exit



sudo apt install php8.3-fpm

sudo apt install gedit

sudo cp /etc/php/8.3/fpm/pool.d/www.conf /etc/php/8.3/fpm/pool.d/caddy.conf

sudo gedit /etc/php/8.3/fpm/pool.d/caddy.conf

Change pool name and others like below and save

[caddy]
user = caddy
group = caddy

listen.owner = caddy
listen.group = caddy

listen = /run/php/php8.3-caddy.sock



sudo gedit /etc/php/8.3/fpm/php.ini

Search, uncomment and save, you might want to google what these session settings do, but i think they should be on if you are going to expose zoneminder online over https

date.timezone = Australia/Perth
session.cookie_secure = 1
session.cookie_httponly = 1



https://go.dev/doc/install

Download Go zip form go

cd ~/Downloads

sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.24.0.linux-amd64.tar.gz

sudo nano ~/.bashrc

Add to bottom

export PATH=$PATH:/usr/local/go/bin

Save and open new terminal

Check

go version



https://caddyserver.com/docs/build#pack ... turaspbian

sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/s ... an.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddy

sudo mkdir /var/lib/caddy

sudo chown -R caddy:caddy /var/lib/caddy

sudo caddy trust

sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/xcaddy/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-xcaddy-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/x ... an.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-xcaddy.list
sudo apt update
sudo apt install xcaddy

xcaddy build --with=github.com/aksdb/caddy-cgi/v2

sudo dpkg-divert --divert /usr/bin/caddy.default --rename /usr/bin/caddy
sudo mv ./caddy /usr/bin/caddy.custom
sudo update-alternatives --install /usr/bin/caddy caddy /usr/bin/caddy.default 10
sudo update-alternatives --install /usr/bin/caddy caddy /usr/bin/caddy.custom 50

You can change between the custom and default caddy binaries by executing the below, and following the on screen information. Then, restart the Caddy service.

sudo update-alternatives --config caddy

sudo systemctl restart caddy



sudo nano /etc/caddy/Caddyfile

{
debug
order cgi before respond
}

zone.localhost {
root * /usr/share/zoneminder/www
log
redir / /zm 301
header {
Permissions-Policy interest-cohort=()
Strict-Transport-Security max-age=31536000;
X-Content-Type-Options nosniff
X-Frame-Options DENY
}
handle_errors {
respond "{err.status_code} {err.status_text}"
}
handle_path /cache/* {
root * /var/cache/zoneminder/cache
}
cgi /zm/cgi-bin/nph-zms /usr/lib/zoneminder/cgi-bin/nph-zms {
unbuffered_output
}
php_fastcgi unix//run/php/php8.3-caddy.sock
file_server
}



sudo mkdir /etc/systemd/system/zoneminder.service.d

sudo nano /etc/systemd/system/zoneminder.service.d/override.conf

[Service]
User=caddy



sudo chown -R caddy:caddy /usr/share/zoneminder
sudo chown -R caddy:caddy /var/cache/zoneminder
sudo chown -R caddy:caddy /var/log/zm
sudo chown caddy:caddy /etc/zm/zm.conf
sudo chmod 740 /etc/zm/zm.conf
sudo adduser caddy video



sudo cp -r /usr/share/zoneminder/www/fonts /usr/share/zoneminder/www/skins/classic/css/fonts

Reboot the computer



sudo systemctl daemon-reload
sudo systemctl enable zoneminder
sudo systemctl enable caddy
sudo systemctl start zoneminder
sudo systemctl start caddy



Extra; Iphone presence detection
Change the home /home/dan bit
Change the user pass bit
Change the MAC Address bit
You might need to change the --interface=eno1 one bit your own network adaptor

Ifconfig

The state matches a state created in zoneminder
You do need to change the Iphone wireless settings to be a fixed MAC Address

sudo apt install arp-scan

nano config.cnf

[client]
user = "zmusercaddy"
password = "zmpasscaddy"
host = "localhost"

nano home.sh

#!/bin/bash

STATE=$(mysql --defaults-extra-file=/home/dan/config.cnf --skip-column-names zm -e 'SELECT Name FROM `States` WHERE IsActive=1')

MAC_DAN_ROOM="********"

MAC_TYSON_HOUSE="**********"

for RUN in {1..5}; do
TEST+=$(arp-scan --interface=eno1 --localnet --destaddr=$MAC_DAN_ROOM | grep $MAC_DAN_ROOM | awk '{print $2 "\t"}') ;
TEST+=$(arp-scan --interface=eno1 --localnet --destaddr=$MAC_TYSON_HOUSE | grep $MAC_TYSON_HOUSE | awk '{print $2 "\t"}') ;
done

if [ ! -z "${TEST}" ] && [ "${STATE}" != "off" ]; then
/usr/bin/zmpkg.pl off
exit 0
fi

if [ -z "${TEST}" ] && [ "${STATE}" != "motion" ]; then
/usr/bin/zmpkg.pl motion
fi

sudo mv home.sh /home/dan/home.sh

cd /home/dan

sudo chmod +x home.sh

sudo crontab -e

MAILTO=""

*/5 * * * * bash /home/dan/home.sh



Extra; Email body for a motion filter, fixes images on Iphone

https://wiki.zoneminder.com/How_to_get_ ... Zoneminder

<!DOCTYPE html>
<html>
<head>
<title>ZoneMinder: Alarm - %MN%-%EI%</title>
</head>
<body>

<h1>ZM alarm detected</h1>
<p> %MN%</p>
<p> %ET% </p>
%EIMA%

</body>
</html>



So if anyone else has improvements please share
Post Reply