Compare commits

...

3 Commits

Author SHA1 Message Date
jokob-sk
00a47ab5d3 FE: config backups saved in incorrect location #1311
Some checks failed
Code checks / check-url-paths (push) Has been cancelled
Code checks / lint (push) Has been cancelled
Code checks / docker-tests (push) Has been cancelled
docker / docker_dev (push) Has been cancelled
Deploy MkDocs / deploy (push) Has been cancelled
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2025-11-30 07:42:11 +11:00
jokob-sk
525d082f3d DOCS: volume
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2025-11-29 16:53:15 +11:00
jokob-sk
ba3481759b DOCS: Migration callouts
Some checks failed
Code checks / check-url-paths (push) Has been cancelled
Code checks / lint (push) Has been cancelled
Code checks / docker-tests (push) Has been cancelled
docker / docker_dev (push) Has been cancelled
Deploy MkDocs / deploy (push) Has been cancelled
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2025-11-29 16:50:06 +11:00
8 changed files with 74 additions and 88 deletions

View File

@@ -34,9 +34,7 @@ Get visibility of what's going on on your WIFI/LAN network and enable presence d
## 🚀 Quick Start ## 🚀 Quick Start
> [!WARNING] > [!WARNING]
> ⚠️ **Important:** The documentation has been recently updated and some instructions may have changed. > ⚠️ **Important:** The docker-compose has recently changed. Carefully read the [Migration guide](https://jokob-sk.github.io/NetAlertX/MIGRATION/?h=migrat#12-migration-from-netalertx-v25524) for detailed instructions.
> If you are using the currently live production image, please follow the instructions on [Docker Hub](https://hub.docker.com/r/jokobsk/netalertx) for building and running the container.
> These docs reflect the latest development version and may differ from the production image.
Start NetAlertX in seconds with Docker: Start NetAlertX in seconds with Docker:

View File

@@ -1,9 +1,7 @@
# NetAlertX and Docker Compose # NetAlertX and Docker Compose
> [!WARNING] > [!WARNING]
> ⚠️ **Important:** The documentation has been recently updated and some instructions may have changed. > ⚠️ **Important:** The docker-compose has recently changed. Carefully read the [Migration guide](https://jokob-sk.github.io/NetAlertX/MIGRATION/?h=migrat#12-migration-from-netalertx-v25524) for detailed instructions.
> If you are using the currently live production image, please follow the instructions on [Docker Hub](https://hub.docker.com/r/jokobsk/netalertx) for building and running the container.
> These docs reflect the latest development version and may differ from the production image.
Great care is taken to ensure NetAlertX meets the needs of everyone while being flexible enough for anyone. This document outlines how you can configure your docker-compose. There are many settings, so we recommend using the Baseline Docker Compose as-is, or modifying it for your system.Good care is taken to ensure NetAlertX meets the needs of everyone while being flexible enough for anyone. This document outlines how you can configure your docker-compose. There are many settings, so we recommend using the Baseline Docker Compose as-is, or modifying it for your system. Great care is taken to ensure NetAlertX meets the needs of everyone while being flexible enough for anyone. This document outlines how you can configure your docker-compose. There are many settings, so we recommend using the Baseline Docker Compose as-is, or modifying it for your system.Good care is taken to ensure NetAlertX meets the needs of everyone while being flexible enough for anyone. This document outlines how you can configure your docker-compose. There are many settings, so we recommend using the Baseline Docker Compose as-is, or modifying it for your system.

View File

@@ -61,8 +61,7 @@ See alternative [docked-compose examples](https://github.com/jokob-sk/NetAlertX/
| Required | Path | Description | | Required | Path | Description |
| :------------- | :------------- | :-------------| | :------------- | :------------- | :-------------|
| ✅ | `:/data/config` | Folder which will contain the `app.conf` & `devices.csv` ([read about devices.csv](https://github.com/jokob-sk/NetAlertX/blob/main/docs/DEVICES_BULK_EDITING.md)) files | | ✅ | `:/data` | Folder which will contain the `/db/app.db`, `/config/app.conf` & `/config/devices.csv` ([read about devices.csv](https://github.com/jokob-sk/NetAlertX/blob/main/docs/DEVICES_BULK_EDITING.md)) files |
| ✅ | `:/data/db` | Folder which will contain the `app.db` database file |
| ✅ | `/etc/localtime:/etc/localtime:ro` | Ensuring the timezone is teh same as on teh server. | | ✅ | `/etc/localtime:/etc/localtime:ro` | Ensuring the timezone is teh same as on teh server. |
| | `:/tmp/log` | Logs folder useful for debugging if you have issues setting up the container | | | `:/tmp/log` | Logs folder useful for debugging if you have issues setting up the container |
| | `:/tmp/api` | The [API endpoint](https://github.com/jokob-sk/NetAlertX/blob/main/docs/API.md) containing static (but regularly updated) json and other files. Path configurable via `NETALERTX_API` environment variable. | | | `:/tmp/api` | The [API endpoint](https://github.com/jokob-sk/NetAlertX/blob/main/docs/API.md) containing static (but regularly updated) json and other files. Path configurable via `NETALERTX_API` environment variable. |

View File

@@ -1,20 +1,18 @@
# The NetAlertX Container Operator's Guide # The NetAlertX Container Operator's Guide
> [!WARNING] > [!WARNING]
> ⚠️ **Important:** The documentation has been recently updated and some instructions may have changed. > ⚠️ **Important:** The docker-compose has recently changed. Carefully read the [Migration guide](https://jokob-sk.github.io/NetAlertX/MIGRATION/?h=migrat#12-migration-from-netalertx-v25524) for detailed instructions.
> If you are using the currently live production image, please follow the instructions on [Docker Hub](https://hub.docker.com/r/jokobsk/netalertx) for building and running the container.
> These docs reflect the latest development version and may differ from the production image.
This guide assumes you are starting with the official `docker-compose.yml` file provided with the project. We strongly recommend you start with or migrate to this file as your baseline and modify it to suit your specific needs (e.g., changing file paths). While there are many ways to configure NetAlertX, the default file is designed to meet the mandatory security baseline with layer-2 networking capabilities while operating securely and without startup warnings. This guide assumes you are starting with the official `docker-compose.yml` file provided with the project. We strongly recommend you start with or migrate to this file as your baseline and modify it to suit your specific needs (e.g., changing file paths). While there are many ways to configure NetAlertX, the default file is designed to meet the mandatory security baseline with layer-2 networking capabilities while operating securely and without startup warnings.
This guide provides direct, concise solutions for common NetAlertX administrative tasks. It is structured to help you identify a problem, implement the solution, and understand the details. This guide provides direct, concise solutions for common NetAlertX administrative tasks. It is structured to help you identify a problem, implement the solution, and understand the details.
## Guide Contents ## Guide Contents
- Using a Local Folder for Configuration - Using a Local Folder for Configuration
- Migrating from a Local Folder to a Docker Volume - Migrating from a Local Folder to a Docker Volume
- Applying a Custom Nginx Configuration - Applying a Custom Nginx Configuration
- Mounting Additional Files for Plugins - Mounting Additional Files for Plugins
> [!NOTE] > [!NOTE]

View File

@@ -62,7 +62,7 @@ docker run -it --rm --name netalertx --user "0" \
> >
> `sudo chown -R 20211:20211 /local_data_dir` > `sudo chown -R 20211:20211 /local_data_dir`
> >
> `sudo chmod -R a+rwx /local_data_dir1` > `sudo chmod -R a+rwx /local_data_dir`
> >
--- ---

View File

@@ -1,11 +1,5 @@
# Migration # Migration
> [!WARNING]
> ⚠️ **Important:** The documentation has been recently updated and some instructions may have changed.
> If you are using the currently live production image, please follow the instructions on [Docker Hub](https://hub.docker.com/r/jokobsk/netalertx) for building and running the container.
> These docs reflect the latest development version and may differ from the production image.
When upgrading from older versions of NetAlertX (or PiAlert by jokob-sk), follow the migration steps below to ensure your data and configuration are properly transferred. When upgrading from older versions of NetAlertX (or PiAlert by jokob-sk), follow the migration steps below to ensure your data and configuration are properly transferred.
> [!TIP] > [!TIP]
@@ -262,8 +256,7 @@ docker run -it --rm --name netalertx --user "0" \
..or alternatively execute: ..or alternatively execute:
```bash ```bash
sudo chown -R 20211:20211 /local_data_dir/config sudo chown -R 20211:20211 /local_data_dir
sudo chown -R 20211:20211 /local_data_dir/db
sudo chmod -R a+rwx /local_data_dir/ sudo chmod -R a+rwx /local_data_dir/
``` ```

View File

@@ -84,5 +84,5 @@ services:
> >
> `sudo chown -R 20211:20211 /local_data_dir` > `sudo chown -R 20211:20211 /local_data_dir`
> >
> `sudo chmod -R a+rwx /local_data_dir1` > `sudo chmod -R a+rwx /local_data_dir`
> >

View File

@@ -1,7 +1,7 @@
<?php <?php
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// NetAlertX // NetAlertX
// Open Source Network Guard / WIFI & LAN intrusion detector // Open Source Network Guard / WIFI & LAN intrusion detector
// //
// util.php - Front module. Server side. Common generic functions // util.php - Front module. Server side. Common generic functions
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@@ -22,8 +22,8 @@ $ACTION = "";
// init request params // init request params
if(array_key_exists('function', $_REQUEST) != FALSE) if(array_key_exists('function', $_REQUEST) != FALSE)
{ {
$FUNCTION = $_REQUEST['function']; $FUNCTION = $_REQUEST['function'];
} }
if(array_key_exists('settings', $_REQUEST) != FALSE) if(array_key_exists('settings', $_REQUEST) != FALSE)
{ {
@@ -33,13 +33,13 @@ if(array_key_exists('settings', $_REQUEST) != FALSE)
// call functions based on requested params // call functions based on requested params
switch ($FUNCTION) { switch ($FUNCTION) {
case 'savesettings': case 'savesettings':
saveSettings(); saveSettings();
break; break;
case 'cleanLog': case 'cleanLog':
cleanLog($SETTINGS); cleanLog($SETTINGS);
break; break;
@@ -66,7 +66,7 @@ switch ($FUNCTION) {
// Creates a PHP array from a string representing a python array (input format ['...','...']) // Creates a PHP array from a string representing a python array (input format ['...','...'])
// Only supports: // Only supports:
// - one level arrays, not nested ones // - one level arrays, not nested ones
// - single quotes // - single quotes
function createArray($input){ function createArray($input){
// empty array // empty array
@@ -81,9 +81,9 @@ function createArray($input){
$replacement = ''; $replacement = '';
// remove brackets // remove brackets
$noBrackets = preg_replace($patternBrackets, $replacement, $input); $noBrackets = preg_replace($patternBrackets, $replacement, $input);
$options = array(); $options = array();
// create array // create array
$optionsTmp = explode(",", $noBrackets); $optionsTmp = explode(",", $noBrackets);
@@ -99,7 +99,7 @@ function createArray($input){
{ {
array_push($options, preg_replace($patternQuotes, $replacement, $item) ); array_push($options, preg_replace($patternQuotes, $replacement, $item) );
} }
return $options; return $options;
} }
@@ -117,7 +117,7 @@ function printArray ($array) {
{ {
echo $val.', '; echo $val.', ';
} }
} }
echo ']<br/>'; echo ']<br/>';
} }
@@ -171,9 +171,9 @@ function checkPermissions($files)
if(file_exists($file) != 1) if(file_exists($file) != 1)
{ {
$message = "File '".$file."' not found or inaccessible. Correct file permissions, create one yourself or generate a new one in 'Settings' by clicking the 'Save' button."; $message = "File '".$file."' not found or inaccessible. Correct file permissions, create one yourself or generate a new one in 'Settings' by clicking the 'Save' button.";
displayMessage($message, TRUE); displayMessage($message, TRUE);
} }
} }
} }
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
@@ -189,8 +189,8 @@ function displayMessage($message, $logAlert = FALSE, $logConsole = TRUE, $logFil
$message = str_replace(array("\n", "\r", PHP_EOL), '', $message); $message = str_replace(array("\n", "\r", PHP_EOL), '', $message);
echo "<script>function escape(html, encode) { echo "<script>function escape(html, encode) {
return html.replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;') return html.replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
.replace(/\t/g, '') .replace(/\t/g, '')
}</script>"; }</script>";
// Javascript Alert pop-up // Javascript Alert pop-up
@@ -210,7 +210,7 @@ function displayMessage($message, $logAlert = FALSE, $logConsole = TRUE, $logFil
{ {
if (is_writable($logFolderPath.$log_file)) { if (is_writable($logFolderPath.$log_file)) {
if(file_exists($logFolderPath.$log_file) != 1) // file doesn't exist, create one if(file_exists($logFolderPath.$log_file) != 1) // file doesn't exist, create one
{ {
@@ -219,7 +219,7 @@ function displayMessage($message, $logAlert = FALSE, $logConsole = TRUE, $logFil
{ {
$log = fopen($logFolderPath.$log_file, "a") or die("Unable to open file - Permissions issue!"); $log = fopen($logFolderPath.$log_file, "a") or die("Unable to open file - Permissions issue!");
} }
fwrite($log, "[".$timestamp. "] " . str_replace('<br>',"\n ",str_replace('<br/>',"\n ",$message)).PHP_EOL."" ); fwrite($log, "[".$timestamp. "] " . str_replace('<br>',"\n ",str_replace('<br/>',"\n ",$message)).PHP_EOL."" );
fclose($log); fclose($log);
@@ -269,13 +269,13 @@ function addToExecutionQueue($action)
// equivalent: /logs DELETE // equivalent: /logs DELETE
// 🔺----- API ENDPOINTS SUPERSEDED -----🔺 // 🔺----- API ENDPOINTS SUPERSEDED -----🔺
function cleanLog($logFile) function cleanLog($logFile)
{ {
global $logFolderPath, $timestamp; global $logFolderPath, $timestamp;
$path = ""; $path = "";
$allowedFiles = ['app.log', 'app_front.log', 'IP_changes.log', 'stdout.log', 'stderr.log', 'app.php_errors.log', 'execution_queue.log', 'db_is_locked.log', 'nginx-error.log', 'cron.log']; $allowedFiles = ['app.log', 'app_front.log', 'IP_changes.log', 'stdout.log', 'stderr.log', 'app.php_errors.log', 'execution_queue.log', 'db_is_locked.log', 'nginx-error.log', 'cron.log'];
if(in_array($logFile, $allowedFiles)) if(in_array($logFile, $allowedFiles))
{ {
$path = $logFolderPath.$logFile; $path = $logFolderPath.$logFile;
@@ -287,11 +287,11 @@ function cleanLog($logFile)
$file = fopen($path, "w") or die("Unable to open file!"); $file = fopen($path, "w") or die("Unable to open file!");
fwrite($file, ""); fwrite($file, "");
fclose($file); fclose($file);
displayMessage('File <code>'.$logFile.'</code> purged.', FALSE, TRUE, TRUE, TRUE); displayMessage('File <code>'.$logFile.'</code> purged.', FALSE, TRUE, TRUE, TRUE);
} else } else
{ {
displayMessage('File <code>'.$logFile.'</code> is not allowed to be purged.', FALSE, TRUE, TRUE, TRUE); displayMessage('File <code>'.$logFile.'</code> is not allowed to be purged.', FALSE, TRUE, TRUE, TRUE);
} }
} }
@@ -299,23 +299,23 @@ function cleanLog($logFile)
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
function saveSettings() function saveSettings()
{ {
global $SETTINGS, $FUNCTION, $config_file, $fullConfPath, $configFolderPath, $timestamp; global $SETTINGS, $FUNCTION, $config_file, $fullConfPath, $configFolderPath, $timestamp;
// save to the file // save to the file
$new_name = $config_file.'_'.$timestamp.'.backup'; $new_name = $config_file.'_'.$timestamp.'.backup';
$new_location = $configFolderPath.$new_name; $new_location = $configFolderPath.'/'.$new_name;
if(file_exists( $fullConfPath) != 1) if(file_exists( $fullConfPath) != 1)
{ {
displayMessage('File "'.$fullConfPath.'" not found or missing read permissions. Creating a new <code>'.$config_file.'</code> file.', FALSE, TRUE, TRUE, TRUE); displayMessage('File "'.$fullConfPath.'" not found or missing read permissions. Creating a new <code>'.$config_file.'</code> file.', FALSE, TRUE, TRUE, TRUE);
} }
// create a backup copy // create a backup copy
elseif (!copy($fullConfPath, $new_location)) elseif (!copy($fullConfPath, $new_location))
{ {
displayMessage("Failed to copy file ".$fullConfPath." to ".$new_location." <br/> Check your permissions to allow read/write access to the /config folder.", FALSE, TRUE, TRUE, TRUE); displayMessage("Failed to copy file ".$fullConfPath." to ".$new_location." <br/> Check your permissions to allow read/write access to the /config folder.", FALSE, TRUE, TRUE, TRUE);
} }
// generate a clean .conf file // generate a clean .conf file
$groups = []; $groups = [];
@@ -339,12 +339,12 @@ function saveSettings()
return; return;
} }
foreach ($decodedSettings as $setting) { foreach ($decodedSettings as $setting) {
if( in_array($setting[0] , $groups) == false) { if( in_array($setting[0] , $groups) == false) {
array_push($groups ,$setting[0]); array_push($groups ,$setting[0]);
} }
} }
// go thru the groups and prepare settings to write to file // go thru the groups and prepare settings to write to file
foreach ($groups as $group) { foreach ($groups as $group) {
$txt .= "\n\n# " . $group; $txt .= "\n\n# " . $group;
@@ -353,20 +353,20 @@ function saveSettings()
foreach ($decodedSettings as $setting) { foreach ($decodedSettings as $setting) {
$settingGroup = $setting[0]; $settingGroup = $setting[0];
$setKey = $setting[1]; $setKey = $setting[1];
$dataType = $setting[2]; $dataType = $setting[2];
$settingValue = $setting[3]; $settingValue = $setting[3];
// // Parse the settingType JSON // // Parse the settingType JSON
// $settingType = json_decode($settingTypeJson, true); // $settingType = json_decode($settingTypeJson, true);
// Sanity check // Sanity check
if($setKey == "UI_LANG" && $settingValue == "") { if($setKey == "UI_LANG" && $settingValue == "") {
echo "🔴 Error: important settings missing. Refresh the page with 🔃 on the top and try again."; echo "🔴 Error: important settings missing. Refresh the page with 🔃 on the top and try again.";
return; return;
} }
if ($group == $settingGroup) { if ($group == $settingGroup) {
if ($dataType == 'string' ) { if ($dataType == 'string' ) {
$val = encode_single_quotes($settingValue); $val = encode_single_quotes($settingValue);
$txt .= $setKey . "='" . $val . "'\n"; $txt .= $setKey . "='" . $val . "'\n";
@@ -381,7 +381,7 @@ function saveSettings()
$txt .= $setKey . "=" . $val . "\n"; $txt .= $setKey . "=" . $val . "\n";
} elseif ($dataType == 'array' ) { } elseif ($dataType == 'array' ) {
$temp = ''; $temp = '';
if(is_array($settingValue) == FALSE) if(is_array($settingValue) == FALSE)
{ {
$settingValue = json_decode($settingValue); $settingValue = json_decode($settingValue);
@@ -397,22 +397,22 @@ function saveSettings()
$temp = '['.$temp.']'; // wrap brackets $temp = '['.$temp.']'; // wrap brackets
$txt .= $setKey . "=" . $temp . "\n"; $txt .= $setKey . "=" . $temp . "\n";
} else { } else {
$txt .= $setKey . "='⭕Not handled⭕'\n"; $txt .= $setKey . "='⭕Not handled⭕'\n";
} }
} }
} }
} }
$txt = $txt."\n\n"; $txt = $txt."\n\n";
$txt = $txt."#-------------------IMPORTANT INFO-------------------#\n"; $txt = $txt."#-------------------IMPORTANT INFO-------------------#\n";
$txt = $txt."# This file is ingested by a python script, so if #\n"; $txt = $txt."# This file is ingested by a python script, so if #\n";
$txt = $txt."# modified it needs to use python syntax #\n"; $txt = $txt."# modified it needs to use python syntax #\n";
$txt = $txt."#-------------------IMPORTANT INFO-------------------#\n"; $txt = $txt."#-------------------IMPORTANT INFO-------------------#\n";
// open new file and write the new configuration // open new file and write the new configuration
// Create a temporary file // Create a temporary file
$tempConfPath = $fullConfPath . ".tmp"; $tempConfPath = $fullConfPath . ".tmp";
@@ -426,8 +426,8 @@ function saveSettings()
fwrite($file, $txt); fwrite($file, $txt);
fclose($file); fclose($file);
// displayMessage(lang('settings_saved'), // displayMessage(lang('settings_saved'),
// FALSE, TRUE, TRUE, TRUE); // FALSE, TRUE, TRUE, TRUE);
echo "OK"; echo "OK";
@@ -445,7 +445,7 @@ function getString ($setKey, $default) {
if ($result ) if ($result )
{ {
return $result; return $result;
} }
return $default; return $default;
} }
@@ -520,14 +520,14 @@ function getDateFromPeriod () {
$days = "3650"; //10 years $days = "3650"; //10 years
break; break;
default: default:
$days = "1"; $days = "1";
} }
$periodDateSQL = "-".$days." day"; $periodDateSQL = "-".$days." day";
return " date('now', '".$periodDateSQL."') "; return " date('now', '".$periodDateSQL."') ";
// $period = $_REQUEST['period']; // $period = $_REQUEST['period'];
// return '"'. date ('Y-m-d', strtotime ('+2 day -'. $period) ) .'"'; // return '"'. date ('Y-m-d', strtotime ('+2 day -'. $period) ) .'"';
} }
@@ -537,13 +537,13 @@ function getDateFromPeriod () {
function quotes ($text) { function quotes ($text) {
return str_replace ('"','""',$text); return str_replace ('"','""',$text);
} }
// ------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------
function logServerConsole ($text) { function logServerConsole ($text) {
$x = array(); $x = array();
$y = $x['__________'. $text .'__________']; $y = $x['__________'. $text .'__________'];
} }
// ------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------
function handleNull ($text, $default = "") { function handleNull ($text, $default = "") {
if($text == NULL || $text == 'NULL') if($text == NULL || $text == 'NULL')
@@ -553,7 +553,7 @@ function handleNull ($text, $default = "") {
{ {
return $text; return $text;
} }
} }
// ------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------
@@ -581,14 +581,14 @@ function decodeSpecialChars($str) {
// used in Export CSV // used in Export CSV
function getDevicesColumns(){ function getDevicesColumns(){
$columns = ["devMac", $columns = ["devMac",
"devName", "devName",
"devOwner", "devOwner",
"devType", "devType",
"devVendor", "devVendor",
"devFavorite", "devFavorite",
"devGroup", "devGroup",
"devComments", "devComments",
"devFirstConnection", "devFirstConnection",
"devLastConnection", "devLastConnection",
"devLastIP", "devLastIP",
@@ -615,8 +615,8 @@ function getDevicesColumns(){
"devFQDN", "devFQDN",
"devParentRelType", "devParentRelType",
"devReqNicsOnline" "devReqNicsOnline"
]; ];
return $columns; return $columns;
} }
@@ -646,7 +646,7 @@ function getCache($key) {
} }
// ------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------
function setCache($key, $value, $expireMinutes = 5) { function setCache($key, $value, $expireMinutes = 5) {
setcookie($key, $value, time()+$expireMinutes*60, "/","", 0); setcookie($key, $value, time()+$expireMinutes*60, "/","", 0);
} }