I'm trying to run ZoneMinder in my PC since I want to manage my IP camera through ZoneMinder. My operating system is Debian bookworm. I followed the instalation steps at https://wiki.zoneminder.com/Debian_12_B ... and_1.37.x, basically the suggested script in that website. So I now have ZoneMinder version 1.36.35~20241022.27-bookworm installed.
But I can't access the web interface via http://hostname_or_ip/zm. What I get is a text result in the browser, either in firefox or in chromium.
Here are some outputs in case it would help to narrow down my issue:
Code: Select all
dpkg -s zoneminder
Package: zoneminder
Status: install ok installed
Priority: optional
Section: net
Installed-Size: 33559
Maintainer: Isaac Connor <isaac@zoneminder.com>
Architecture: amd64
Version: 1.36.35~20241022.27-bookworm
Depends: libavcodec59 (>= 7:5.0), libavformat59 (>= 7:5.0), libavutil57 (>= 7:5.1), libc6 (>= 2.34), libgcc-s1 (>= 3.0), libgcrypt20 (>= 1.10.0), libgnutls30 (>= 3.7.0), libjpeg62-turbo (>= 1.3.1), libjwt-gnutls0 (>= 1.9.0), libmariadb3 (>= 3.0.0), libpcre3, libstdc++6 (>= 12), libswresample4 (>= 7:5.1), libswscale6 (>= 7:5.0), zlib1g (>= 1:1.1.4), perl:any, javascript-common, ffmpeg, libdate-manip-perl, libmime-lite-perl, libmime-tools-perl, libdbd-mysql-perl, libphp-serialization-perl, libmodule-load-conditional-perl, libnet-sftp-foreign-perl, libarchive-zip-perl, libdevice-serialport-perl, libimage-info-perl, libio-interface-perl, libjson-maybexs-perl, libsys-mmap-perl, liburi-encode-perl, libwww-perl, liburi-perl, libdata-dump-perl, libdatetime-perl, libclass-std-fast-perl, libsoap-wsdl-perl, libio-socket-multicast-perl, libdigest-sha-perl, libsys-cpu-perl, libsys-meminfo-perl, libdata-uuid-perl, libnumber-bytes-human-perl, libfile-slurp-perl, default-mysql-client | mariadb-client | virtual-mysql-client, php-mysql, php-gd, php-apcu, php-json, php-intl, policykit-1, rsyslog | system-log-daemon, zip, libcrypt-eksblowfish-perl, libdata-entropy-perl, libvncclient1 | libvncclient0
Recommends: apache2 (>= 2.4.6-4~) | nginx | httpd, libapache2-mod-php | php-fpm, default-mysql-server | mariadb-server | virtual-mysql-server, zoneminder-doc (>= 1.36.35~20241022.27-bookworm)
Suggests: fcgiwrap, logrotate
Conffiles:
/etc/apache2/conf-available/zoneminder.conf 845925cd0e008e93c0850b9f5236db82
/etc/init.d/zoneminder bb12d862700881828f722c477ef271c1
/etc/logrotate.d/zoneminder 94a48a435af9434bea71b00802e7a5d9
/etc/zm/conf.d/01-system-paths.conf 934bbdf926fdc4c9b5167028e134f70a
/etc/zm/conf.d/02-multiserver.conf af136258d51fdb551b50d39f4f563cd9
/etc/zm/conf.d/README 15fa271f6d59fd553c7e282ddd502898
/etc/zm/zm.conf 21d5c0e3b2c2337aae600ffa4429152a
Description: video camera security and surveillance solution
ZoneMinder is intended for use in single or multi-camera video security
applications, including commercial or home CCTV, theft prevention and child
or family member or home monitoring and other care scenarios. It
supports capture, analysis, recording, and monitoring of video data coming
from one or more video or network cameras attached to a Linux system.
ZoneMinder also support web and semi-automatic control of Pan/Tilt/Zoom
cameras using a variety of protocols. It is suitable for use as a home
video security system and for commercial or professional video security
and surveillance. It can also be integrated into a home automation system
via X.10 or other protocols.
Homepage: https://www.zoneminder.com/
Code: Select all
sudo systemctl enable zoneminder
sudo service zoneminder start
sudo adduser www-data video
sudo a2enconf zoneminder
sudo a2enmod rewrite
sudo a2enmod headers
sudo a2enmod expires
sudo service apache2 reload
Here is the same in text format. It is shown as a long and continuos text:
Code: Select all
setPatter(ZM_DATE_FORMAT_PATTERN); } if (ZM_DATETIME_FORMAT_PATTERN) { $dateTimeFormatter->setPattern(ZM_DATETIME_FORMAT_PATTERN); } if (ZM_TIME_FORMAT_PATTERN) { $timeFormatter->setPattern(ZM_TIME_FORMAT_PATTERN); } require_once('includes/session.php'); require_once('includes/logger.php'); require_once('includes/Server.php'); // Useful debugging lines for mobile devices if ( 0 and ZM\Logger::fetch()->debugOn() ) { ob_start(); phpinfo(INFO_VARIABLES); ZM\Debug(ob_get_contents()); ob_end_clean(); } global $Servers; $Servers = ZM\Server::find(); if ( (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') or (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) and ($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')) ) { $protocol = 'https'; } else { $protocol = 'http'; } define('ZM_BASE_PROTOCOL', $protocol); // Absolute URL's are unnecessary and break compatibility with reverse proxies // define( "ZM_BASE_URL", $protocol.'://'.$_SERVER['HTTP_HOST'] ); // Use relative URL's instead define('ZM_BASE_URL', ''); require_once('includes/functions.php'); if ( $_SERVER['REQUEST_METHOD'] == 'OPTIONS' ) { ZM\Debug('OPTIONS Method, only doing CORS'); # Add Cross domain access headers CORSHeaders(); return; } if ( isset($_GET['skin']) ) { $skin = $_GET['skin']; } else if ( isset($_COOKIE['zmSkin']) ) { $skin = $_COOKIE['zmSkin']; } else if ( defined('ZM_SKIN_DEFAULT') ) { $skin = ZM_SKIN_DEFAULT; } else { $skin = 'classic'; } if (!is_dir('skins/'.$skin) ) { $skins = array_map('basename', glob('skins/*', GLOB_ONLYDIR)); if ( !in_array($skin, $skins) ) { ZM\Error("Invalid skin '$skin' setting to ".$skins[0]); $skin = $skins[0]; } } global $css; if ( isset($_GET['css']) ) { $css = $_GET['css']; } else if ( isset($_COOKIE['zmCSS']) ) { $css = $_COOKIE['zmCSS']; } else if ( defined('ZM_CSS_DEFAULT') ) { $css = ZM_CSS_DEFAULT; } else { $css = 'classic'; } if (!is_dir("skins/$skin/css/$css")) { $css_skins = array_map('basename', glob('skins/'.$skin.'/css/*', GLOB_ONLYDIR)); if (count($css_skins)) { if (!in_array($css, $css_skins)) { ZM\Error("Invalid skin css '$css' setting to " . $css_skins[0]); $css = $css_skins[0]; if (isset($_COOKIE['zmCSS'])) { unset($_COOKIE['zmCSS']); setcookie('zmCSS', '', time() - 3600); } } else { $css = ''; } } else { ZM\Error("No css options found at skins/$skin/css"); $css = ''; } } define('ZM_BASE_PATH', dirname($_SERVER['REQUEST_URI'])); define('ZM_SKIN_PATH', "skins/$skin"); define('ZM_SKIN_NAME', $skin); $skinBase = array(); // To allow for inheritance of skins if (!file_exists(ZM_SKIN_PATH)) ZM\Fatal("Invalid skin '$skin'"); $skinBase[] = $skin; zm_session_start(); if ( !isset($_SESSION['skin']) || isset($_REQUEST['skin']) || !isset($_COOKIE['zmSkin']) || ($_COOKIE['zmSkin'] != $skin) ) { $_SESSION['skin'] = $skin; zm_setcookie('zmSkin', $skin); } if ( !isset($_SESSION['css']) || isset($_REQUEST['css']) || !isset($_COOKIE['zmCSS']) || ($_COOKIE['zmCSS'] != $css) ) { $_SESSION['css'] = $css; zm_setcookie('zmCSS', $css); } # Add Cross domain access headers CORSHeaders(); // Check for valid content dirs if ( !is_writable(ZM_DIR_EVENTS) ) { ZM\Warning("Cannot write to event folder ".ZM_DIR_EVENTS.". Check that it exists and is owned by the web account user."); } # Globals # Running is global but only do the daemonCheck if it is actually needed $running = null; $action = null; $error_message = null; $redirect = null; $view = isset($_REQUEST['view']) ? detaintPath($_REQUEST['view']) : null; $user = null; $request = isset($_REQUEST['request']) ? detaintPath($_REQUEST['request']) : null; require_once('includes/auth.php'); # Only one request can open the session file at a time, so let's close the session here to improve concurrency. # Any file/page that sets session variables must re-open it. session_write_close(); require_once('includes/Storage.php'); require_once('includes/Event.php'); require_once('includes/Group.php'); require_once('includes/Monitor.php'); // lang references $user[Language] so must come after auth require_once('includes/lang.php'); foreach ( getSkinIncludes('skin.php') as $includeFile ) { require_once $includeFile; } if (isset($_POST['action'])) { # Actions can only be performed on POST because we don't check csrf on GETs. $action = detaintPath($_POST['action']); } else if (isset($_REQUEST['action']) and $_REQUEST['action'] and empty($_REQUEST['request'])) { ZM\Error('actions can no longer be performed without POST. Requested: '.$_REQUEST['action']. ' for ' .$view); } # The only variable we really need to set is action. The others are informal. isset($view) || $view = NULL; isset($request) || $request = NULL; isset($action) || $action = NULL; if ( (!$view and !$request) or ($view == 'console') ) { check_timezone(); } ZM\Debug("View: $view Request: $request Action: $action User: " . ( isset($user) ? $user['Username'] : 'none' )); if ( ZM_ENABLE_CSRF_MAGIC && ( $action != 'login' ) && ( $view != 'view_video' ) && // only video no html ( $view != 'image' ) && // view=image doesn't return html, just image data. ( $request != 'control' ) && //( $view != 'frames' ) && // big html can overflow ob ( $view != 'archive' ) // returns data && ( (!isset($_SERVER['CONTENT_TYPE']) or ($_SERVER['CONTENT_TYPE'] != 'application/csp-report')) ) ) { require_once('includes/csrf/csrf-magic.php'); #ZM\Debug("Calling csrf_check with the following values: \$request = \"$request\", \$view = \"$view\", \$action = \"$action\""); csrf_check(); } # If I put this here, it protects all views and popups, but it has to go after actions.php because actions.php does the actual logging in. if ( ZM_OPT_USE_AUTH and (!isset($user)) and ($view != 'login') and ($view != 'none') ) { if ($request) { # requests only return json header('HTTP/1.1 401 Unauthorized'); exit; } $view = 'none'; $redirect = ZM_BASE_URL.$_SERVER['PHP_SELF'].'?view=login'; zm_session_start(); $_SESSION['postLoginQuery'] = $_SERVER['QUERY_STRING']; session_write_close(); } else if ( ZM_SHOW_PRIVACY && ($view != 'privacy') && ($view != 'options') && (!$request) && canEdit('System') ) { $view = 'none'; $redirect = ZM_BASE_URL.$_SERVER['PHP_SELF'].'?view=privacy'; $request = null; } # Need to include actions because it does auth if ( $action and $view and !$request ) { if ( file_exists('includes/actions/'.$view.'.php') ) { require_once('includes/actions/'.$view.'.php'); } else { ZM\Debug("No includes/actions/$view.php for action $action"); } } if ( isset($_REQUEST['redirect']) ) { $redirect = '?view='.detaintPath($_REQUEST['redirect']); } if ($redirect) { ZM\Debug("Redirecting to $redirect"); header('Location: '.$redirect); return; } if ( $request ) { foreach ( getSkinIncludes('ajax/'.$request.'.php', true, true) as $includeFile ) { if ( !file_exists($includeFile) ) ZM\Fatal("Request '$request' does not exist"); require_once $includeFile; } return; } # Add CSP Headers $cspNonce = bin2hex(zm_random_bytes(16)); if ( $includeFiles = getSkinIncludes('views/'.$view.'.php', true, true) ) { ob_start(); CSPHeaders($view, $cspNonce); foreach ( $includeFiles as $includeFile ) { if (!file_exists($includeFile)) { ZM\Error("View '$view' does not exist, redirecting to console"); header('Location: ?view=console'); return; } require_once $includeFile; } // If the view overrides $view to 'error', and the user is not logged in, then the // issue is probably resolvable by logging in, so provide the opportunity to do so. // The login view should handle redirecting to the correct location afterward. if ( $view == 'error' && !isset($user) ) { $view = 'login'; foreach ( getSkinIncludes('views/login.php', true, true) as $includeFile ) require_once $includeFile; } while (ob_get_level() > 0) ob_end_flush(); } # end if include files for view // If the view is missing or the view still returned error with the user logged in, // then it is not recoverable. if ( !$includeFiles || $view == 'error' ) { foreach ( getSkinIncludes('views/error.php', true, true) as $includeFile ) require_once $includeFile; } ?>
Code: Select all
setPatter(ZM_DATE_FORMAT_PATTERN);
}
if (ZM_DATETIME_FORMAT_PATTERN) {
$dateTimeFormatter->setPattern(ZM_DATETIME_FORMAT_PATTERN);
}
if (ZM_TIME_FORMAT_PATTERN) {
$timeFormatter->setPattern(ZM_TIME_FORMAT_PATTERN);
}
require_once('includes/session.php');
require_once('includes/logger.php');
require_once('includes/Server.php');
// Useful debugging lines for mobile devices if ( 0 and ZM\Logger::fetch()->debugOn() ) {
ob_start();
phpinfo(INFO_VARIABLES);
ZM\Debug(ob_get_contents());
ob_end_clean();
}
global $Servers;
$Servers = ZM\Server::find();
if ( (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') or (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) and ($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')) ) {
$protocol = 'https';
}
else {
$protocol = 'http';
}
define('ZM_BASE_PROTOCOL', $protocol);
// Absolute URL's are unnecessary and break compatibility with reverse proxies // define( "ZM_BASE_URL", $protocol.'://'.$_SERVER['HTTP_HOST'] );
// Use relative URL's instead define('ZM_BASE_URL', '');
require_once('includes/functions.php');
if ( $_SERVER['REQUEST_METHOD'] == 'OPTIONS' ) {
ZM\Debug('OPTIONS Method, only doing CORS');
# Add Cross domain access headers CORSHeaders();
return;
}
if ( isset($_GET['skin']) ) {
$skin = $_GET['skin'];
}
else if ( isset($_COOKIE['zmSkin']) ) {
$skin = $_COOKIE['zmSkin'];
}
else if ( defined('ZM_SKIN_DEFAULT') ) {
$skin = ZM_SKIN_DEFAULT;
}
else {
$skin = 'classic';
}
if (!is_dir('skins/'.$skin) ) {
$skins = array_map('basename', glob('skins/*', GLOB_ONLYDIR));
if ( !in_array($skin, $skins) ) {
ZM\Error("Invalid skin '$skin' setting to ".$skins[0]);
$skin = $skins[0];
}
}
global $css;
if ( isset($_GET['css']) ) {
$css = $_GET['css'];
}
else if ( isset($_COOKIE['zmCSS']) ) {
$css = $_COOKIE['zmCSS'];
}
else if ( defined('ZM_CSS_DEFAULT') ) {
$css = ZM_CSS_DEFAULT;
}
else {
$css = 'classic';
}
if (!is_dir("skins/$skin/css/$css")) {
$css_skins = array_map('basename', glob('skins/'.$skin.'/css/*', GLOB_ONLYDIR));
if (count($css_skins)) {
if (!in_array($css, $css_skins)) {
ZM\Error("Invalid skin css '$css' setting to " . $css_skins[0]);
$css = $css_skins[0];
if (isset($_COOKIE['zmCSS'])) {
unset($_COOKIE['zmCSS']);
setcookie('zmCSS', '', time() - 3600);
}
}
else {
$css = '';
}
}
else {
ZM\Error("No css options found at skins/$skin/css");
$css = '';
}
}
define('ZM_BASE_PATH', dirname($_SERVER['REQUEST_URI']));
define('ZM_SKIN_PATH', "skins/$skin");
define('ZM_SKIN_NAME', $skin);
$skinBase = array();
// To allow for inheritance of skins if (!file_exists(ZM_SKIN_PATH)) ZM\Fatal("Invalid skin '$skin'");
$skinBase[] = $skin;
zm_session_start();
if ( !isset($_SESSION['skin']) || isset($_REQUEST['skin']) || !isset($_COOKIE['zmSkin']) || ($_COOKIE['zmSkin'] != $skin) ) {
$_SESSION['skin'] = $skin;
zm_setcookie('zmSkin', $skin);
}
if ( !isset($_SESSION['css']) || isset($_REQUEST['css']) || !isset($_COOKIE['zmCSS']) || ($_COOKIE['zmCSS'] != $css) ) {
$_SESSION['css'] = $css;
zm_setcookie('zmCSS', $css);
}
# Add Cross domain access headers CORSHeaders();
// Check for valid content dirs if ( !is_writable(ZM_DIR_EVENTS) ) {
ZM\Warning("Cannot write to event folder ".ZM_DIR_EVENTS.". Check that it exists and is owned by the web account user.");
}
# Globals # Running is global but only do the daemonCheck if it is actually needed $running = null;
$action = null;
$error_message = null;
$redirect = null;
$view = isset($_REQUEST['view']) ? detaintPath($_REQUEST['view']) : null;
$user = null;
$request = isset($_REQUEST['request']) ? detaintPath($_REQUEST['request']) : null;
require_once('includes/auth.php');
# Only one request can open the session file at a time, so let's close the session here to improve concurrency. # Any file/page that sets session variables must re-open it. session_write_close();
require_once('includes/Storage.php');
require_once('includes/Event.php');
require_once('includes/Group.php');
require_once('includes/Monitor.php');
// lang references $user[Language] so must come after auth require_once('includes/lang.php');
foreach ( getSkinIncludes('skin.php') as $includeFile ) {
require_once $includeFile;
}
if (isset($_POST['action'])) {
# Actions can only be performed on POST because we don't check csrf on GETs. $action = detaintPath($_POST['action']);
}
else if (isset($_REQUEST['action']) and $_REQUEST['action'] and empty($_REQUEST['request'])) {
ZM\Error('actions can no longer be performed without POST. Requested: '.$_REQUEST['action']. ' for ' .$view);
}
# The only variable we really need to set is action. The others are informal. isset($view) || $view = NULL;
isset($request) || $request = NULL;
isset($action) || $action = NULL;
if ( (!$view and !$request) or ($view == 'console') ) {
check_timezone();
}
ZM\Debug("View: $view Request: $request Action: $action User: " . ( isset($user) ? $user['Username'] : 'none' ));
if ( ZM_ENABLE_CSRF_MAGIC && ( $action != 'login' ) && ( $view != 'view_video' ) && // only video no html ( $view != 'image' ) && // view=image doesn't return html, just image data. ( $request != 'control' ) && //( $view != 'frames' ) && // big html can overflow ob ( $view != 'archive' ) // returns data && ( (!isset($_SERVER['CONTENT_TYPE']) or ($_SERVER['CONTENT_TYPE'] != 'application/csp-report')) ) ) {
require_once('includes/csrf/csrf-magic.php');
#ZM\Debug("Calling csrf_check with the following values: \$request = \"$request\", \$view = \"$view\", \$action = \"$action\"");
csrf_check();
}
# If I put this here, it protects all views and popups, but it has to go after actions.php because actions.php does the actual logging in. if ( ZM_OPT_USE_AUTH and (!isset($user)) and ($view != 'login') and ($view != 'none') ) {
if ($request) {
# requests only return json header('HTTP/1.1 401 Unauthorized');
exit;
}
$view = 'none';
$redirect = ZM_BASE_URL.$_SERVER['PHP_SELF'].'?view=login';
zm_session_start();
$_SESSION['postLoginQuery'] = $_SERVER['QUERY_STRING'];
session_write_close();
}
else if ( ZM_SHOW_PRIVACY && ($view != 'privacy') && ($view != 'options') && (!$request) && canEdit('System') ) {
$view = 'none';
$redirect = ZM_BASE_URL.$_SERVER['PHP_SELF'].'?view=privacy';
$request = null;
}
# Need to include actions because it does auth if ( $action and $view and !$request ) {
if ( file_exists('includes/actions/'.$view.'.php') ) {
require_once('includes/actions/'.$view.'.php');
}
else {
ZM\Debug("No includes/actions/$view.php for action $action");
}
}
if ( isset($_REQUEST['redirect']) ) {
$redirect = '?view='.detaintPath($_REQUEST['redirect']);
}
if ($redirect) {
ZM\Debug("Redirecting to $redirect");
header('Location: '.$redirect);
return;
}
if ( $request ) {
foreach ( getSkinIncludes('ajax/'.$request.'.php', true, true) as $includeFile ) {
if ( !file_exists($includeFile) ) ZM\Fatal("Request '$request' does not exist");
require_once $includeFile;
}
return;
}
# Add CSP Headers $cspNonce = bin2hex(zm_random_bytes(16));
if ( $includeFiles = getSkinIncludes('views/'.$view.'.php', true, true) ) {
ob_start();
CSPHeaders($view, $cspNonce);
foreach ( $includeFiles as $includeFile ) {
if (!file_exists($includeFile)) {
ZM\Error("View '$view' does not exist, redirecting to console");
header('Location: ?view=console');
return;
}
require_once $includeFile;
}
// If the view overrides $view to 'error', and the user is not logged in, then the // issue is probably resolvable by logging in, so provide the opportunity to do so. // The login view should handle redirecting to the correct location afterward. if ( $view == 'error' && !isset($user) ) {
$view = 'login';
foreach ( getSkinIncludes('views/login.php', true, true) as $includeFile ) require_once $includeFile;
}
while (ob_get_level() > 0) ob_end_flush();
}
# end if include files for view // If the view is missing or the view still returned error with the user logged in, // then it is not recoverable. if ( !$includeFiles || $view == 'error' ) {
foreach ( getSkinIncludes('views/error.php', true, true) as $includeFile ) require_once $includeFile;
}
?>
Following another post viewtopic.php?t=29382 I changed '#User=www-data' to 'User=www-data' (just removed the '#') in the file /lib/systemd/system/zoneminder.service. But it didn't help either.
I am not used to php language, nor the complexity of network systems. I looked at https://www.w3schools.com/php/php_mysql_intro.asp to read about the php syntax and the rest of the php file apparently seems ok.
The command: sudo systemctl status zoneminder.service seems to inform that everything is OK too (to me).
Code: Select all
● zoneminder.service - ZoneMinder CCTV recording and surveillance system
Loaded: loaded (/lib/systemd/system/zoneminder.service; enabled; preset: enabled)
Active: active (running) since Tue 2024-11-26 12:57:31 CET; 52min ago
Main PID: 5121 (zmdc.pl)
Tasks: 6 (limit: 55255)
Memory: 105.3M
CPU: 3.005s
CGroup: /system.slice/zoneminder.service
├─5121 /usr/bin/perl -wT /usr/bin/zmdc.pl startup
├─5149 /usr/bin/perl -wT /usr/bin/zmfilter.pl --filter_id=1 --daemon
├─5153 /usr/bin/perl -wT /usr/bin/zmfilter.pl --filter_id=2 --daemon
├─5160 /usr/bin/perl -wT /usr/bin/zmwatch.pl
├─5165 /usr/bin/perl -wT /usr/bin/zmupdate.pl -c
└─5169 /usr/bin/perl -wT /usr/bin/zmstats.pl
Nov 26 12:57:31 anndrewhost sudo[5155]: root : PWD=/usr/share/zoneminder/www ; USER=www-data ; COMM>
Nov 26 12:57:31 anndrewhost sudo[5155]: pam_unix(sudo:session): session opened for user www-data(uid=33>
Nov 26 12:57:31 anndrewhost sudo[5155]: pam_unix(sudo:session): session closed for user www-data
Nov 26 12:57:31 anndrewhost sudo[5161]: root : PWD=/usr/share/zoneminder/www ; USER=www-data ; COMM>
Nov 26 12:57:31 anndrewhost sudo[5161]: pam_unix(sudo:session): session opened for user www-data(uid=33>
Nov 26 12:57:31 anndrewhost sudo[5161]: pam_unix(sudo:session): session closed for user www-data
Nov 26 12:57:31 anndrewhost sudo[5166]: root : PWD=/usr/share/zoneminder/www ; USER=www-data ; COMM>
Nov 26 12:57:31 anndrewhost sudo[5166]: pam_unix(sudo:session): session opened for user www-data(uid=33>
Nov 26 12:57:31 anndrewhost sudo[5166]: pam_unix(sudo:session): session closed for user www-data
Nov 26 12:57:31 anndrewhost systemd[1]: Started zoneminder.service - ZoneMinder CCTV recording and surv>
Any help would be much appreciated. Thanks.