Starting a server on a local machine is straightforward because we just run this simple line.
node app.js
Well, it's not so easy if you are planning to run the application on a server for real users.
I use Express.js's Hello world in this article as a simple example. Just in addition, I've added the morgan library for detailed logging.
You can find the application source code here.
A pretty simple example, isn't it?
It works without issues. Just whenever we close this terminal's session, we will not see the results anymore.
Why?
Because it's the terminal session that keeps the Node.js application alive.
As you may already understand, we don't use the node command to run the application in production. We need to use tools like PM2, Docker or something else in production. This article isn't about those tools.
Whenever I talk about this topic, I remember a funny story about how I solved this problem with my friend when we first saw this issue at the beginning of our journey to engineering.
I will tell you the story because there is much to share.
Back in those days, when who knew about the tools or services like PM2, Heroku, etc. We barely made a Node.js application. And we wanted to run it for real users.
We created a DigitalOcean server and chose Ubuntu as an operating system.
Simply running the application with the node command, we were happy as it was working for everyone. But whenever we closed the ssh session, the application stopped working.
So we started to think about some ideas.
We will discuss some native UNIX tools that helped us solve this issue.
But the IDEA is not something you need to use for your application to make it available for everyone.
Overall the tools are interesting. And they may be helpful for you in your journey.
So, let's get started!
&
We can run a specific process in the background when we add this symbol at the end of our shell command. The environment where the process runs is called a subshell.
As we added a & symbol at the end of the command, it will start the process in the background.
1* The number we see below the command is the PID (process identifier).
Despite that, the command runs in the background but still shows the logs in the terminal. It's ok. We can ignore the logs and run any command.
Bellow, we run the ps command to check the active processes.
2* As we can see, the application is listed there. We can verify that with the PID. The line starts with the 26347 number, which represents the corresponding process identifier. It's the same number we got after running the application(*1).
TTY
In the result list, we also see TTY values. It shows the association between the processes and terminal sessions. In my case first five processes are related to the WebStorm editor. Each one has his tty name. And if we look at the commands, we will probably guess that each process is a simple terminal session in the editor because those are simple bash processes.
Let's understand the TTY value of our particular process. Which, in my case, is ttys005
. This is the current terminal name. We ran the application in the current terminal, so that's why the ps result list contains this tty name.
who am i OR tty
How can we verify that the current terminal name is actually ttys005
?
3* Try to run who am i
eather tty
commands, they will return the current terminal name.
But wait a second. Why do we have three processes for ttys005
?
It's simple. Because, in my case, I use a terminal called iTerm.
If I try to open a new terminal, it automatically runs two processes, the first is iTerm's internal process, and the second one is the bash. In your case, you may have the bash and application processes.
> /dev/null
4* In the end, we see some logs related to our application.
As I mentioned, logs will be visible here, even in case it's running in the background.
To prevent it, add > /dev/null
to the command.
node app.js > /dev/null &
This means that stdout will go to /dev/null (logs will not be recorded here).
2>&1
Additionally, you can also add2>&1
, which means that stderr also will go to the stdout (which is already redirected to /dev/null
).
node app.js > /dev/null 2>&1 &
Well, there here is a better workaround for this case. We will get back to it soon.
It seems we discussed everything, but there is one crucial thing.
If we close the terminal, then subshell will be killed too.
disown
It removes the process from the shell's processes. So whenever we kill the shell session/terminal, the process will not be killed because disown prevents SIGHUP
signal, which is sent to the process when the terminal is closed.
node app.js > /dev/null & disown
Try to run this command. Then close the terminal, and check the browser.
Wooala, it works!
Now, we can't run processes on the same port anymore. We have to kill the active process. For that, we need the PID. We can find the process information using this command.
ps aux | grep node
grep helps us to filter the lines containing the node keyword.
Here we get the PID.
And using the command from the picture, we can kill the active Node process.
kill -9 PID
As the PORT it's not used anymore, we can run the application on that PORT.
I mentioned that there is a better workaround for logging.
The solutions which I've shown you are imperfect. It will be better if we keep them somewhere for future debuggings.
nohup
nohup node app.js &
This command also prevents the SIGHUP
signals that will kill the process if the terminal is closed. So it's similar to disown command.
After running this command, you will notice a new file in that directory. It's called nohup.out
. nohup will save all the logs of that process inside that file.
So basically, this command is the combination of the last three things that we have discussed.
This is how we started our application in production until we learned that we need to use better tools to prevent the process's exit when the ssh session is closed.
Summary
Overall we discussed many UNIX native commands that can be useful for you in the future.
ps, &, disown, nohup, grep, kill, tty, who am i …
Please research more about these commands. You can understand better use cases.
I just wanted to share our experiences and how we learned about them.
And I want to thank my best friend Varik, with whom I had such a joyful journey, and I'm sure we will have more.
Thank you, feel free to ask any questions or tweet me @nairihar
Also follow my “JavaScript Universe” newsletter on Telegram: @javascript