Skip to content

Commit b65d825

Browse files
authored
Merge pull request #8 from virtuosoft-dev/version2.0.0
Version2.0.0
2 parents 218bb11 + a2f3cd6 commit b65d825

File tree

10 files changed

+639
-140
lines changed

10 files changed

+639
-140
lines changed

README.md

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# hcpp-nodeapp
22
A plugin for Hestia Control Panel (via [hestiacp-pluginable](https://github.com/virtuosoft-dev/hestiacp-pluginable)) that enables hosting generic NodeJS based applications with control via [PM2 (Process Manager)](https://pm2.keymetrics.io). With this plugin installed, user accounts can host their own NodeJS applications. A simple [Hello World! ExpressJS application](https://expressjs.com/en/starter/hello-world.html) is included as the default NodeApp application. [NVM (NodeJS Version Manager)](https://github.com/nvm-sh/nvm) is also included and the default PM2 configuration file will automatically select the proper NodeJS version based on the simple .nvmrc file.
33

4+
Version 2.0.0 now includes a (PM2 based) process list UI within HestiaCP that lists all NodeApps for a given user account under the Web tab (see #1 in screenshot below). Additional controls have been added to allow for Start, Stop, and Restart with bulk actions and viewing of the log output for each NodeApp process (see #2 in screenshot below).
45

5-
6-
7-
6+
<br><img src='images/nodeapp-pm2.jpg' width='100%'><br>
7+
<sub>Figure 1 - NodeApp process list, control, and logs</sub>
88

99
Long term support NodeJS versions that are automatically installed with this plugin include:
1010

@@ -13,57 +13,54 @@ Long term support NodeJS versions that are automatically installed with this plu
1313
* Iron v20
1414
* Jod v22
1515

16-
&nbsp;
17-
## Installation
18-
HCPP-NodeApp requires an Ubuntu or Debian based installation of [Hestia Control Panel](https://hestiacp.com) in addition to an installation of [HestiaCP-Pluginable](https://github.com/virtuosoft-dev/hestiacp-pluginable) to function; please ensure that you have first installed pluginable on your Hestia Control Panel before proceeding. Switch to a root user and simply clone this project to the /usr/local/hestia/plugins folder. It should appear as a subfolder with the name `nodeapp`, i.e. `/usr/local/hestia/plugins/nodeapp`.
16+
NodeApp also includes an updated administrator's [Server Settings -> Updates]() screen (see figure 2 below) that shows the current state of NVM NodeJS versions. All versions are automatically updated and maintained along with any global modules when HestiaCP's native [Enable Automatic Updates]() option is turned on.
1917

20-
First, switch to root user:
21-
```
22-
sudo -s
23-
```
18+
<br><img src='images/updates.png' width='100%'><br>
2419

25-
Then simply clone the repo to your plugins folder, with the name `nodeapp`:
20+
&nbsp;
21+
## Installation
22+
HCPP-NodeApp requires an Ubuntu or Debian based installation of [Hestia Control Panel](https://hestiacp.com) in addition to an installation of [HestiaCP-Pluginable](https://github.com/virtuosoft-dev/hestiacp-pluginable) to function; please ensure that you have first installed pluginable on your Hestia Control Panel before proceeding. Clone the latest release version (i.e. replace **v2.0.0** below with the latest release version) to the nodeapp folder:
2623

2724
```
2825
cd /usr/local/hestia/plugins
29-
git clone https://github.com/virtuosoft-dev/hcpp-nodeapp nodeapp
26+
sudo git clone --branch v2.0.0 https://github.com/virtuosoft-dev/hcpp-nodeapp nodeapp
3027
```
3128

3229
Note: It is important that the destination plugin folder name is `nodeapp`.
3330

34-
3531
Be sure to logout and login again to your Hestia Control Panel as the admin user or, as admin, visit Server (gear icon) -> Configure -> Plugins -> Save; the plugin will immediately start installing NodeJS depedencies in the background.
3632

3733
<br><img src='images/nodeapp-notify.jpg' width='50%'><br>
38-
<sub>Figure 1 - NodeApp plugin install notification</sub>
34+
<sub>Figure 3 - NodeApp plugin install notification</sub>
3935

4036
A notification will appear under the admin user account indicating *"NodeApp plugin has finished installing"* when complete. This may take awhile before the options appear in Hestia. You can force manual installation via:
4137

4238
```
4339
cd /usr/local/hestia/plugins/nodeapp
44-
./install
45-
touch "/usr/local/hestia/data/hcpp/installed/nodeapp"
40+
sudo ./install
41+
sudo touch "/usr/local/hestia/data/hcpp/installed/nodeapp"
4642
```
4743

4844
&nbsp;
4945
## Using NodeApp to Host a NodeJS Website
5046
The Hestia user account to be associated with a new web domain must have bash SSH access. This is to allow Hestia to switch to their user account to start and stop the NodeJS application. Login as the admin user in Hestia to grant bash SSH Access. Simply edit the Hestia user account; 1) Click the *'Advanced Options'* button after ***'Edit User'*** and 2) Select `bash` from the combobox under ***'SSH Access'***, and save the changes (see image below).
5147

5248
<br><img src='images/enable-bash.jpg' width='50%'><br>
53-
<sub>Figure 2 - Enable Bash for domain</sub>
49+
<sub>Figure 4 - Enable Bash for domain</sub>
5450

5551
The basic default NodeJS application is the [Hello World! ExpressJS application](https://expressjs.com/en/starter/hello-world.html). To use it, simply select the user account (that has bash SSH access enabled), and add a web domain. Edit the web domain; 1) Click the ***'Advanced Options'*** and 2) Select `NodeApp` in the ***'Proxy Template'*** combobox (if the option is missing, wait for installation to complete or attempt manual installation instructions above).
5652

5753
<br><img src='images/nodeapp.jpg' width='50%'><br>
58-
<sub>Figure 3 - Selecting a Proxy Template</sub>
54+
<sub>Figure 5 - Selecting a Proxy Template</sub>
5955

6056
## Root NodeJS Application Hosting
6157
Using the NodeApp proxy template will allow you to host a NodeJS application from the web domain root (for a subfolder, see **'Subfolder NodeJS Application below'**). The example above will serve the NodeJS application using PM2. After saving your changes, you should be able to visit the web domain and see the `Hello World!` text on a white background. The basic NodeJS Express application lives in the `app.js` file which is located in the nodeapp folder. I.e. for the user "johnsmith" on "example.com", the filename path for the application would be at `/home/johnsmith/web/example.com/nodeapp/app.js`. Hestia control panel will automatically stop the NodeJS application when you select a different proxy template for the domain and restart it when you select NodeApp again. Likewise if you delete the domain, Hestia will free the allocated port from the pool of ports on the system and shutdown the NodeJS app prior to deleting the web domain.
6258

6359
## Subfolder NodeJS Application Hosting
64-
The HCPP-NodeApp plugin automatically scans the nodeapp folder for any additional PM2 configuration files (*.config.js) in subfolders (excluding node_modules). If it finds any such files, NodeApp plugin will automatically allocate an application port and auto-generate an Nginx include file, defininig the subfolder path, for addendum to whichever backend proxy template is selected. This allows you to automatically mix the hosting of multiple applications under a single domain. For instance, you can select Hestia's default backend template to host a PHP based application in root (such as WordPress), while hosting a NodeJS based applicaiton in a subfolder (such as nodeBB, or Node-RED). Simply create a subfolder within the nodeapp folder and place a valid, unique, *&lt;application name&gt;*.config.js file within the subfolder. You can simply copy the app.config.js file; replace *'app'* with your own application name (be sure to update the package.json's *'main'* property from *'app'* too). Nginx will be configured to serve the NodeJS application under the given subfolder (i.e. www.example.com/nodebb). Note: the *&lt;application name&gt;*.config.js file name must be unique for a given domain. For example, you cannot have two app.config.js files; even if one exists in a subfolder. Instead, i.e. name the second file app2.config.js.
60+
The HCPP-NodeApp plugin automatically scans the nodeapp folder for any additional PM2 configuration files (*.config.js) in subfolders (excluding node_modules). If it finds any such files, NodeApp plugin will automatically allocate an application port and auto-generate an Nginx include file, defininig the subfolder path, for addendum to whichever backend proxy template is selected. This allows you to automatically mix the hosting of multiple applications under a single domain. For instance, you can select Hestia's default backend template to host a PHP based application in root (such as WordPress), while hosting a NodeJS based applicaiton in a subfolder (such as VitePress, or Node-RED). Simply create a subfolder within the nodeapp folder and place a valid, unique, *&lt;application name&gt;*.config.js file within the subfolder. You can simply copy the app.config.js file; replace *'app'* with your own application name (be sure to update the package.json's *'main'* property from *'app'* too). Nginx will be configured to serve the NodeJS application under the given subfolder (i.e. www.example.com/nodebb). Note: the *&lt;application name&gt;*.config.js file name must be unique for a given domain. For example, you cannot have two app.config.js files; even if one exists in a subfolder. Instead, i.e. name the second file app2.config.js.
61+
62+
Likewise, you can select the backend proxy template `NodeApp` and host two NodeJS applications, one from root, and another in a subfolder. Note that the scanning for *.config.js files, automatic allocation of proxy ports, auto-generation of Nginx addendum files, and automatic startup of NodeJS, only takes place when Nginx services are restarted; you can invoke a restart by selecting/re-selecting a different Proxy Template (see figure 4 above) or using HestiaCP's *`suspend'* and *'unsuspend'* actions. You may use suspend/unsuspend options to populate the NodeApp process list.
6563

66-
Likewise, you can select the backend proxy template `NodeApp` and host two NodeJS applications, one from root, and another in a subfolder. Note that the scanning for *.config.js files, automatic allocation of proxy ports, auto-generation of Nginx addendum files, and automatic startup of NodeJS, only takes place when Nginx services are restarted; you can invoke a restart by selecting/re-selecting a different Proxy Template (see figure 3 above) or using HestiaCP's *`suspend'* and *'unsuspend'* actions.
6764

6865
## Conclusion
6966
With the HCPP-NodeApp plugin, you do not need to configure ports, create Ngnix templates, or customize any templates. The plugin will automatically allocate ports for each user account and web domain (as well as clean them up when they are deleted). It will furnish a unique NodeJS instance using an advanced process manager with watch dog, as well as configure Nginx to securely display the app on your designated web domain or domain subfolder (or both). Your web development stack will be able to leverage the latest in NodeJS technology, use websockets, and run multiple users, and web domains all from the Hestia control panel.
@@ -77,9 +74,19 @@ the NodeApp. Developers can hook and implement their own NodeApp using these act
7774
* **nodeapp_install_dependencies** - *occurs before `"npm install"`, allows filtering the command.*
7875
* **nodeapp_startup_services** - *occurs before `"pm2 start app.config.js"`, allows filtering the command.*
7976
* **nodeapp_shutdown_services** - *occurs before `"pm2 delete app.config.js"`, allows filtering the command.*
80-
* **nodeapp_subfolder_nginx_conf** - *occurs before writing Nginx conf file for subfolder app hosting.*
81-
* **nodeapp_subfolder_nginx_ssl_conf** - *occurs before writing Nginx SSL conf file for subfolder app hosting.*
77+
* **nodeapp_write_conf_nodeapp** - *occurs before writing nginx.conf_nodeapp file for app hosting.*
78+
* **nodeapp_write_ssl_conf_nodeapp** - *occurs before writing nginx.ssl.conf_nodeapp file for app hosting.*
79+
* **nodeapp_nginx_confs_written** - *occurs after nginx.conf and nginx.ssl.conf have been written.*
8280
* **nodeapp_resurrect_apps** - *occurs after system reboot and issues the command to restart PM2 apps.*
81+
* **nodeapp_xpath** - *occurs when viewing the NodeApp process list.*
82+
* **nodeapp_html** - *occurs when viewing the NodeApp process list.*
83+
* **nodeapplog_xpath** - *occurs when viewing the NodeApp process log.*
84+
* **nodeapplog_html** - *occurs when viewing the NodeApp process log.*
85+
* **nodeapp_maintenance_start** - *occurs before a maintenance event starts.*
86+
* **nodeapp_maintenance_start** - *occurs after a maintenance event ends.*
87+
* **nodeapp_update_nodejs** - *occurs when a nodejs version is about to be updated.*
88+
* **nodeapp_autoupdate** - *occurs daily if hestia autoupdates is enabled; ideal time perform updates (do_maintenance) tasks.*
89+
8390

8491
## Support the creator
8592
You can help this author's open source development endeavors by donating any amount to Stephen J. Carnam @ Virtuosoft. Your donation, no matter how large or small helps pay for essential time and resources to create MIT and GPL licensed projects that you and the world can benefit from. Click the link below to donate today :)

benchmark

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#!/bin/bash
2+
#
3+
# @author Stephen J. Carnam
4+
# @license GNU GENERAL PUBLIC LICENSE Version 2
5+
# @link https://steveorevo.com
6+
#
7+
8+
# Check if a command is provided
9+
if [ -z "$1" ]; then
10+
echo "Usage: benchmark <command>"
11+
exit 1
12+
fi
13+
14+
# Capture the start time in nanoseconds
15+
start_time=$(date +%s%N)
16+
17+
# Run the provided command
18+
"$@"
19+
20+
# Capture the end time in nanoseconds
21+
end_time=$(date +%s%N)
22+
23+
# Calculate the elapsed time in seconds with fractional seconds
24+
elapsed_time=$(echo "scale=6; ($end_time - $start_time) / 1000000000" | bc)
25+
26+
# Format the elapsed time
27+
minutes=$(echo "$elapsed_time / 60" | bc)
28+
seconds=$(echo "$elapsed_time % 60" | bc)
29+
30+
if (( $(echo "$minutes > 0" | bc -l) )); then
31+
printf "Time taken: %d minutes and %.6f seconds\n" "$minutes" "$seconds"
32+
else
33+
printf "Time taken: %.6f seconds\n" "$seconds"
34+
fi

images/nodeapp-pm2.jpg

65.3 KB
Loading

images/updates.png

48.4 KB
Loading

install

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ fi
1414
# apt remove --purge nodejs -y
1515

1616
# Get prerequisites, latest NVM version, and build tools if we need to compile from source
17-
apt-get install -y curl build-essential gnupg2
17+
apt-get install -y curl build-essential gnupg2 rsync
1818
LATEST_VERSION=$(curl -s https://api.github.com/repos/nvm-sh/nvm/releases/latest | grep '"tag_name":' | cut -d '"' -f 4)
1919
curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/${LATEST_VERSION}/install.sh | bash
2020
source ~/.bashrc
@@ -75,5 +75,29 @@ EOT
7575

7676
fi
7777

78+
# Comment out /root/.bashrc
79+
BASHRC_FILE="/root/.bashrc"
80+
81+
# Lines to search for
82+
NVM_LINES=(
83+
'export NVM_DIR="$HOME/.nvm"'
84+
'[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"'
85+
'[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"'
86+
)
87+
88+
# Iterate over each line and comment it out if not already commented
89+
for line in "${NVM_LINES[@]}"; do
90+
# Escape special characters in the line for use in grep and sed
91+
escaped_line=$(printf '%s\n' "$line" | sed 's/[.[\*^$(){}?+|]/\\&/g')
92+
93+
# Check if the line exists and is not already commented
94+
if grep -q "$escaped_line" "$BASHRC_FILE" && ! grep -q "# $escaped_line" "$BASHRC_FILE"; then
95+
sed -i "s|$escaped_line|# $line|" "$BASHRC_FILE"
96+
echo "Commented out: $line"
97+
else
98+
echo "Line not found or already commented: $line"
99+
fi
100+
done
101+
78102
# Notify installation has finished
79103
/usr/local/hestia/bin/v-add-user-notification admin NodeApp "<span style=\"font-size:large;color:green;\">&#11042;</span> NodeApp plugin has finished installing."

nodeapp.js

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
* @param {*} path - the path to the *.config.js file, contains the user, domain, etc.
66
*/
77

8+
const { version } = require('os');
9+
810
module.exports = function(path) {
911
// Get the app name, user, domain, other details given the file path
1012
const fs = require('fs');
@@ -13,7 +15,7 @@ module.exports = function(path) {
1315
details._config = parse.pop();
1416
details._app = details._config.replace('.config.js', '');
1517
details._domain = parse[4];
16-
details.name = details._app + '-' + details._domain;
18+
details.name = details._app + ' | ' + details._domain;
1719
details._user = parse[2];
1820
details.cwd = path.substr(0, path.length - details._config.length - 1);
1921
details.script = details.cwd + '/' + details._app + '.js';
@@ -36,6 +38,15 @@ module.exports = function(path) {
3638
}
3739
details.interpreter = ver;
3840

41+
// Get the interpreter version from path
42+
let versionMatch = ver.match(/v\d+\.\d+\.\d+/); // Regular expression to match 'v' followed by version numbers
43+
if (versionMatch) {
44+
let version = versionMatch[0]; // Extract the matched version
45+
details.version = version;
46+
} else {
47+
console.error('Version not found in the path');
48+
}
49+
3950
// Pass the allocated port number as a -p argument
4051
let port = 0;
4152
let pfile = '/usr/local/hestia/data/hcpp/ports/' + details._user + '/' + details._domain + '.ports';
@@ -56,5 +67,33 @@ module.exports = function(path) {
5667
details._debugPort = port + 3000;
5768
details.interpreter_args = '--inspect=' + details._debugPort;
5869
}
70+
71+
72+
details.linkGlobalModules = function(modules) {
73+
74+
// Ensure node_modules directory exists
75+
const nodeModulesPath = this.cwd + '/node_modules';
76+
if (!fs.existsSync(nodeModulesPath)) {
77+
fs.mkdirSync(nodeModulesPath);
78+
}
79+
80+
// Setup nvm, use npm version specified in .nvmrc
81+
let cmd = "bash -c 'export NVM_DIR=/opt/nvm && source /opt/nvm/nvm.sh && nvm use " + this.version + " && ";
82+
cmd += "cd " + this.cwd + " && ";
83+
84+
// Link global modules to local node_modules
85+
for (let i = 0; i < modules.length; i++) {
86+
cmd += "unlink node_modules/" + modules[i] + " > /dev/null 2>&1 ; npm link " + modules[i] + " > /dev/null 2>&1 ; ";
87+
}
88+
cmd += "'";
89+
90+
// Update npm links
91+
try {
92+
const {execSync} = require('child_process');
93+
execSync(cmd);
94+
} catch (error) {
95+
// Eat npm link permissions errors
96+
}
97+
}
5998
return details;
6099
}

0 commit comments

Comments
 (0)