
How to deploy your node app on Linux, 2016 edition - nailer
https://certsimple.com/blog/deploy-node-on-linux
======
xorcist
Please note that this describes something you would do for a toy project. If
you do this for work you probably want to:

* Install NPM in a way that you can upgrade easily. Your package manager was designed to do this, so use it. Never ever put untracked files in the system directories.

* Don't git clone into production. You need to know which version was deployed when and where. At the very least set a tag. Better yet, roll a package from that tag (see above) which you then can sign and store. It's very easy and there are tools to help.

* Schedule when and how you upgrade your operating system, NPM, and your application. To do this you need a way to take an application out of production, which brings us to...

* You generally want a load balancer or some sort of web server between the world and your application. This could be as simple as an Apache or nginx. Don't muck about with port forwards!

* And most importantly, document this down to every command in the internal wiki! Even better, write a Puppet/Salt/Ansible file and put it under version control.

In short: Tools exist for a reason. Use them. Don't hack files manually until
you master the tools and know why they exist.

~~~
nailer
> * Install NPM in a way that you can upgrade easily. Your package manager was
> designed to do this, so use it. Never ever put untracked files in the system
> directories.

The articles uses the package manager - specifically, the article directs
people to install node using nodesource's RPM and dpkg node packages (npm is
included with node), and only mentions tarballs if these don't exist for your
OS.

> * Schedule when and how you upgrade your operating system, NPM, and your
> application. To do this you need a way to take an application out of
> production, which brings us to... > You generally want a load balancer or
> some sort of web server between the world and your application.

Hence covering that and load balancing with HAProxy in the article. This is
mentioned in the introduction.

> * And most importantly, document this down to every command in the internal
> wiki! Even better, write a Puppet/Salt/Ansible file and put it under version
> control.

Hence mentioning exactly that in the opening few paragraphs.

It's very clear you didn't read the article before commenting.

~~~
kiallmacinnes
>> * Install NPM in a way that you can upgrade easily. Your package manager
was designed to do this, so use it. Never ever put untracked files in the
system directories.

> The articles uses the package manager - specifically, the article directs
> people to install node using nodesource's RPM and dpkg node packages (npm is
> included with node), and only mentions tarballs if these don't exist for
> your OS.

Sure, but it also advises users that it's generally OK to extract tarballs
into /usr/local. While this clearly is OK in some circumstances, the target
audience for this article clearly aren't in a position to make that decision,
or understand the consequences of doing this. The article could have suggested
"/opt/node" for example and avoided the issue at the expense of explaining how
PATH variables work.

~~~
nailer
So you'd prefer, if no packages are available, unpackaged software be
installed to /opt rather than /usr/local? OK.

The FHS forbids distros from installing software to either location.

See
[http://www.pathname.com/fhs/2.2/fhs-4.9.html](http://www.pathname.com/fhs/2.2/fhs-4.9.html):

> "The /usr/local hierarchy is for use by the system administrator when
> installing software locally. It needs to be safe from being overwritten when
> the system software is updated. It may be used for programs and data that
> are shareable amongst a group of hosts, but not found in /usr."

~~~
kiallmacinnes
> So you'd prefer, if no packages are available, unpackaged software be
> installed to /opt rather than /usr/local? OK.

Ah, I did miss the subfolder. This is a _very_ unusual convention for
installation into /usr/local. Typically, this is what modern day usage of /opt
looks like.

> The FHS forbids distros from installing software to either location.

> See
> [http://www.pathname.com/fhs/2.2/fhs-4.9.html](http://www.pathname.com/fhs/2.2/fhs-4.9.html):

Correct, both options are valid per the FHS. Yet, the description for /opt
describes the pattern used in your example.

See
[http://www.pathname.com/fhs/2.2/fhs-3.12.html](http://www.pathname.com/fhs/2.2/fhs-3.12.html):

"A package to be installed in /opt must locate its static files in a separate
/opt/<package> directory tree, where <package> is a name that describes the
software package."

~~~
nailer
I see your point - I used to be reticent to use /opt since it was a bit of a
Solaris-ism (it only got added to the FHS because the proprietary Unixes kept
asking for it).

I'm thinking about changing it to /opt instead (and will credit you if I do
it), alas /opt/bin isn't in $PATH on most distros.

~~~
merb
They can't just add /opt/bin to $PATH Read the link he wrote down:

> Programs to be invoked by users must be located in the > directory
> /opt/<package>/bin. If the package includes UNIX > manual pages, they must
> be located in /opt/<package>/man > and the same substructure as
> /usr/share/man must be used.

Static packages should be kept together as /opt/myprogramm and mostly follow
the same structure as /usr than so like: /opt/myprogramm/bin
/opt/myprogramm/include /opt/myprogramm/lib ...

Mostly I put my programs there, too. /opt/app1 /opt/app2

~~~
nailer
_nod_ that's the thing - you'll break the interpreter for every node app -
'#!/usr/bin/env node' \- if you don't have node in $PATH. And as you say. /opt
apps normally aren't in $PATH.

Looks like /usr/local wins.

~~~
merb
It won't. Why should I install node in /opt? Mostly I install server-side or
desktop apps there (which most other people do aswell (Chrome, Atlasssian))
They don't need to be in path since they are mostly called by initd or sytemd
or .desktop file.

Also they don't screw the system as others do that won't get installed with
the package manager.

Don't touch any directory without the package manager, if you still do use
/opt.

~~~
nailer
I think most people would install desktop apps via their package manager.
Unpackaged apps are generally the exception rather than the rule. /usr/local
is also outside the package manager as previously discussed.

------
edelans
For hassle-free node apps deployment, I use and recommend PM2 : a [free and
open source
tool]([https://github.com/Unitech/pm2](https://github.com/Unitech/pm2))

As its doc states: PM2 is a production process manager for Node.js
applications with a built-in load balancer. It allows you to keep applications
alive forever, to reload them without downtime and to facilitate common system
admin tasks.

It also provides a very nice integration with keymetrics.io, which is the paid
service which finance PM2 development (they do provide a free tier).

PS: Apart from using it and loving it, I am not affiliated with this product's
team.

~~~
jorge-d
PM2 also provides a tool [1] to deploy your application directly into your
server, rollback & co. You can checkout this blogpost [2].

[1]
[http://pm2.keymetrics.io/docs/usage/deployment/](http://pm2.keymetrics.io/docs/usage/deployment/)

[2] [https://keymetrics.io/2014/06/25/ecosystem-json-deploy-
and-i...](https://keymetrics.io/2014/06/25/ecosystem-json-deploy-and-iterate-
faster/)

------
jimmcslim
Surprised that this is missing a recommendation to run 'npm shrinkwrap' and
include npm-shrinkwrap.json in your deployment package so that the
dependencies you have been testing against (and more importantly your
dependencies' dependencies) don't shift unintentionally under your feet.
Although maybe this isn't a problem with npm v3?

I'd also recommend including your dependencies in your deployment package
anyway to avoid a deployment being held up by npmjs.org downtime.

~~~
nailer
Author here! You're totally right, I've just added a shrinkwrap section.

PS. npm v3 still needs it, in fact it makes it better - `install --save`
updates the shrinkwrap file.

Re: checking in modules, I used to do this during 2013 when npm was up and
down every few days, but stopped a couple of years ago after npm Inc
stabilised everything. It's been solid so far and the smaller repo sizes (and
faster deploys) have been worth it.

------
tangue
As someone who never deployed a node app I was a bit surprised to see it
doesn't require a server like Apache or Nginx as a reverse proxy ? Is it a
commmon practice to deploy node apps like this ?

~~~
nailer
For most cases you want load balancing, hence HAProxy. But if you don't, node
has event driven IO like nginx does, so it's quite capable of things like
static file serving and https (like nginx, node uses openssl for all the hard
work).

~~~
nomailing
Don't you think nginx is better for serving static files? I first served
directly croon node with express and did a test with chrome with a simulated
modem connection speed. A simultaneous fast client was blocked because the
number of connection nodejs/express was exhausted by the slow modem connection
getting a lot of js files...

I think I also read many other blogs suggesting serving static files with
nginx in front of nodejs. Are you sure that this does not make sense?

~~~
nailer
It's not so much a matter of 'better' vs 'worse' as a balance between
complexity and speed. node has very fast IO - that's what it's known for - and
unlike Python or Ruby it can handle static files at speed:
[http://i.stack.imgur.com/amngX.png](http://i.stack.imgur.com/amngX.png) (from
the second post at [http://stackoverflow.com/questions/9967887/node-js-itself-
or...](http://stackoverflow.com/questions/9967887/node-js-itself-or-nginx-
frontend-for-serving-static-files) which provides some excellent discussion).
nginx is faster, but small projects that don't need load balancing may benefit
from having less software to install.

As the article mentions, you'll probably want a load balancer for high
availability. Whether you use haproxy or nginx for that is a whole different
discussion.

~~~
moron4hire
Faster than Ruby or Python doesn't mean anything if it's objectively slow. And
it is. I've only been able to serve a small handful of concurrent users at a
time with Express. I'm talking 5 or 6 before things get out of hand.

You should aim to have the bulk of your payload be static, and all of the
static payload be served by apache or nginx. It's the difference between
getting good feedback from a Show HN post or completely missing out and
looking like a fool.

~~~
nailer
> I've only been able to serve a small handful of concurrent users at a time
> with Express.

Something's massively wrong with your node setup. node won't be as fast, but
it should be on the same order of magnitude as nginx:
[https://github.com/observing/balancerbattle](https://github.com/observing/balancerbattle)
(or any other benchmark)

------
ehartsuyker
Can I shamelessly plug[0] and say maybe do all this and stick it in a Debian
package if you're running Debian, or like most of the cloud world, Ubuntu.

[0] [https://github.com/ehartsuyker/node-
deb](https://github.com/ehartsuyker/node-deb)

------
tomcam
Boy, this is golden. Just the ticket for a reluctant devops noobster like me.
Bonus for explaining wheel in *nix.

------
hardwaresofton
Huge thanks for taking the time to write and document this process. This is
bound to be a great resource for numerous devs in the future.

------
kybernetikos
If you want to run multiple node apps on a single box, you might find bouncy
useful too:
[https://github.com/substack/bouncy](https://github.com/substack/bouncy)

------
emilsedgh
Does it make sense to reverse proxy a node app behind nginx if the node app
only provides a REST API?

As far as I know, using nginx in front helps with serving static files, which
is a moot point on a REST API.

~~~
icebraining
_As far as I know, using nginx in front helps with serving static files, which
is a moot point on a REST API._

Well, that depends on the API; for example, a product inventory API might need
to serve many product images, a document management API might have to serve
PDFs and such, etc.

------
daleharvey
After a few years of deploying apps in a reasonably similiar way to this, I
switched to using dokku for deploying node applications recently, the
experience so far has been extremely nice.

I get `git push dokku master` deployment for free, for any application, I dont
have to worry about conflicting node versions between applications and it took
a lot less setup for all of my applications than this process describes for
one.

~~~
nailer
Sure - as discussed in the article, the steps of deploying a server should
only be performed once, and customised to your needs.

From then on you can - and should - deploy everything with Ansible playbooks,
AWS AMIs / Digital Ocean images, Dockerfiles, or whatever else. You've already
been doing this for years and have the experience - this is written for
developers who haven't done a lot of Linux before and want to take control of
the process.

------
CalmStorm
If the node app uses express js and has multiple processes, then a redis
server may be required to handle non-stikcy session. It would be nice if the
article describes the redis server setup.

------
emilsedgh
If you are deploying to a single server, consider using `pm2 deploy` which
makes life much easier for rolling new releases and deploying them on server.

------
cdnsteve
Why is Docker not being used here?

~~~
nailer
Mainly because I didn't want it to be a Docker/kubernetes tutorial. At some
point I'll publish an Ansible playbook you can modify for your environment and
call from a Dockerfile.

