This guide is based on the following article http://blog.dealspotapp.com/post/40184153657/node-js-production-deployment-with-nginx-varnish
This setup is tested deploying on Ubuntu Server.
sudo apt-get update
sudo apt-get install nginx
Next create site config, replace myapp
with desired name
sudo vim /etc/nginx/sites-available/myapp
Paste the following, adapt as needed
upstream myapp_upstream {
server 127.0.0.1:3000;
keepalive 64;
}
server {
listen 8080;
server_name myapp.com;
return 301 $scheme://www.myapp.com$request_uri;
}
server {
listen 8080;
server_name www.myapp.com;
error_page 400 404 500 502 503 504 /50x.html;
location /50x.html {
internal;
root /usr/share/nginx/www;
}
location ~ ^/(images/|img/|javascript/|js/|css/|stylesheets/|flash/|media/|static/|robots.txt|humans.txt|favicon.ico|home/|html|xml) {
root /home/user/myapp/public;
access_log off;
expires max;
}
location / {
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_set_header Connection "";
proxy_http_version 1.1;
proxy_pass http://myapp_upstream;
proxy_intercept_errors on;
}
}
First we define an upstream, which tells Nginx about our Node.js servers (If you have multiple servers just add all of them).
We define a redirection from myapp.com to www.myapp.com, keeping the original request URI.
Finally, We tell Nginx to handle HTTP error codes (the internal location means that the error page isn’t publicly accessible).
Then We tell Nginx to intercept any static assets (by directory and by extensions) and serve them directly. We also set the required headers and pass traffic to the upstream server we defined earlier.
As a final step We need to create a symbolic link from the file in /etc/nginx/sites-available
to /etc/nginx/sites-enabled
. Make sure that there are no other enabled sites with conflicting configuration.
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/myapp
Notice that We told Nginx to listen on port 8080
Restart Nginx:
sudo service nginx restart
sudo apt-get install varnish
Edit /etc/default/varnish
and tell Varnish to listen on port 80
DAEMON_OPTS="-a :80 \
-T localhost:6082 \
-f /etc/varnish/default.vcl \
-S /etc/varnish/secret \
-s malloc,256m"
Next edit /etc/varnish/default.vcl
# Default backend definition. Set this to point to your content
# server.
#
backend default {
.host = "127.0.0.1";
.port = "8080";
}
sub vcl_recv {
if (req.restarts == 0) {
if (req.http.x-forwarded-for) {
set req.http.X-Forwarded-For =
req.http.X-Forwarded-For + ", " + client.ip;
} else {
set req.http.X-Forwarded-For = client.ip;
}
}
if (req.request != "GET" &&
req.request != "HEAD" &&
req.request != "PUT" &&
req.request != "POST" &&
req.request != "TRACE" &&
req.request != "OPTIONS" &&
req.request != "DELETE") {
/* Non-RFC2616 or CONNECT which is weird. */
return (pipe);
}
if (req.request != "GET" && req.request != "HEAD") {
/* We only deal with GET and HEAD by default */
return (pass);
}
# force lookup for static assets
if (req.url ~ "\.(png|gif|jpg|swf|css|js|html|ico)$") {
return(lookup);
}
if (req.http.Authorization || req.http.Cookie) {
/* Not cacheable by default */
return (pass);
}
return (lookup);
}
sub vcl_fetch {
# strip the cookie before static asset is inserted into cache.
if (req.url ~ "\.(png|gif|jpg|swf|css|js|html|ico)$") {
unset beresp.http.set-cookie;
}
if (beresp.ttl <= 0s ||
beresp.http.Set-Cookie ||
beresp.http.Vary == "*") {
/*
* Mark as "Hit-For-Pass" for the next 2 minutes
*/
set beresp.ttl = 120 s;
return (hit_for_pass);
}
return (deliver);
}
What I’m doing here is telling Varnish about the Nginx server, in sub_recv
making sure that static assets are always fetched from cache and in vcl_fetch
stripping any cookies before static assets are inserted into cache (Varnish doesn't cache requests with cookies by default).
restart Varnish
sudo service varnish restart
Create a new file under /etc/init/myapp.conf
#/etc/init/myapp.conf
description "MyApp Node.js"
author "[email protected]"
start on (local-filesystems and net-device-up IFACE=eth0)
stop on shutdown
respawn
respawn limit 5 60
script
cd /home/user/myapp
exec sudo -u user NODE_ENV=production /usr/bin/node /home/user/myapp/server.js >> /home/user/myapp/log/server.log 2>&1
end script
Here We tell Upstart how to start our process, to respawn it if it dies and to auto-start on boot after the file systems and network interface are up.
Now We can start and stop our Node.js server
sudo service myapp start
sudo service myapp stop
sudo service myapp restart
sudo apt-get install monit
Edit /etc/monit/monitrc
and uncomment the lines with set httpd..
use address
localhost
and allow localhost
, We need those in order to use monit status.
Create a new file under /etc/monit/conf.d/myapp.conf
check host localhost with address 127.0.0.1
start "/sbin/start myapp"
stop "/sbin/stop myapp"
if failed port 3000 protocol HTTP
request /
with timeout 5 seconds
then restart
This tells Monit how to start and stop the Node.js server, How to check for a response and how often.
Restart Monit:
sudo service monit restart
Now everything should be working, the Node.js server is started on boot with Upstart and monitored with Monit. HTTP requests are handled with Nginx and cached with Varnish.