#!/bin/bash # # Copyright 2019,2023 JS Foundation and other contributors, https://js.foundation/ # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Node-RED Installer for RPM based systems unset NODERED_HOME umask 0022 usage() { cat << EOL Usage: $0 [options] options: --help display this help and exits. --nodered-user= specify the user to run as e.g. '--nodered-user=nodered'. --open-firewall adding public firewall rule for node-red port 1880. --confirm-root install as root without asking confirmation. --confirm-install confirm the installation without asking a confirmation. EOL } #NODE_VERSION="" if [ $# -gt 0 ]; then # Parsing parameters while (( "$#" )); do case "$1" in --help) usage && exit 0 shift ;; --confirm-root) CONFIRM_ROOT="y" shift ;; --confirm-install) CONFIRM_INSTALL="y" shift ;; --open-firewall) OPEN_FIREWALL="y" shift ;; --nodered-user=*) NODERED_USER="${1#*=}" shift ;; --) # end argument parsing shift break ;; -*|--*=) # unsupported flags echo "Error: Unsupported flag $1" >&2 exit 1 ;; esac done fi echo -ne "\033[2 q" echo -en "\n **************************************\n" echo -en " *** \e[1;91mNode-RED\e[0;97m \e[1;97mRPM install Script\e[0m ***\n" echo -en " **************************************\n" # sanitize environment case "${CONFIRM_ROOT}" in [Yy]* ) export CONFIRM_ROOT=y ;; [Nn]* ) export CONFIRM_ROOT=n ;; * ) export CONFIRM_ROOT=n ;; esac case "${CONFIRM_INSTALL}" in [Yy]* ) export CONFIRM_INSTALL=y ;; [Nn]* ) export CONFIRM_INSTALL=n ;; * ) export CONFIRM_INSTALL=n ;; esac # user requested, not root if [[ -n "${NODERED_USER}" ]] && [[ "${NODERED_USER}" != "root" ]] && [[ "${CONFIRM_INSTALL}" == "n" ]] then echo -en "\nThe sytem user is requested as \e[1;32m'${NODERED_USER}'\e[0m\r\n\r\n" read -p $'\e[0;97mAre you really sure you want to install as the target user \e[1;32m'"'${NODERED_USER}'"$'\e[0;97m? [\e[1;32my\e[0m/N] ?\e[0m' yn case $yn in [Yy]* ) ;; * ) exit ;; esac fi # user root requested if [[ -n "${NODERED_USER}" ]] && [[ "${NODERED_USER}" == "root" ]] && [[ "${CONFIRM_ROOT}" == "n" ]] then echo -en "\nThe sytem user is requested as \e[1;33m'${NODERED_USER}'\e[0m\r\n\r\n" read -p $'\e[0;97mAre you really sure you want to install as the target user \e[1;33m'"'${NODERED_USER}'"$'\e[0;97m? [\e[1;33my\e[0m/N] ?\e[0m' yn case $yn in [Yy]* ) ;; * ) exit ;; esac fi # no user requested, default to the current non root user if [[ "${EUID}" != "0" ]] && [[ -z "${NODERED_USER}" ]] && [[ "${CONFIRM_INSTALL}" == "n" ]] then echo -en "\e[0;97m\nNo user has been set, this script is run as user '\e[1;33m${USER}\e[0;97m'.\r\n\r\n" read -p $'\e[0;97mWould you like to change to the recommended the target user to \e[1;32m\'nodered\'\e[0;97m? [\e[1;32my\e[0m/N] ' yn case $yn in [Yy]* ) export NODERED_USER=nodered ;; * ) ;; esac fi # no user requested, default to the current root user if [[ "${EUID}" == "0" ]] && [[ -z "${NODERED_USER}" ]] && [[ "${CONFIRM_ROOT}" == "n" ]] then echo -en "\nThe current user \e[1;33mroot\e[0m defaults as the target user for node-red install.\r\n\r\n" read -p $'\e[0;97mAre you really sure you want to install as the target user \e[1;31mroot\e[0;97m ? [\e[1;31my\e[0;97m/N] ?\e[0m' yn case $yn in [Yy]* ) [[ -n "${NODERED_HOME}" ]] || export NODERED_HOME=/root; ;; * ) exit ;; esac fi if [[ -z "${OPEN_FIREWALL}" ]] && [[ "${CONFIRM_INSTALL}" == "n" ]] then OPEN_FIREWALL="n" read -r -t 15 -p $'\e[0;97mWould you like to add Node-RED port \e[34m1880\e[0;97m to the \e[1;34mfirewall\e[0;97m public zone ? [\e[1;34my\e[0;97m/N] ? ' response if [[ "$response" =~ ^([yY])+$ ]]; then OPEN_FIREWALL="y" fi fi # sanitize environment variable OPEN_FIREWALL case "${OPEN_FIREWALL}" in [Yy]* ) export OPEN_FIREWALL=y ;; [Nn]* ) export OPEN_FIREWALL=n ;; * ) export OPEN_FIREWALL=n ;; esac # this script assumes that $HOME is the folder of the user that runs node-red # that $USER is the user name and the group name to use when running is the # primary group of that user # if this is not correct then edit the lines below [[ -n "${NODERED_USER}" ]] || export NODERED_USER=$USER; [[ -n "${NODERED_HOME}" ]] || export NODERED_HOME="/home/${NODERED_USER}" # check internet, if failure exit if curl -f https://www.npmjs.com/package/node-red >/dev/null 2>&1 then echo " " else echo " " echo "Sorry - cannot connect to internet - not going to touch anything." echo "https://www.npmjs.com/package/node-red is not reachable." echo "Please ensure you have a working internet connection." echo " " exit 1 fi # final install details host=`hostname` echo -e "\e[1;33m ${host}\e[0m : \e[1;97mNode-RED update \e[0;97m" echo " " echo -e "This script will do an install of node.js and \e[1;91mNode-RED\e[0;97m" echo -e " with the service to auto-run as user \e[1;33m'${NODERED_USER}'\e[0m" echo -e " in the home directory \e[1;37m'${NODERED_HOME}'\e[0m" [[ "${OPEN_FIREWALL}" == "y" ]] && echo -e " with public \e[1;34mfirewall\e[0;97m port \e[34m1880\e[0;97m opened." echo " " # final confirmation of the install yn="${CONFIRM_INSTALL}" [[ "${yn}" == "y" ]] || read -p $'\e[1;97mAre you really \e[0m\e[1;32msure\e[1;97m you want to do this ? [\e[1;32my\e[1;97m/N] ?\e[0m' yn case "${yn}" in [Yy]* ) sudo () { [[ $EUID = 0 ]] || set -- command sudo "$@" "$@" } sudo useradd ${NODERED_USER} NODERED_GROUP=`id -gn ${NODERED_USER}` MYOS=$(cat /etc/*release | grep "^ID=" | cut -d = -f 2) versions='fedora"centos"rhel"ol"almalinux"rocky"miraclelinux"nobara"' if [[ $versions != *"${MYOS}"* ]]; then echo " " echo "Doesn't seem to be running on RedHat, Centos, Fedora, Rocky, Alma, Oracle Linux, MIRACLE LINUX or Nobara so quitting" echo " " exit 1 fi GLOBAL="true" TICK='\033[1;32m\u2714\033[0m' CROSS='\033[1;31m\u2718\033[0m' sudo cd "${NODERED_HOME}" || exit 1 clear echo -e "\n\e[0;97mRunning nodejs and Node-RED install for user '\e[1;33m${NODERED_USER}\e[0;97m' at '${NODERED_HOME}' on ${MYOS}\e[0m\n" time1=$(date) echo "" | sudo tee -a /var/log/nodered-install.log >>/dev/null echo "***************************************" | sudo tee -a /var/log/nodered-install.log >>/dev/null echo "" | sudo tee -a /var/log/nodered-install.log >>/dev/null echo "Started : "$time1 | sudo tee -a /var/log/nodered-install.log >>/dev/null echo "Running for user $USER at $HOME" | sudo tee -a /var/log/nodered-install.log >>/dev/null echo -ne ' Stop Node-RED \r\n' echo -ne ' Install Node.js \r\n' echo -ne ' Install Node-RED core \r\n' echo -ne ' Add shortcut commands \r\n' echo -ne ' Update systemd script \r\n' echo -ne ' Update public zone firewall rule \r\n' echo -ne ' \r\n' echo -ne '\r\nAny errors will be logged to /var/log/nodered-install.log\r\n' echo -ne '\033[9A' # stop any running node-red service if sudo systemctl stop nodered 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null ; then CHAR=$TICK; else CHAR=$CROSS; fi echo -ne " Stop Node-RED $CHAR\r\n" # ensure ~/.config dir is owned by the user sudo chown -Rf ${NODERED_USER}:${NODERED_GROUP} ${NODERED_HOME}/.config echo "Now install nodejs" | sudo tee -a /var/log/nodered-install.log >>/dev/null # if [ "${MYOS}" = "fedora" ] || [ "${MYOS}" = "almalinux" ] || [ "${MYOS}" = "rocky" ] || [ "${MYOS}" = "miraclelinux" ]; then # sudo dnf module reset -y nodejs 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null # if sudo dnf module install -y nodejs:18/default 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null; then CHAR=$TICK; else CHAR=$CROSS; fi # else # if [ "$EUID" == "0" ] # then # if curl -fsSL https://rpm.nodesource.com/setup_18.x | bash - 2>&1 | tee -a /var/log/nodered-install.log >>/dev/null; then CHAR=$TICK; else CHAR=$CROSS; fi # else # if curl -fsSL https://rpm.nodesource.com/setup_18.x | sudo -E bash - 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null; then CHAR=$TICK; else CHAR=$CROSS; fi # fi # if sudo yum install -y nodejs 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null; then CHAR=$TICK; else CHAR=$CROSS; fi # fi sudo yum install https://rpm.nodesource.com/pub_18.x/nodistro/repo/nodesource-release-nodistro-1.noarch.rpm -y 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null if sudo yum install nodejs -y --setopt=nodesource-nodejs.module_hotfixes=1 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null; then CHAR=$TICK; else CHAR=$CROSS; fi echo -ne " Install Node.js LTS $CHAR" # sudo npm i -g npm 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null; hash -r rc="" if nov=$(node -v 2>/dev/null); then :; else rc="ERR"; fi if npv=$(npm -v 2>/dev/null); then :; else rc="ERR"; fi if [[ $rc == "" ]]; then echo -ne " Node $nov Npm $npv\r\n" else echo -ne "\b$CROSS Failed to install Node.js - Exit\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n" exit 2 fi # clean up the npm cache and node-gyp # and install Node-RED echo "Now install Node-RED" | sudo tee -a /var/log/nodered-install.log >>/dev/null if sudo npm i -g --unsafe-perm --no-progress node-red@latest 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null; then CHAR=$TICK; else CHAR=$CROSS; fi nrv=$(npm --no-progress -g ls node-red | grep node-red | cut -d '@' -f 2 | sudo tee -a /var/log/nodered-install.log) >>/dev/null 2>&1 echo -ne " Install Node-RED core $CHAR $nrv\r\n" echo "Now create basic package.json for the user" | sudo tee -a /var/log/nodered-install.log >>/dev/null sudo lastlog -u ${NODERED_USER} -C >>/dev/null 2>&1 sudo su - ${NODERED_USER} <<'EOF' cd mkdir -p ".node-red/node_modules" cd .node-red npm config set update-notifier false #2>&1 >>/dev/null if [ ! -f "package.json" ]; then echo '{' > package.json echo ' "name": "node-red-project",' >> package.json echo ' "description": "initially created for you by Node-RED '$nrv'",' >> package.json echo ' "version": "0.0.1",' >> package.json echo ' "dependencies": {' >> package.json echo ' }' >> package.json echo '}' >> package.json fi EOF echo "Now add start/stop/reload/log scripts" | sudo tee -a /var/log/nodered-install.log >>/dev/null sudo mkdir -p /usr/bin if curl -f https://raw.githubusercontent.com/node-red/linux-installers/master/resources/node-red-icon.svg >/dev/null 2>&1 then sudo curl -sL -o /usr/bin/node-red-start https://raw.githubusercontent.com/node-red/linux-installers/master/resources/node-red-start.rpm 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null sudo curl -sL -o /usr/bin/node-red-stop https://raw.githubusercontent.com/node-red/linux-installers/master/resources/node-red-stop 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null sudo curl -sL -o /usr/bin/node-red-restart https://raw.githubusercontent.com/node-red/linux-installers/master/resources/node-red-restart 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null sudo curl -sL -o /usr/bin/node-red-reload https://raw.githubusercontent.com/node-red/linux-installers/master/resources/node-red-reload 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null sudo curl -sL -o /usr/bin/node-red-log https://raw.githubusercontent.com/node-red/linux-installers/master/resources/node-red-log 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null sudo curl -sL -o /etc/logrotate.d/nodered https://raw.githubusercontent.com/node-red/linux-installers/master/resources/nodered.rotate 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null sudo chmod +x /usr/bin/node-red-start sudo chmod +x /usr/bin/node-red-stop sudo chmod +x /usr/bin/node-red-restart sudo chmod +x /usr/bin/node-red-reload sudo chmod +x /usr/bin/node-red-log echo -ne " Add shortcut commands $TICK\r\n" else echo -ne " Add shortcut commands $CROSS\r\n" fi # add systemd script and configure it for ${NODERED_USER} echo "Now add systemd script and configure it for ${NODERED_USER}:${NODERED_GROUP} @ ${NODERED_HOME}" | sudo tee -a /var/log/nodered-install.log >>/dev/null # check if systemd script already exists SYSTEMDFILE="/etc/systemd/system/nodered.service" if sudo curl -sL -o ${SYSTEMDFILE}.temp https://raw.githubusercontent.com/node-red/linux-installers/master/resources/nodered.service 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null; then CHAR=$TICK; else CHAR=$CROSS; fi # set the User,Group,EnvironmentFile and WorkingDirectory in nodered.service sudo sed -i 's#^User=pi#User='${NODERED_USER}'#; s#^Group=pi#Group='${NODERED_GROUP}'#; s#^WorkingDirectory=/home/pi#WorkingDirectory='${NODERED_HOME}'#; s#^EnvironmentFile=-/home/pi/.node-red#EnvironmentFile=-/etc/node-red#; s!^Environment="NODE_OPTIONS=--max_old_space_size=512"!#Environment="NODE_OPTIONS=--max_old_space_size=512"!' ${SYSTEMDFILE}.temp if test -f "${SYSTEMDFILE}"; then # there's already a systemd script EXISTING_FILE=$(md5sum ${SYSTEMDFILE} | awk '$1 "${SYSTEMDFILE}" {print $1}'); TEMP_FILE=$(md5sum ${SYSTEMDFILE}.temp | awk '$1 "${SYSTEMDFILE}.temp" {print $1}'); if [[ $EXISTING_FILE == $TEMP_FILE ]]; then : # silent procedure else echo "Customized systemd script found @ ${SYSTEMDFILE}. To prevent loss of modifications, we'll not recreate the systemd script." | sudo tee -a /var/log/nodered-install.log >>/dev/null echo "If you want the installer to recreate the systemd script, please delete or rename the current script & re-run the installer." | sudo tee -a /var/log/nodered-install.log >>/dev/null CHAR="- Skipped - existing script is customized." fi sudo rm ${SYSTEMDFILE}.temp else sudo mv ${SYSTEMDFILE}.temp ${SYSTEMDFILE} fi # make environment file for systemd sudo mkdir -p /etc/node-red if test ! -f /etc/node-red/environment; then echo "# Node-RED EnvironmentFile for Systemd Service" | sudo tee -a /etc/node-red/environment >>/dev/null echo "# after edit this file `sudo systemctl restart nodered` to reload Node-red with the new options" | sudo tee -a /etc/node-red/environment >>/dev/null echo "" | sudo tee -a /etc/node-red/environment >>/dev/null echo "# uncomment and edit if running on low memory resource hardware" | sudo tee -a /etc/node-red/environment >>/dev/null echo "#NODE_OPTIONS=--max_old_space_size=512" | sudo tee -a /etc/node-red/environment >>/dev/null echo "" | sudo tee -a /etc/node-red/environment >>/dev/null echo "# uncomment next line and edit if you need an http proxy" | sudo tee -a /etc/node-red/environment >>/dev/null echo "#HTTP_PROXY=my.httpproxy.server.address" | sudo tee -a /etc/node-red/environment >>/dev/null echo "" | sudo tee -a /etc/node-red/environment >>/dev/null echo "# uncomment the next line for a more verbose log output" | sudo tee -a /etc/node-red/environment >>/dev/null echo "#NODE_RED_OPTIONS=-v" | sudo tee -a /etc/node-red/environment >>/dev/null echo "" | sudo tee -a /etc/node-red/environment >>/dev/null echo "Created /etc/node-red/environment for systemd service." | sudo tee -a /var/log/nodered-install.log >>/dev/null fi sudo systemctl daemon-reload 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null echo -ne " Update systemd script $CHAR\r\n" if [[ ${OPEN_FIREWALL} == "y" ]]; then echo "Now add firewall rule for 1880" | sudo tee -a /var/log/nodered-install.log >>/dev/null if sudo curl -sL -o /etc/firewalld/services/nodered.xml https://raw.githubusercontent.com/node-red/linux-installers/master/resources/nodered.xml 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null; then CHAR=$TICK; else CHAR=$CROSS; fi sudo firewall-cmd --zone=public --add-service=nodered 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null sudo firewall-cmd --reload 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null sudo firewall-cmd --zone=public --add-service=nodered --permanent 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null sudo firewall-cmd --reload 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null echo -ne " Update public zone firewall rule $CHAR\r\n" else echo "Not adding firewall rule" | sudo tee -a /var/log/nodered-install.log >>/dev/null echo -ne " Not adding firewall rule -\r\n" fi echo -ne "\r\n\r\n\r\n" echo -ne "All done.\r\n" echo -ne " You can now start Node-RED with the command \033[0;36mnode-red-start\033[0m\r\n" echo -ne " Then point your browser to \033[0;36mlocalhost:1880\033[0m or \033[0;36mhttp://{your_ip-address}:1880\033[0m\r\n" echo -ne "\r\nStarted $time1 - Finished $(date)\r\n\r\n" echo "Finished : "$time1 | sudo tee -a /var/log/nodered-install.log >>/dev/null ;; * ) echo " " exit 1 ;; esac