How do I run a node.js app as a background service?

Viewed 738288

Since this post has gotten a lot of attention over the years, I've listed the top solutions per platform at the bottom of this post.


Original post:

I want my node.js server to run in the background, i.e.: when I close my terminal I want my server to keep running. I've googled this and came up with this tutorial, however it doesn't work as intended. So instead of using that daemon script, I thought I just used the output redirection (the 2>&1 >> file part), but this too does not exit - I get a blank line in my terminal, like it's waiting for output/errors.

I've also tried to put the process in the background, but as soon as I close my terminal the process is killed as well.

So how can I leave it running when I shut down my local computer?


Top solutions:

28 Answers

If you simply want to run the script uninterrupted until it completes you can use nohup as already mentioned in the answers here. However, none of the answers provide a full command that also logs stdin and stdout.

nohup node index.js >> app.log 2>&1 &
  • The >> means append to app.log.
  • 2>&1 makes sure that errors are also send to stdout and added to the app.log.
  • The ending & makes sure your current terminal is disconnected from command so you can continue working.

If you want to run a node server (or something that should start back up when the server restarts) you should use systemd / systemctl.

Since I'm missing this option in the list of provided answers I'd like to add an eligible option as of 2020: docker or any equivalent container platform. In addition to ensuring your application is working in a stable environment there are additional security benefits as well as improved portability.

There is docker support for Windows, macOS and most/major Linux distributions. Installing docker on a supported platform is rather straight-forward and well-documented. Setting up a Node.js application is as simple as putting it in a container and running that container while making sure its being restarted after shutdown.

Create Container Image

Assuming your application is available in /home/me/my-app on that server, create a text file Dockerfile in folder /home/me with content similar to this one:

FROM node:lts-alpine
COPY /my-app/ /app/
RUN cd /app && npm ci
CMD ["/app/server.js"]

It is creating an image for running LTS version of Node.js under Alpine Linux, copying the application's files into the image and runs npm ci to make sure dependencies are matching that runtime context.

Create another file .dockerignore in same folder with content

**/node_modules

This will prevent existing dependencies of your host system from being injected into container as they might not work there. The presented RUN command in Dockerfile is going to fix that.

Create the image using command like this:

docker build -t myapp-as-a-service /home/me

The -t option is selecting the "name" of built container image. This is used on running containers below.

Note: Last parameter is selecting folder containing that Dockerfile instead of the Dockerfile itself. You may pick a different one using option -f.

Start Container

Use this command for starting the container:

docker run -d --restart always -p 80:3000 myapp-as-a-service

This command is assuming your app is listening on port 3000 and you want it to be exposed on port 80 of your host.

This is a very limited example for sure, but it's a good starting point.

For people using newer versions of the daemon npm module - you need to pass file descriptors instead of strings:

var fs = require('fs');
var stdoutFd = fs.openSync('output.log', 'a');
var stderrFd = fs.openSync('errors.log', 'a');
require('daemon')({
    stdout: stdoutFd, 
    stderr: stderrFd
});

If you are using pm2, you can use it with autorestart set to false:

$ pm2 ecosystem

This will generate a sample ecosystem.config.js:

module.exports = {
  apps: [
    {
      script: './scripts/companies.js',
      autorestart: false,
    },
    {
      script: './scripts/domains.js',
      autorestart: false,
    },
    {
      script: './scripts/technologies.js',
      autorestart: false,
    },
  ],
}

$ pm2 start ecosystem.config.js

I received the following error when using @mikemaccana's accepted answer on a RHEL 8 AWS EC2 instance: (code=exited, status=216/GROUP)

It was due to using the user/group set to: 'nobody'.

Upon googling, it seems that using user/group as 'nobody'/'nogroup' is bad practice for daemons as answered here on the unix stack exchange.

It worked great after I set user/group to my actual user and group.

You can enter whomai and groups to see your available options to fix this.

My service file for a full stack node app with mongodb:

[Unit]
Description=myapp
After=mongod.service

[Service]
ExecStart=/home/myusername/apps/myapp/root/build/server/index.js
Restart=always
RestartSec=30
User=myusername
Group=myusername
Environment=PATH=/usr/bin:/usr/local/bin
Environment=NODE_ENV=production
WorkingDirectory=/home/myusername/apps/myapp

[Install]
WantedBy=multi-user.target
Related