Skip to content

Instantly share code, notes, and snippets.

@mjurincic
Forked from tomysmile/node-setup-pm2-nginx.md
Last active June 30, 2022 16:05
Show Gist options
  • Save mjurincic/e3557d42a830d5e9f0fd19532ff87146 to your computer and use it in GitHub Desktop.
Save mjurincic/e3557d42a830d5e9f0fd19532ff87146 to your computer and use it in GitHub Desktop.
Setup NodeJS Production with PM2, Nginx on AWS Ubuntu 16.04 server
proxy_http_version 1.1;
proxy_set_header Connection "";
https://gist.github.com/miguelmota/6912559
# The upstream module is the link between Node.js and Nginx.
# Upstream is used for proxying requests to other servers.
# All requests for / get distributed between any of the servers listed.
upstream helloworld {
# Set up multiple Node.js webservers for load balancing.
# max_fails refers to number of failed attempts
# before server is considered inactive.
# weight priorities traffic to server. Ex. weight=2 will recieve
# twice as much traffic as server with weight=1
server <your server ip>:3000 max_fails=0 fail_timeout=10s weight=1;
# server <your server ip>:3001 max_fails=0 fail_timeout=10s weight=1;
# server <your server ip>:3002 max_fails=0 fail_timeout=10s weight=1;
# server <your server ip>:3003 max_fails=0 fail_timeout=10s weight=1;
# Send visitors back to the same server each time.
ip_hash;
# Enable number of keep-alive connections.
keepalive 512;
}
server {
listen 80;
listen [::]:80 default_server ipv6only=on;
# Index files.
index index.html;
# Domain names.
# Make sure to set the A Record on your domain's DNS settings to your server's IP address.
# You can test if was set properly by using the `dig` command: dig yourdomain.com
server_name yourdomain.com www.yourdomain.com;
# Timeout for closing keep-alive connections.
keepalive_timeout 10;
# Enable gzip compression.
gzip on;
gzip_http_version 1.1;
gzip_vary on;
gzip_comp_level 6;
gzip_proxied any;
gzip_buffers 16 8k;
gzip_disable "MSIE [1-6]\.(?!.*SV1)";
# Max upload size.
# client_max_body_size 16M;
# Change access and error log files.
# access_log /var/log/nginx/yourdomain.com/access.log;
# error_log /var/log/nginx/yourdomain.com/error.log;
# Custom error page.
# error_page 404 maintenance.html;
# error_page 500 502 503 504 maintenance.html;
# location /maintenance.html {
# root /var/www;
# }
location / {
# Set this to your upstream module.
proxy_pass http://helloworld;
# Headers to pass to proxy server.
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_set_header X-NginX-Proxy true;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_cache_bypass $http_upgrade;
proxy_http_version 1.1;
proxy_redirect off;
# Go to next upstream after if server down.
proxy_next_upstream error timeout http_500 http_502 http_503 http_504;
proxy_connect_timeout 5s;
# Gateway timeout.
proxy_read_timeout 20s;
proxy_send_timeout 20s;
# Buffer settings.
proxy_buffers 8 32k;
proxy_buffer_size 64k;
}
# Enable caching of static files.
# location ~* \.(css|js|ico|gif|jpe?g|png|svg)$ {
# expires 168h;
# add_header Pragma public;
# add_header Cache-Control "public, must-revalidate, proxy-revalidate";
# }
# Don't cache html files.
# location ~* \.html$ {
# expires -1;
# }
# Serve static files without going through upstreams
location ~ ^/(images/|img/|javascript/|js/|css/|stylesheets/|flash/|media/|static/|robots.txt|humans.txt|favicon.ico) {
root /var/www/helloworld;
access_log off;
expires 1h;
}
}

Setup NodeJS Production with PM2, Nginx on AWS Ubuntu 16.04 server

Installing Nginx on AWS ec2 instance with Ubuntu 16.04

$ sudo apt-get update && sudo apt-get upgrade -y
$ sudo apt-get install nginx -y

Setup Nginx

Check status of Nginx and start it using the following commands:

$ sudo systemctl status nginx    # To check the status of nginx
$ sudo systemctl start nginx     # To start nginx

Make sure that Nginx will run on system startup by using command below:

$ sudo systemctl enable nginx

Nginx should be up and running, now we need to setup Nodejs on server.

Setup Nodejs

Check if Nodejs and npm are already installed and clean it up

$ node --version  # For checking nodejs version
$ npm --version   # For checking npm version
$ sudo apt-get purge nodejs npm

Install Node.js

NVM binaries

instal NVM (node version manager)

curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.6/install.sh | bash

get latest LTS node.js release

$ nvm install --lts

NodeSource binaries

We will install the latest LTS release of Node.js, using the NodeSource package archives.

Fresh installation

Use the NodeSource PPA. For details look at the installation instructions. First, choose the Node.js version you need and add the sources for it:

for Node.js v4

curl -sL https://deb.nodesource.com/setup_4.x | sudo -E bash -

for Node.js v5

curl -sL https://deb.nodesource.com/setup_5.x | sudo -E bash -

for Node.js v6

curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -

for Node.js v7

curl -sL https://deb.nodesource.com/setup_7.x | sudo -E bash -

for Node.js v8

curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -

Then install the Node.js package

sudo apt-get install -y nodejs

Upgrading

If you have nodejs already installed and want to update, then first remove current instalation and install it again using scripts above.

sudo apt-get purge nodejs npm

Install PM2

runs below as root :

$ sudo npm install pm2 -g --unsafe-perm

Make pm2 auto-boot at server restart:

$ pm2 startup 

This will create a systemd unit which runs pm2 for your user on boot. This pm2 instance, in turn, runs hello.js or any script or apps you have defined. You can check the status of the systemd unit with systemctl:

$ systemctl status pm2

Other PM2 Usage (Optional)

Stop an application with this command (specify the PM2 App name or id):

$ pm2 stop app_name_or_id

Restart an application with this command (specify the PM2 App name or id):

$ pm2 restart app_name_or_id

The list of applications currently managed by PM2 can also be looked up with the list subcommand:

$ pm2 list

More information about a specific application can be found by using the info subcommand (specify the PM2 App name or id):

$ pm2 info example

The PM2 process monitor can be pulled up with the monit subcommand. This displays the application status, CPU, and memory usage:

$ pm2 monit

Setting up Nginx as a reverse proxy for Nodejs application

Get the private ip address of your instance by using the command below, do make sure you are logged into your instance using ssh:

$ wget -q -O - 'http://169.254.169.254/latest/meta-data/local-ipv4'

Make a backup of original file:

$ sudo cp /etc/nginx/sites-available/default /etc/nginx/sites-available/default.bak

Edit original file:

$ sudo nano /etc/nginx/sites-available/default

When you are finished, your file will likely look something like this:

upstream node-helloworld.your-domain.com {
        server 127.0.0.1:5000;
        keepalive 64;
}

server {
        listen 80;
        server_name helloworld.your-domain.com;

        access_log /var/log/nginx/helloworld.your-domain.com-access.log;
        error_log /var/log/nginx/helloworld.your-domain.com-error.log;

        location / {
                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 Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
                proxy_pass http://node-helloworld.your-domain.com;
                proxy_redirect off;
                proxy_http_version 1.1;
                proxy_cache_bypass $http_upgrade;
        }
}

When you are finished, save and close the file.

Now that we have our server block files, we need to enable them. We can do this by creating symbolic links from these files to the sites-enabled directory, which Nginx reads from during startup.

We can create these links by typing:

$ sudo ln -s /etc/nginx/sites-available/default.com /etc/nginx/sites-enabled/

Create Node.js Application;

We will write a Hello World application that simply returns "Hello World" to any HTTP requests. This is a sample application that will help you get your Node.js set up, which you can replace with your own application--just make sure that you modify your application to listen on the appropriate IP addresses and ports.

Hello World Code node.js App

cd ~
mkdir www
nano server.js

Insert the following code into the file. If you want to, you may replace the highlighted port, 8080, in both locations (be sure to use a non-admin port, i.e. 1024 or greater):

server.js:

var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
}).listen(3000, 'localhost');
console.log('Server running at http://localhost:3000/');

Save and exit.

Start app with pm2:

pm2 start server.js

Save process list to disk.

pm2 save

Note: to be able to reference multiple domains for one Node.js app (like www.example.com and example.com) you need to add the following code to the file /etc/nginx/nginx.conf in the http section:

server_names_hash_bucket_size 64;

If the DNS changes are propagated, you can point your web browser to your domain and you should see your application running, accessible from the internet.

Next, test to make sure that there are no syntax errors in any of your Nginx files:

$ sudo nginx -t

If no problems were found, restart Nginx to enable your changes:

$ sudo systemctl restart nginx

Nginx should now be serving both of your domain names.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment