When development and the testing is done, we need to deploy to online machine and then provide services.
If project code needs to be compiled, though it outputs app/
directory from src/
, we suggest to run command npm run compile
during deployement, to avoid some unexpected impact. Or pull the latest code in a clean directory and execute the compile command.
If you modify the babel preset, then you need to modify the compile command (babel src/ --presets think-node --out-dir app/) in package.json the corresponding changes.
If the code does not need translation, then deploy src/
directory can be.
When the project is created, a file named production.js
is automatically created in root directory, which is the entry file for the production environment and definesenv
as production
. Never use development.js
in the production environment as an entry file to start the service.
PM2 is specific designed module for Node.js service management. PM2 need to be install globally:
sudo npm install -g pm2
After installation, we have pm2
command line command.
When project is created, a file named pm2.json
is created in root directory, of which content is as bellow:
{
"apps": [{
"name": "demo",
"script": "production.js",
"cwd": "/Users/welefen/Develop/git/thinkjs/demo",
"max_memory_restart": "1G",
"autorestart": true,
"node_args": [],
"args": [],
"env": {}
}]
}
Change name
to your project name, and modify cwd
field to online project path.
Run pm2 start pm2.json
on project root directory to start application, and you will see the following information:
When there is code changed, we need to restart service to make it effective.
The easiest way to restart service is through pm2 restart pm2.json
, but this approch can result in temporary service interruptions. (restarting the service takes time and restarting can result in inability to process user requests which cause service interruption). If you don't want service interruption, then you can send a signal to restart, the specific code:
pm2 sendSignal SIGUSR2 pm2.json
pm2 will send SIGUSR2
singal to framework, after the main process capture this signal, it will fork a new child process for incomming service, and then gradually close previous child process so as to achiveve none-interrupt service restart.
Framework will force the use of cluster, and provide service in master/worker way, so you can't open cluster mode in pm2
(if you open, service will report errors and exist on start up).
If you don't want to use PM2 to manage service in production environment, you can manually manage it through a script, , first run `node production.js' to start service.
When service is start up and accessible, start service with nohub node production.js &
, nohub
and &
means run service in background, after that you can see a log similar to the following:
$ nohup node production.js &
[2] 1114
appending output to nohup.out
After seeing the output, press Enter, execute the exit
command to exit the current terminal, so the service is running in the background.
After the start is complete, you can see the specific node process by ps aux | grep node
:
welefen 3971 0.0 0.3 3106048 46244 s001 S+ 11:14AM 0:00.65 /usr/local/bin/node /Users/welefen/demo/production.js
welefen 3970 0.0 0.3 3106048 46064 s001 S+ 11:14AM 0:00.64 /usr/local/bin/node /Users/welefen/demo/production.js
welefen 3969 0.0 0.3 3106040 46248 s001 S+ 11:14AM 0:00.65 /usr/local/bin/node /Users/welefen/demo/production.js
welefen 3968 0.0 0.3 3106048 46400 s001 S+ 11:14AM 0:00.65 /usr/local/bin/node /Users/welefen/demo/production.js
welefen 3967 0.0 0.3 3106048 46608 s001 S+ 11:14AM 0:00.65 /usr/local/bin/node /Users/welefen/demo/production.js
welefen 3966 0.0 0.3 3106048 46432 s001 S+ 11:14AM 0:00.65 /usr/local/bin/node /Users/welefen/demo/production.js
welefen 3965 0.0 0.3 3106040 46828 s001 S+ 11:14AM 0:00.65 /usr/local/bin/node /Users/welefen/demo/production.js
welefen 3964 0.0 0.3 3106048 46440 s001 S+ 11:14AM 0:00.64 /usr/local/bin/node /Users/welefen/demo/production.js
welefen 3963 0.0 0.2 3135796 40960 s001 S+ 11:14AM 0:00.31 node production.js
The first few are fork process, the last one is master process.
When the code changes requires restart the service, the easiest way is to find the main process pid, kill the process by kill -9 PID
and then restart. If you do not want to interrupt the service, you can send SIGUSR2
signal to the main process to finish:
kill -s USR2 PID
For example, the master process's pid being printed in log above is 3963, you can kill -s USR2 3963
to restart the service without interruption. Of course, it is troublesome to do so everytime, you can create a simple script for that.
#!/bin/sh
cd PROJECT_PATH; # enter root directory
nodepid=`ps auxww | grep node | grep production.js | grep -v grep | awk '{print $2}' `
if [ -z "$nodepid" ]; then
echo 'node service is not running'
nohup node production.js > ~/file.log 2>&1 &
else
echo 'node service is running'
kill -s USR2 $nodepid 2>/dev/null
echo 'gracefull restart'
fi
Although Node.js itself can directly create HTTP(S) services, it is not recommand so in production environment, instead uses WebServer (such as: nginx) in front, which has several benefits:
When creating a project, a configuration file named nginx.conf
is created in the project root directory:
server {
listen 80;
server_name example.com www.example.com;
root /Users/welefen/Downloads/demo/www;
set $node_port 8360;
index index.js index.html index.htm;
if ( -f $request_filename/index.html ){
rewrite (.*) $1/index.html break;
}
if ( !-f $request_filename ){
rewrite (.*) /index.js;
}
location = /index.js {
proxy_http_version 1.1;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://127.0.0.1:$node_port$request_uri;
proxy_redirect off;
}
location ~ /static/ {
etag on;
expires max;
}
}
server_name
,root
, port
field value is configured according to the actual situation, and then the configuration file is soft link to the nginx configuration file directory, and finally restart the nginx service (you can nginx -s reload
to reload the configuration file).
If you still want to provide services directly through Node.js, it is also possible to listen directly to port 80 or port 443 (some environments require sudo
to listen on these two ports).
Modern websites highly suggest using HTTPS to provide the security of the website content and prevent the content from being intercepted and tampered with. If you do not want to pay for a certificate, you can use the free SSL/TLS certificate provided by Let's Encrypt, which can be found in the article Let's Encrypt 免费好用的证书.
On project initiation, it will auto-generate middleware config file src/config/middleware.js
(multi-module project src/common/config/middleware.js
). There is a middleware for handling static resources request, but this middleware by default only for development environment, so you will see static resources can not access after going online.
It is recommanded to use nginx to handle static resource online, of which performance will be higher and lower load for Node service. If you still want to use framework to deal with static resource requests, modify src/config/middleware.js
to enable this middleware can do so.
module.exports = [
...
{
handle: 'resource',
enable: true // always open, default is `enable: isDev` which means only open in development environment
},
...
]