#!/usr/bin/env bash # Exit immediately if a command exits with a non-zero status. set -e # Treat unset variables as an error when substituting set -u # Consider failures in a pipeline set -o pipefail # Safe IFS IFS=$' \t\n' # 🛑 Important: This is only used for the bare-metal install 🛑 # Colors (guarded) if [ -t 1 ] && [ -z "${NO_COLOR:-}" ]; then RESET='\e[0m' GREEN='\e[1;38;5;2m' RED='\e[31m' else RESET=''; GREEN=''; RED='' fi printf "%b\n" "--------------------------------------------------------------------------" printf "%b\n" "${GREEN}[UPDATING] ${RESET}Making sure the system is up to date" printf "%b\n" "--------------------------------------------------------------------------" printf "%b\n" "--------------------------------------------------------------------------" printf "%b\n" "${GREEN}[INSTALLING] ${RESET}Running proxmox-install-netalertx.sh" printf "%b\n" "--------------------------------------------------------------------------" # Set environment variables INSTALL_DIR=/app # default installation directory # DO NOT CHANGE ANYTHING BELOW THIS LINE! INSTALLER_DIR="$INSTALL_DIR/install/proxmox" CONF_FILE=app.conf DB_FILE=app.db NGINX_CONF_FILE=netalertx.conf WEB_UI_DIR=/var/www/html/netalertx NGINX_CONFIG=/etc/nginx/conf.d/$NGINX_CONF_FILE OUI_FILE="/usr/share/arp-scan/ieee-oui.txt" FILEDB=$INSTALL_DIR/db/$DB_FILE # DO NOT CHANGE ANYTHING ABOVE THIS LINE! # Check if script is run as root if [[ $EUID -ne 0 ]]; then echo "This script must be run as root." exit 1 fi # Interactive confirmation: warn about overwriting/removing existing installation and NGINX config if [ -z "${NETALERTX_ASSUME_YES:-}" ] && [ -z "${ASSUME_YES:-}" ] && [ -z "${NETALERTX_FORCE:-}" ]; then printf "%b\n" "------------------------------------------------------------------------" printf "%b\n" "${RED}[WARNING] ${RESET}This script should be run on a fresh server" printf "%b\n" "${RED}[WARNING] ${RESET}This script will install NetAlertX and will:" printf "%b\n" "${RED}[WARNING] ${RESET}• Update OS with apt-get update/upgrade" printf "%b\n" "${RED}[WARNING] ${RESET}• Overwrite existing files under ${INSTALL_DIR} " printf "%b\n" "${RED}[WARNING] ${RESET}• Wipe any existing database" printf "%b\n" "${RED}[WARNING] ${RESET}• Wipe/Set up NGINX configuration under /etc/nginx" printf "%b\n" "${RED}[WARNING] ${RESET}• Set up systemd services." read -r -p "Proceed with installation? [y/N]: " _reply case "${_reply}" in y|Y|yes|YES) ;; *) echo "Aborting by user choice."; exit 1;; esac else printf "%b\n" "--------------------------------------------------------------------------" printf "%b\n" "${GREEN}[INSTALLING] ${RESET}Non-interactive mode detected; proceeding without confirmation." printf "%b\n" "--------------------------------------------------------------------------" fi # Getting up to date apt-get update -y apt-get upgrade -y # Prompt for HTTP port (default 20211) with countdown fallback DEFAULT_PORT=20211 if [ -z "${NETALERTX_ASSUME_YES:-}" ] && [ -z "${ASSUME_YES:-}" ] && [ -z "${NETALERTX_FORCE:-}" ]; then printf "%b\n" "--------------------------------------------------------------------------" # Countdown-based prompt _entered_port="" for _sec in 10 9 8 7 6 5 4 3 2 1; do printf "\rEnter HTTP port for NetAlertX [${DEFAULT_PORT}] (auto-continue in %2ds): " "${_sec}" if read -t 1 -r _entered_port; then break fi done printf "\n" if [ -z "${_entered_port}" ]; then PORT="${DEFAULT_PORT}" elif printf '%s' "${_entered_port}" | grep -Eq '^[0-9]+$' && [ "${_entered_port}" -ge 1 ] && [ "${_entered_port}" -le 65535 ]; then PORT="${_entered_port}" else printf "%b\n" "${RED}[WARNING] ${RESET}Invalid port. Falling back to ${DEFAULT_PORT}" PORT="${DEFAULT_PORT}" fi else PORT="${PORT-}"; PORT="${PORT:-${DEFAULT_PORT}}" fi export PORT # Detect primary server IP SERVER_IP="$(ip -4 route get 1.1.1.1 2>/dev/null | awk '{for(i=1;i<=NF;i++) if ($i=="src") {print $(i+1); exit}}')" if [ -z "${SERVER_IP}" ]; then SERVER_IP="$(hostname -I 2>/dev/null | awk '{print $1}')" fi if [ -z "${SERVER_IP}" ]; then SERVER_IP="127.0.0.1" fi export SERVER_IP # Ensure tmpfs mounts are cleaned up on exit/failure trap 'umount "${INSTALL_DIR}/log" 2>/dev/null || true; umount "${INSTALL_DIR}/api" 2>/dev/null || true' EXIT # Making sure the system is clean if [ -d "$INSTALL_DIR" ]; then printf "%b\n" "Removing existing directory: $INSTALL_DIR" rm -rf "$INSTALL_DIR" fi # 1. INSTALL SYSTEM DEPENDENCIES & ADD PHP REPOSITORY printf "%b\n" "--------------------------------------------------------------------------" printf "%b\n" "${GREEN}[INSTALLING] ${RESET}Installing system dependencies" printf "%b\n" "--------------------------------------------------------------------------" export DEBIAN_FRONTEND=noninteractive apt-get update -y # software-properties-common is not available and not needed apt-get install -y --no-install-recommends \ ca-certificates lsb-release curl gnupg # Detect OS . /etc/os-release OS_ID="${ID:-}" OS_VER="${VERSION_ID:-}" printf "%b\n" "--------------------------------------------------------------------------" printf "%b\n" "${GREEN}[INSTALLING] ${RESET}Detected OS: ${OS_ID} ${OS_VER}" printf "%b\n" "--------------------------------------------------------------------------" if [ "${OS_ID}" = "ubuntu" ] && printf '%s' "${OS_VER}" | grep -q '^24'; then # Ubuntu 24.x typically ships PHP 8.3; add ondrej/php PPA and set 8.4 printf "%b\n" "--------------------------------------------------------------------------" printf "%b\n" "${GREEN}[INSTALLING] ${RESET}Ubuntu 24 detected - enabling ondrej/php PPA for PHP 8.4" printf "%b\n" "--------------------------------------------------------------------------" apt-get install -y --no-install-recommends software-properties-common || true add-apt-repository ppa:ondrej/php -y apt update -y elif [ "${OS_ID}" = "debian" ] && printf '%s' "${OS_VER}" | grep -q '^13'; then printf "%b\n" "--------------------------------------------------------------------------" printf "%b\n" "${GREEN}[INSTALLING] ${RESET}Debian 13 detected - using built-in PHP 8.4" printf "%b\n" "--------------------------------------------------------------------------" fi apt-get install -y --no-install-recommends \ tini snmp ca-certificates curl libwww-perl arp-scan perl apt-utils cron sudo \ php8.4 php8.4-cgi php8.4-fpm php8.4-sqlite3 php8.4-curl sqlite3 dnsutils net-tools mtr \ python3 python3-dev iproute2 nmap python3-pip zip usbutils traceroute nbtscan \ avahi-daemon avahi-utils build-essential git gnupg2 lsb-release \ debian-archive-keyring python3-venv if [ "${OS_ID}" = "ubuntu" ] && printf '%s' "${OS_VER}" | grep -q '^24'; then # Set PHP 8.4 as the default alternatives where applicable update-alternatives --set php /usr/bin/php8.4 || true systemctl enable php8.4-fpm || true systemctl restart php8.4-fpm || true fi printf "%b\n" "--------------------------------------------------------------------------" printf "%b\n" "${GREEN}[INSTALLING] ${RESET}Setting up NGINX - Might take a minute!" printf "%b\n" "--------------------------------------------------------------------------" apt-get install -y nginx # Enable and start nginx if command -v systemctl >/dev/null 2>&1; then systemctl enable nginx || true systemctl restart nginx || true fi # 3. CLONE OR UPDATE APPLICATION REPOSITORY printf "%b\n" "--------------------------------------------------------------------------" printf "%b\n" "${GREEN}[INSTALLING] ${RESET}Cloning application repository and setup" printf "%b\n" "--------------------------------------------------------------------------" mkdir -p "$INSTALL_DIR" git clone https://github.com/jokob-sk/NetAlertX.git "$INSTALL_DIR/" if [ ! -f "$INSTALL_DIR/front/buildtimestamp.txt" ]; then date +%s > "$INSTALL_DIR/front/buildtimestamp.txt" fi printf "%b\n" "--------------------------------------------------------------------------" printf "%b\n" "${GREEN}[FINISHED] ${RESET}NetAlertX Installation complete" printf "%b\n" "--------------------------------------------------------------------------" printf "%b\n" "${GREEN}[CONFIGURATION] ${RESET}Configuring the web server" printf "%b\n" "--------------------------------------------------------------------------" # Stop any existing NetAlertX python server process (narrow pattern) pkill -f "^python(3)?\s+.*${INSTALL_DIR}/server/?$" 2>/dev/null || true # 4. SET UP PYTHON VIRTUAL ENVIRONMENT & DEPENDENCIES printf "%b\n" "--------------------------------------------------------------------------" printf "%b\n" "${GREEN}[INSTALLING] ${RESET}Setting up Python environment" printf "%b\n" "--------------------------------------------------------------------------" python3 -m venv /opt/myenv source /opt/myenv/bin/activate python -m pip install --upgrade pip python -m pip install -r "${INSTALLER_DIR}/requirements.txt" # Backup default NGINX site just in case if [ -L /etc/nginx/sites-enabled/default ] ; then rm /etc/nginx/sites-enabled/default elif [ -f /etc/nginx/sites-enabled/default ]; then mv /etc/nginx/sites-enabled/default /etc/nginx/sites-available/default.bkp_netalertx fi # Clear existing directories and files if [ -d "$WEB_UI_DIR" ]; then printf "%b\n" "--------------------------------------------------------------------------" printf "%b\n" "${GREEN}[CHECKING] ${RESET}Removing existing NetAlertX web-UI" printf "%b\n" "--------------------------------------------------------------------------" rm -R "$WEB_UI_DIR" fi printf "%b\n" "--------------------------------------------------------------------------" printf "%b\n" "${GREEN}[CHECKING] ${RESET}Removing existing NetAlertX NGINX config" printf "%b\n" "--------------------------------------------------------------------------" rm "$NGINX_CONFIG" 2>/dev/null || true # Create web directory if it doesn't exist mkdir -p /var/www/html # create symbolic link to the installer directory ln -sfn "${INSTALL_DIR}/front" "$WEB_UI_DIR" # Copy NGINX configuration to NetAlertX config directory cp "${INSTALLER_DIR}/${NGINX_CONF_FILE}" "${INSTALL_DIR}/config/${NGINX_CONF_FILE}" # Use selected port (may be default 20211) if [ -n "${PORT-}" ]; then printf "%b\n" "--------------------------------------------------------------------------" printf "%b\n" "Setting webserver to port ($PORT)" printf "%b\n" "--------------------------------------------------------------------------" # Update the template to reflect the right port sed -i "s/listen 20211;/listen ${PORT};/g" "${INSTALL_DIR}/config/${NGINX_CONF_FILE}" # Warn if port is already in use if ss -ltn | awk '{print $4}' | grep -q ":${PORT}$"; then printf "%b\n" "--------------------------------------------------------------------------" printf "%b\n" "${RED}[WARNING] ${RESET}Port ${PORT} appears in use. NGINX may fail to bind." printf "%b\n" "--------------------------------------------------------------------------" fi fi # Create symbolic link to NGINX configuration coming with NetAlertX ln -sfn "${INSTALL_DIR}/config/${NGINX_CONF_FILE}" "${NGINX_CONFIG}" # Run the hardware vendors update at least once printf "%b\n" "--------------------------------------------------------------------------" printf "%b\n" "${GREEN}[VENDORS UPDATE] ${RESET}Run the hardware vendors update" printf "%b\n" "--------------------------------------------------------------------------" # Check if ieee-oui.txt or ieee-iab.txt exist if [ -f "$OUI_FILE" ]; then printf "%b\n" "--------------------------------------------------------------------------" printf "%b\n" "The file ieee-oui.txt exists. Skipping update_vendors.sh..." printf "%b\n" "--------------------------------------------------------------------------" else printf "%b\n" "--------------------------------------------------------------------------" printf "%b\n" "The file ieee-oui.txt does not exist. Running update_vendors..." printf "%b\n" "--------------------------------------------------------------------------" # Run the update_vendors.sh script if [ -f "${INSTALL_DIR}/back/update_vendors.sh" ]; then "${INSTALL_DIR}/back/update_vendors.sh" else printf "%b\n" "--------------------------------------------------------------------------" printf "%b\n" " update_vendors.sh script not found in $INSTALL_DIR." printf "%b\n" "--------------------------------------------------------------------------" fi fi # Create empty log files and plugin folders printf "%b\n" "--------------------------------------------------------------------------" printf "%b\n" "${GREEN}[INSTALLING] ${RESET}Creating mounts and file structure" printf "%b\n" "--------------------------------------------------------------------------" printf "%b\n" "Cleaning up old mounts if any" umount "${INSTALL_DIR}/log" 2>/dev/null || true umount "${INSTALL_DIR}/api" 2>/dev/null || true printf "%b\n" "Creating log api folders if they don't exist" mkdir -p "${INSTALL_DIR}/log" "${INSTALL_DIR}/api" printf "%b\n" "--------------------------------------------------------------------------" printf "%b\n" "${GREEN}[INSTALLING] ${RESET}Mounting log and api folders as tmpfs" printf "%b\n" "--------------------------------------------------------------------------" mountpoint -q "${INSTALL_DIR}/log" || mount -t tmpfs -o noexec,nosuid,nodev tmpfs "${INSTALL_DIR}/log" mountpoint -q "${INSTALL_DIR}/api" || mount -t tmpfs -o noexec,nosuid,nodev tmpfs "${INSTALL_DIR}/api" chown -R www-data:www-data "${INSTALL_DIR}/log" "${INSTALL_DIR}/api" # Ensure plugins directory exists within the tmpfs mount mkdir -p "${INSTALL_DIR}"/log/plugins chown -R www-data:www-data "${INSTALL_DIR}"/log/plugins # Create the execution_queue.log file if it doesn't exist touch ${INSTALL_DIR}/log/{app.log,execution_queue.log,app_front.log,app.php_errors.log,stderr.log,stdout.log,db_is_locked.log} touch ${INSTALL_DIR}/api/user_notifications.json chown -R www-data:www-data "${INSTALL_DIR}"/log "${INSTALL_DIR}"/api chmod -R ug+rwX "${INSTALL_DIR}"/log "${INSTALL_DIR}"/api # Set ownership of the tmpfs mountpoints first. chown www-data:www-data "${INSTALL_DIR}/log" "${INSTALL_DIR}/api" # Ensure plugins directory exists within the tmpfs mount mkdir -p "${INSTALL_DIR}/log/plugins" # Create log and api files directly as the www-data user to ensure correct ownership from the start. sudo -u www-data touch ${INSTALL_DIR}/log/{app.log,execution_queue.log,app_front.log,app.php_errors.log,stderr.log,stdout.log,db_is_locked.log} sudo -u www-data touch ${INSTALL_DIR}/api/user_notifications.json # Set final permissions for all created files and directories. chown -R www-data:www-data "${INSTALL_DIR}/log" "${INSTALL_DIR}/api" chmod -R ug+rwX "${INSTALL_DIR}/log" "${INSTALL_DIR}/api" printf "%b\n" "--------------------------------------------------------------------------" printf "%b\n" "${GREEN}[INSTALLING] ${RESET}Setting up DB and CONF files" printf "%b\n" "--------------------------------------------------------------------------" # Copy starter $DB_FILE and $CONF_FILE mkdir -p "${INSTALL_DIR}/config" "${INSTALL_DIR}/db" cp -u "${INSTALL_DIR}/back/${CONF_FILE}" "${INSTALL_DIR}/config/${CONF_FILE}" cp -u "${INSTALL_DIR}/back/${DB_FILE}" "${FILEDB}" printf "%b\n" "--------------------------------------------------------------------------" printf "%b\n" "${GREEN}[CONFIGURING] ${RESET}Setting File Permissions" printf "%b\n" "--------------------------------------------------------------------------" # Restrict wide permissions; allow owner/group access chgrp -R www-data "$INSTALL_DIR" chmod -R ug+rwX,o-rwx "$INSTALL_DIR" chmod -R ug+rwX,o-rwx "$WEB_UI_DIR" # chmod -R ug+rwX "$INSTALL_DIR/log" "$INSTALL_DIR/config" chown -R www-data:www-data "$FILEDB" 2>/dev/null || true # start PHP printf "%b\n" "--------------------------------------------------------------------------" printf "%b\n" "${GREEN}[STARTING] ${RESET}Starting PHP and NGINX" printf "%b\n" "--------------------------------------------------------------------------" /etc/init.d/php8.4-fpm start nginx -t || { printf "%b\n" "--------------------------------------------------------------------------" printf "%b\n" "${RED}[ERROR] ${RESET}NGINX config test failed!" printf "%b\n" "--------------------------------------------------------------------------"; exit 1; } /etc/init.d/nginx start # Make a start script cat > "$INSTALL_DIR/start.netalertx.sh" << EOF #!/usr/bin/env bash # Activate the virtual python environment source /opt/myenv/bin/activate echo -e "--------------------------------------------------------------------------" echo -e "Starting NetAlertX - navigate to http://${SERVER_IP}:${PORT}" echo -e "--------------------------------------------------------------------------" # Start the NetAlertX python script python server/ EOF chmod +x "$INSTALL_DIR/start.netalertx.sh" # Install and manage systemd service if available, otherwise fallback to direct start if command -v systemctl >/dev/null 2>&1; then printf "%b\n" "--------------------------------------------------------------------------" printf "%b\n" "${GREEN}[INSTALLING] ${RESET}Setting up systemd service" printf "%b\n" "--------------------------------------------------------------------------" cat > /etc/systemd/system/netalertx.service << 'EOF' [Unit] Description=NetAlertX Service After=network-online.target nginx.service Wants=network-online.target [Service] Type=simple User=www-data Group=www-data ExecStart=/app/start.netalertx.sh WorkingDirectory=/app Restart=on-failure RestartSec=5 StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target EOF # Reload systemd and enable/start service systemctl daemon-reload systemctl enable netalertx.service systemctl start netalertx.service systemctl restart nginx # Verify service is running if systemctl is-active --quiet netalertx.service; then printf "%b\n" "--------------------------------------------------------------------------" printf "%b\n" "${GREEN}[SUCCESS] ${RESET}NetAlertX service started successfully" printf "%b\n" "--------------------------------------------------------------------------" else printf "%b\n" "--------------------------------------------------------------------------" printf "%b\n" "${RED}[WARNING] ${RESET}NetAlertX service may not have started properly" printf "%b\n" "--------------------------------------------------------------------------" systemctl status netalertx.service --no-pager -l fi else printf "%b\n" "--------------------------------------------------------------------------" printf "%b\n" "${GREEN}[INSTALLING] ${RESET}Starting NetAlertX (no systemd)" printf "%b\n" "--------------------------------------------------------------------------" "$INSTALL_DIR/start.netalertx.sh" & fi echo -e "--------------------------------------------------------------------------" echo -e "${GREEN}[Service] 🚀 Starting app - navigate to http://${SERVER_IP}:${PORT}" echo -e "--------------------------------------------------------------------------"