203

What is the best way to deploy Node.js?

I have a Dreamhost VPS (that's what they call a VM), and I have been able to install Node.js and set up a proxy. This works great as long as I keep the SSH connection that I started node with open.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
respectTheCode
  • 42,348
  • 18
  • 73
  • 86
  • 6
    Hmm, it seems strange to me that you call using Forever as "deploying node.js". Isn't it just a process monitoring/supervision tool? Usually web deployment means (at least what I encounter in articles) several interrelated activities that make a web app available (this process tool being a part of it). Anyway, this is still a great post here in StackOverflow as I've learned from everyone's answers. – mikong Aug 19 '11 at 08:23
  • This is just the simplest deployment of node.js on Dreamhost. The goal was simply to get node running reliably as a starting point to build from. – respectTheCode Aug 24 '11 at 16:33
  • How have you handled forwarding the domain to the port node is running on? – grm Dec 22 '12 at 15:56
  • 2
    @grm I use HTTP-Proxy https://github.com/nodejitsu/node-http-proxy – respectTheCode Jan 08 '13 at 12:50
  • We are using Elastic Beanstalk now and it is working quite nicely. – respectTheCode Nov 08 '13 at 11:44
  • Possible duplicate of [Node.js as a background service](http://stackoverflow.com/questions/4018154/node-js-as-a-background-service) – mikemaccana Oct 17 '15 at 13:52

17 Answers17

121

2016 answer: nearly every Linux distribution comes with systemd, which means forever, monit, PM2, etc. are no longer necessary - your OS already handles these tasks.

Make a myapp.service file (replacing 'myapp' with your app's name, obviously):

[Unit]
Description=My app

[Service]
ExecStart=/var/www/myapp/app.js
Restart=always
User=nobody
# Note Debian/Ubuntu uses 'nogroup', RHEL/Fedora uses 'nobody'
Group=nogroup
Environment=PATH=/usr/bin:/usr/local/bin
Environment=NODE_ENV=production
WorkingDirectory=/var/www/myapp

[Install]
WantedBy=multi-user.target

Note if you're new to Unix: /var/www/myapp/app.js should have #!/usr/bin/env node on the very first line and have the executable mode turned on chmod +x myapp.js.

Copy your service file into the /etc/systemd/system folder.

Tell systemd about the new service with systemctl daemon-reload.

Start it with systemctl start myapp.

Enable it to run on boot with systemctl enable myapp.

See logs with journalctl -u myapp

This is taken from How we deploy node apps on Linux, 2018 edition, which also includes commands to generate an AWS/DigitalOcean/Azure CloudConfig to build Linux/node servers (including the .service file).

mikemaccana
  • 110,530
  • 99
  • 389
  • 494
  • 1
    Any idea on how to deal with `Failed to issue method call: Unit name ... is not valid.` ? – Julien Genestoux Apr 01 '15 at 18:56
  • 1
    @JulienGenestoux the 'unit' name is the same as your service. It sounds like there's a discrepancy there. After you copied the file to `/etc/systemd/system` you might need to run `systemctl daemon-reload` (systemd will normally tell you if this is needed). TBH this is best asked as a separate question. – mikemaccana Apr 01 '15 at 19:03
  • 3
    Instead of copying your service file into `/etc/systemd/system`, you can just use `systemctl enable /full/path/to/myapp.service`, which creates a symlink in `/etc/systemd/system` for you. – Arne Apr 02 '16 at 12:39
  • 1
    How does it compare with pm2? Can it replace pm2 or does pm2 offer more necessary features? – Sergei Basharov Oct 30 '16 at 18:45
  • @mikemaccana Can you explain the service line-by-line to a window guy. i mean what `ExecStart` is the `js` file but where is `node` being called . i am confused – Vinod Srivastav Dec 26 '17 at 18:48
  • 1
    @VinodSrivastav `node` is called by `/var/www/myapp/app.js` itself. In Unix, if you make a file executable, and the first line starts with `#!/some/file` the file will be interpreted with that binary. Google 'interpreter Unix' to know more. – mikemaccana Jan 05 '18 at 12:56
  • You mention `systemd` only but wasn't it possible to do the same with other Linux init systems? Note that some Linux distributions reject systemd, like Devuan. It would be nice also if someone can answer the question of @SergeiBasharov, how does it compare to pm2? Not using pm2 has an advantage to have less dependencies, here are interesting answers: https://stackoverflow.com/questions/4681067/how-do-i-run-a-node-js-application-as-its-own-process/14452957#14452957 https://hashnode.com/post/node-forever-vs-pm2-vs-other-cimpvw1o900i0wz53chiyrcbd/answer/cimpy12m700j3xa53dio5llq7 – baptx Jul 23 '19 at 08:14
  • 1
    @baptx: generally if it isn't systemd, it's sysvinit, which means writing a shell script (see `/usr/share/doc/svsvinit*`) then adding an additional tool to monitor the app and restart it. – mikemaccana Jul 23 '19 at 10:47
102

Use Forever. It runs Node.js programs in separate processes and restarts them if any dies.

Usage:

  • forever start example.js to start a process.
  • forever list to see list of all processes started by forever
  • forever stop example.js to stop the process, or forever stop 0 to stop the process with index 0 (as shown by forever list).
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
David Tang
  • 92,262
  • 30
  • 167
  • 149
  • This is close. It starts just fine but wont let me stop anything. I was able to log out and back in and then kill the node process. Forever didn't restart it. So I am thinking something about how it works isn't compatible with DH. – respectTheCode Jan 13 '11 at 15:34
  • @Kevin, you can't kill the node process because Forever itself runs on node! I've added some usage instructions to my answer, including how to stop a process. I've been using this on my VPS and it's worked like a charm. – David Tang Jan 13 '11 at 22:32
  • `forever stop 0` had an error and things just kind of fell apart from there. I have been trying to do this without root on its own user so that I can clean up easily once I find the right solution. That may be my problem. I will look into it some more. – respectTheCode Jan 15 '11 at 10:37
  • I had something wrong with npm that was causing problems. With npm and node installed correctly forever works great. What I ended up doing was adding the forever start commands to a cronjob set to run on restart. I am now working on a little node app that will let me start and stop forever procs. – respectTheCode Feb 21 '11 at 15:35
  • There's an alternative to Forever which uses node's native cluster API: https://github.com/superjoe30/naught – andrewrk Sep 18 '13 at 20:02
  • I don't work on a linux machine, so the top answer was worthless. This answer is the only right one for all OSes that can run node and it's easy to setup and get running right away. Plus, I purposefully ran tests and it restarts the app right away, didn't even notice that it went down for a brief millisecond. – Nicholas R. Grant Nov 16 '22 at 18:08
41

I've written about my deployment method here: Deploying node.js apps

In short:

  • Use git post-receive hook
  • Jake for the build tool
  • Upstart as a service wrapper for node
  • Monit to monitor and restart applications it they go down
  • nginx to route requests to different applications on the same server
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Ben
  • 435
  • 4
  • 3
  • 2
    If I will always have a single Node site on my server, can I safely ditch Nginx? – Dor Apr 10 '13 at 17:45
  • 3
    The link seems to be broken – verybadalloc Jun 09 '13 at 12:17
  • @Dor I know this is a late reply, but I wouldn't. Apart from things like SSL termination and caching, an nginx reverse proxy in front of the host allows you a greater infrastructural flexibility than running node directly on port 80. It also means you don't have to run node as root, which I think is a pretty heavy argument in favour of the nginx setup. – Chris Browne Apr 30 '15 at 13:19
17

pm2 does the tricks.

Features are: Monitoring, hot code reload, built-in load balancer, automatic startup script, and resurrect/dump processes.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
nickleefly
  • 3,733
  • 1
  • 29
  • 31
9

You can use monit, forever, upstart or systemd to start your server.

You can use Varnish or HAProxy instead of Nginx (Nginx is known not to work with websockets).

As a quick and dirty solution you can use nohup node your_app.js & to prevent your app terminating with your server, but forever, monit and other proposed solutions are better.

nponeccop
  • 13,527
  • 1
  • 44
  • 106
  • 2
    A user "Sergey Yarotskiy" tried to edit you post saying that Nginx now supports WebSockets (since version 1.3). I rejected the edit as I think it should be posted as a comment instead. (Otherwise you'd have two contradicting sentences in the same post, which is confusing.) – Backlin Feb 14 '14 at 14:25
7

I made an Upstart script currently used for my apps:

description "YOUR APP NAME"
author "Capy - http://ecapy.com"

env LOG_FILE=/var/log/node/miapp.log
env APP_DIR=/var/node/miapp
env APP=app.js
env PID_NAME=miapp.pid
env USER=www-data
env GROUP=www-data
env POST_START_MESSAGE_TO_LOG="miapp HAS BEEN STARTED."
env NODE_BIN=/usr/local/bin/node
env PID_PATH=/var/opt/node/run
env SERVER_ENV="production"

######################################################

start on runlevel [2345]
stop on runlevel [016]

respawn
respawn limit 99 5

pre-start script
    mkdir -p $PID_PATH
    mkdir -p /var/log/node
end script

script
    export NODE_ENV=$SERVER_ENV
    exec start-stop-daemon --start --chuid $USER:$GROUP --make-pidfile --pidfile $PID_PATH/$PID_NAME --chdir $APP_DIR --exec $NODE_BIN -- $APP >> $LOG_FILE 2>&1
end script

post-start script
    echo $POST_START_MESSAGE_TO_LOG >> $LOG_FILE
end script

Customize all before #########, create a file in /etc/init/your-service.conf and paste it there.

Then you can:

start your-service
stop your-service
restart your-service
status your-service
Capy
  • 5,167
  • 2
  • 20
  • 21
6

I've written a pretty comprehensive guide to deploying Node.js, with example files:

Tutorial: How to Deploy Node.js Applications, With Examples

It covers things like http-proxy, SSL and Socket.IO.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Rich Jones
  • 1,422
  • 1
  • 15
  • 17
  • This looks great. I am using heroku for development and the initial launch but will eventually need to scale past heroku and deploy directly to EC2. I will play with this when I have time. – respectTheCode Jan 15 '12 at 16:46
5

Here's a longer article on solving this problem with systemd: http://savanne.be/articles/deploying-node-js-with-systemd/

Some things to keep in mind:

  • Who will start your process monitoring? Forever is a great tool, but it needs a monitoring tool to keep itself running. That's a bit silly, why not just use your init system?
  • Can you adequately monitor your processes?
  • Are you running multiple backends? If so, do you have provisions in place to prevent any of them from bringing down the others in terms of resource usage?
  • Will the service be needed all the time? If not, consider socket activation (see the article).

All of these things are easily done with systemd.

Ruben Vermeersch
  • 1,933
  • 1
  • 18
  • 27
5

If you have root access you would better set up a daemon so that it runs safe and sound in the background. You can read how to do just that for Debian and Ubuntu in blog post Run Node.js as a Service on Ubuntu.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Seldaek
  • 40,986
  • 9
  • 97
  • 77
3

Forever will do the trick.

@Kevin: You should be able to kill processes fine. I would double check the documentation a bit. If you can reproduce the error it would be great to post it as an issue on GitHub.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Marak
  • 235
  • 1
  • 2
2

As Box9 said, Forever is a good choice for production code. But it is also possible to keep a process going even if the SSH connection is closed from the client.

While not necessarily a good idea for production, this is very handy when in the middle of long debug sessions, or to follow the console output of lengthy processes, or whenever is useful to disconnect your SSH connection, but keep the terminal alive in the server to reconnect later (like starting the Node.js application at home and reconnecting to the console later at work to check how things are going).

Assuming that your server is a *nix box, you can use the screen command from the shell to do keep the process running even if the client SSH is closed. You can download/install screen from the web if not already installed (look for a package for your distribution if Linux, or use MacPorts if OS X).

It works as following:

  1. When you first open the SSH connection, type 'screen' - this will start your screen session.
  2. Start working as normal (i.e. start your Node.js application)
  3. When you are done, close your terminal. Your server process(es) will continue running.
  4. To reconnect to your console, ssh back to the server, login, and enter 'screen -r' to reconnect. Your old console context will pop back ready for you to resume using it.
  5. To exit screen, while connected to the server, type 'exit' on the console prompt - that will drop you onto the regular shell.

You can have multiple screen sessions running concurrently like this if you need, and you can connect to any of it from any client. Read the documentation online for all the options.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
cjcela
  • 268
  • 1
  • 10
2

Try this: http://www.technology-ebay.de/the-teams/mobile-de/blog/deploying-node-applications-with-capistrano-github-nginx-and-upstart.html

A great and detailed guide for deploying Node.js apps with Capistrano, Upstart and Nginx

Pono
  • 11,298
  • 9
  • 53
  • 70
1

Forever is a good option for keeping apps running (and it's npm installable as a module which is nice).

But for more serious 'deployment' -- things like remote management of deploying, restarting, running commands etc -- I would use capistrano with the node extension.

https://github.com/loopj/capistrano-node-deploy

martyman
  • 867
  • 8
  • 14
1

Try node-deploy-server. It is a complex toolset for deploying an application onto your private servers. It is written in Node.js and uses npm for installation.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
AndyGrom
  • 461
  • 1
  • 4
  • 9
1

https://paastor.com is a relatively new service that does the deploy for you, to a VPS or other server. There is a CLI to push code. Paastor has a free tier, at least it did at the time of posting this.

ruffrey
  • 6,018
  • 3
  • 23
  • 19
1

In your case you may use the upstart daemon. For a complete deployment solution, I may suggest capistrano. Two useful guides are How to setup Node.js env and How to deploy via capistrano + upstart.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Anatoliy
  • 29,485
  • 5
  • 46
  • 45
0

I am using express on Dreamhost and got pm2 running on background pm2 start app.js. Convenient. Can view logs and even save log files pm2 logs <PM2_ID> mylogs.txt,

pm2 monit - monitoring metrics of app

pm2 list - table view of processes

You can configure PM2 to automatically restart a process if it exceeds a certain memory usage threshold. This helps prevent memory leaks or excessive memory usage.

pm2 start app.js --name=myapp --max-memory-restart 200M
Tyler2P
  • 2,324
  • 26
  • 22
  • 31