Practical Steps to Deploy a Node.js App with NGINX and SSL
Published: 2022-09-08 10:51:39

There has been a rise in the need for developers to deploy applications quickly in an automated manner. As the development of features increases, the need to deploy applications faster increases to satisfy the users' needs.

Developers employ [Continuous Integration/Continuous Delivery](https://circleci.com/blog/what-is-a-ci-cd-pipeline/) (CI/CD) tools like NGINX. These tools have their unique benefits; to highlight a few, NGINX provides [load balancing](https://www.nginx.com/resources/glossary/load-balancing/), acts as a [reverse proxy server](https://www.nginx.com/resources/glossary/reverse-proxy-server/), does [caching](https://www.nginx.com/resources/glossary/caching/), manages [containerized applications](https://www.docker.com/resources/what-container/), and deploys [microservices](https://microservices.io/).

In this article, you will learn how to automate the deployment process of a Node.js application with [NGINX](https://www.nginx.com/) and [SSL](https://www.ssl.com/faqs/faq-what-is-ssl/).

## Prerequisites

To follow along with this tutorial, you will need the following:

- A [Github Account](https://github.com/)
- A [DigitalOcean Account](https://docs.digitalocean.com/products/getting-started/)
- [Node.js](https://nodejs.org/en/download/) installed
- [Docker](https://docs.docker.com/get-docker/) installed
- [SSH server](https://docs.microsoft.com/en-us/windows-server/administration/openssh/openssh_install_firstuse?tabs=gui) installed
- A [Domain name and hosting](https://www.namecheap.com/visual/site-maker/?gclid=Cj0KCQiAjJOQBhCkARIsAEKMtO2zl9cRuEItr0IbbPrOAni_WgicjNLwVurNNVGdQDWwYyT8dh180sEaAtWiEALw_wcB)
- [Visual Studio Code editor](https://code.visualstudio.com/)
- Terminal

_Note: This tutorial uses Ubuntu 20.04 operating system and Node.js v10.19.0._

Once you have all the prerequisites set up, you can begin.


### Demo: Setting up the Node.js Application

For this tutorial, you will use a Node.js application built with [Express.js](https://expressjs.com/) running on PORT 3000 that displays the text 'Node Application' in the browser.

Get the [application](https://github.com/debemenitammy/sample_node_app) by [cloning](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository) the repository on GitHub. Then, run `npm install` to install the dependencies and `nodemon app.js` to run the application locally.

![](https://lh5.googleusercontent.com/elERjCvMcBD4D8IRTWEJdfUED9wVj5ZmqIeZRCC8PvHgu00US48srqXGiIS71ae4FO763779XmGYkXnpIai3K7_Rv7mxKnHsM23wPVLNIQ7aL7k_VdUTT1GXCrdNSt2VVQtazimv)


Ensure that the application is running by going to 'http://localhost:3000/' in your browser:


![](https://lh6.googleusercontent.com/uX7r5nNnPs9-q96oN9udgbc8kBwL4ITstz3p2F-JByMyGq902q9FP5XC7SNN8iGqWygKZQ3PPdDjz-XDqa5YxQQFoMO53KEPYEjZylu4lFnP5QKc59ke3apmhffq10aN0nqs2GbA)


Now that your application is up and running, you can move forward to setting up NGINX and SSL. 


### Practical Steps to Deploy the Node.js App with NGINX and SSL

To begin, you need to set up [SSH keys](https://www.digitalocean.com/community/tutorials/how-to-set-up-ssh-keys-2) that you will use to authenticate the Droplet you create on DigitalOcean. 

Once you have your SSH keys set up, log in to your DigitalOcean account; then, follow the steps outlined below to create your Droplet for the application using the SSH keys you have set up.


### Creating a Droplet on DigitalOcean

In your DigitalOcean account, create the Droplet by clicking 'Droplet' in the dropdown:

![](https://lh6.googleusercontent.com/PkyslK77je5kM6io5FyU4DaOyq8bgs49gDD6RbUAi28vba5jvvR0_WS5KwANrGHwtgyPgm-TiaYjQnRcp6OYbpjFzyyDkvn8-wAuBG-doQ3HF3sfzG-d9Gp4b6VnIKSCL0gFw5u6)


Then, a page opens that highlights the Ubuntu operating system used for this tutorial:


![](https://lh3.googleusercontent.com/5dBZDRvVbPLsAzeQrrVwH5M2_iYwwse0BMJH2p93Bqg3E3UPhagse_bFTkB9jUST6rYyJcBmEyK8hin5oEm0Z5x74xNlDDiSv7-SZsxUwDPyTxogqpHhhykns_m-vaMDMb17d8gP)


Choose the $12 plan from the options provided:

![](https://lh4.googleusercontent.com/QYgNM9vaSR-rkvVWxWNyIVrr3VZN8cbhMySU6uKNgBSWSQE_k4bdq3ATCK5jFDKq4ytr3BUTB1mTUa2XHHhDgKwN63YBEFkFOlafU_JiMnmsoi42txUYZ_4IO4y0nsVSunSRCQRZ)


Select SSH keys as your authentication method because it is more secure than a one-time password:

![](https://lh4.googleusercontent.com/1e26IzQe7MKZlRN3DV5qjoDZUOMV3ZqDjHjV9ctX0ZmCctIuLKTt8UG2283e2prJAMuSlRycYPRTlC1S6IacjlIW-fzW8iIDfRbZiGs5JyLrd-22dVt8m676o2foKUcOniSwz6Ec)


Run this command and copy your SSH public key:


    cat /home/hp/.ssh/id_rsa.pub

Click **New SSH key** in your Droplet and paste the key:

![](https://lh4.googleusercontent.com/OW7AdQ6fz076IbBYvDvc83nR8FctJmeXpDK5wcPD_y7HhRphB3CnD0_MJUFbYiUa3FTYIxzz3hRWTRnVNFIkdAIYOAalqvHGnKl2Y1biWPOwlxgEuX5mLAONHVBFzzVfGL-fUSp5)


Name the SSH key and click **Add SSH Key** and choose the name of the SSH key:

![](https://lh6.googleusercontent.com/32T9EpCuFPKkotl6GJkua_8nnIaCqLD08kZni5SRiAj2MJ8ru-isfsmsgppDXUd78o5EaLkoNKMN_eetb-7cnuvkB0lB-oHVEIEQ-pQ-JlWqWPRQxpLXl4ZIQzdJr-v3Q82eU2fm)


Next, name your Droplet by choosing a hostname:

![](https://lh5.googleusercontent.com/ICISlrDfoQZtucB1Xv6zmlB74e5ma8TnZ-f2pbt6H0l_5rv3TGDDfGsMZBl0fthFbFRQIvkEuJt0uJ8JsKlBXxcdZeoFvw7WMn9RCyuM_saEUmGkKjUF7DpDzeeVgZWSFO-WjnTM)


Then click **Create Droplet** and you will successfully create your Droplet:

![](https://lh3.googleusercontent.com/XRD8AejGTypdcrvT0qViB9jTwLvDMqMelAS1AqefMEFOrANN45msVXP0CxXT0Shz1u2HbaIeVdFs4cxws_jaVxwr4YErkqUjo72MY7SZ9h7TBFkLe9MAfcenaFyYbuH4tsSCvewB)



### Log in with SSH

To login to your Droplet with SSH, you will use the IP address of the Droplet:

![](https://lh4.googleusercontent.com/MFLIbGxj9hzO1ADoxS49uX9hzFhFLEMa1Tf4tJjwJw08sqWACsJHNZ-qrUx4E0zD4ctbpCICJK23QG_PXxXP9MP4z4dQkzrGbptUFllhMN4bLboiB_pTx-_IP1eeNWJimzmFUPV3)


Copy the IP address and log in as a root user with the following command. Replacing `<your_ip_address>` with the IP address:


    ssh root@<your_ip_address 

After running this command, you will be prompted a question asking you if you want to continue connecting; enter `yes`, and log in:

![](https://lh6.googleusercontent.com/zbUeuP956oyiBrBqUg8c_jT5i8DoTtj7xZDm0ErXpHWgLHCPZqsx2Rttz2T7yhXovZGpzrK5ChaL-IWcdN82tDOe7Bckq7nUkcx7vw1cwO7CsQlEBzV4SBrfs7GIRZvHgQQ8yBV4)


Notice that the prompt changes to **root@FirstDroplet**. It changes to root, followed by the Droplet's name, and confirming your successful login to your Droplet via SSH.

You need to update your package repository and install Node.js and npm on your server; run these commands:


    sudo apt update
    curl -sL https://deb.nodesource.com/setup_16.x -o nodesource_setup.sh
    sudo apt install nodejs
    sudo apt install npm

To confirm the installation, run `node --version` and `npm --version`.


### Setting up the Application on the Droplet’s Server

Now you can set up the Node.js application on the Droplet's server. Here are the following steps:


**Create an application directory on the server**
First, you need to create a directory to house the application on your server. Run `mkdir app` to create a directory `app`. Then, run `cd app` to change the directory into the app directory:


![](https://lh5.googleusercontent.com/bR35V9AHgVL0-1I_DXIY3Hkm4UGSRp2EvSSbMsELIPSq4AyfiLWq0T3UFYEbXL1023cXz549MicyJYHmH7OJpzeVuMXkhkcuJq_xT7dmnbTUiluTGTedyDaVUx2bSIIhDBd03mcu)



**Get the project from the public repo**
Clone the [application](https://github.com/debemenitammy/sample_node_app) from Github with this command:

```
   git clone https://github.com/debemenitammy/sample_node_app.git
```

![](https://lh5.googleusercontent.com/v0CNr3TmimCev61EWlpEqrUIM2iD6nFOZlrxPfRDAKggPjH7cICmiIH8AHmwBK6sId91tF4cal0pjGwng4JQ0eFifXgSXznON_l07Lli_GtEjq29CwD4iRmn3VKeikHIuHQ0ddqt)


Run `npm install` to get your node modules folder and dependencies installed in the application:

![](https://lh6.googleusercontent.com/xF17ZNn8Xfm8fbCy1ZgwDtTLjCt3nJKhUjm6-JoZmphUtUOuBt1gpJNOPhJnH5KjnR2TZVeVPzZulBdS0lzkJI88JT05pzEK2bRFwJwAMZ7j2jdWK9ooGRiKfzr-DdUZYezRCJSq)


Then, run the application with `node app.js` and notice that it is running on PORT 3000:

![](https://lh4.googleusercontent.com/8tWZc15Fug96f23jkG01NvtS0ifgNLL3XEefXWYZhpASlcPS4CII68iNTDLBpYdNJoidze4NaS0Lvc8QcMzEdLDTBiqFHdxFHV1l9X8CS-t42eE_7WUopKOuBsFhplKzPXu9IM6R)


Go to `<your_ip;_address>:3000` URL on your browser, replacing `<your_ip_address>` with your Droplet's IP address:

![](https://lh4.googleusercontent.com/57teVTP2axNUxY6z-_BiFkGTE4tMJKiGyWu-FxQIDpKN9NePH5nMVsOa7al-lyw2LamH4KB-jI3PlngsE-ZURjNb7KYv7DKluItZwdcam8d8EH9n2EykUNwOi631Qb0FjRsC90JR)


Open your DigitalOcean account and view your Droplet. You should see your application existing in your Droplet.


### Setting up Production Process Manager (PM2)

Your application is currently running on this port `<your_ip_address>:3000`. If you decide to end the process by typing the `CRTL C` command in your terminal, the application stops running.

To run the Node.js application as a background process and in a production environment, you can use a PM2 - [Production Process Manager](https://pm2.keymetrics.io/) tool.

In this section, you'll see how to set up this PM2 tool. Here are the following steps:

### Install PM2
Run `CTRL C` to quit the application running in the terminal and run this command:

```
npm install -g pm2
```

![](https://lh5.googleusercontent.com/v9n8X-jrU2wXpVdgrj-PJ0F-msRabuQkeYI0jkn5zZGD5GmWF5k5SNYe7W6UbJJodxTZkvHSWLTah9QCE8Gkj26fUuKrx6DtMDXJIVIGi3cwr0_dJ__Nzl06sRtf6lHy6IbzodHW)


Now that you have PM2 installed, you can use it to start your application in the terminal with this command:

```
pm2 start app.js`
```

Once you run this command, it should display the following in your terminal, showing that you have successfully started your application with PM2:

![](https://lh5.googleusercontent.com/NfBt_avzT5Px5ocHe7T18AKP4mZS02YDZoDCdptwFJ46Gfo5XtYiz5vwj_pq2gK0fQSwujLbnTfXjMB9l-mkBp8hY8W95IxaDUyh6pxXhE_dyUu9skw7MA5xWWZbXKKDux5MKqXA)


The above screenshot shows that the application is running by displaying the `status` as `online`, as seen in the table containing `id`, `name`, `mode`, `CPU`, and `memory`.

You would also notice that the terminal doesn't show that the application is running as it was when it was running with `node app.js`. This time the application is running in the background due to the help of the Process Manager tool (PM2).

In addition, to confirm that your application is running, go to your browser and refresh:

![](https://lh6.googleusercontent.com/fiqqsFnZa9Ek6rZjrDIhOz5OWmxw3iwZxA1CkFSN5-4U9GCNiyyArW6V3QblZs0T0lJpxd9U3lRHjqPExuL1bIjMqIJApvt83CxNu1u2TPsHKRVUG-Bxnugfhkq1xQGjc4qqptD6)


You will see that the application is still running.

Run `pm2 status` to see the status of the application:

![](https://lh4.googleusercontent.com/ob10Salhj7aF8KHbD1B6eC6RYjvBhzzkoLEkiaYPT7iWhEGU-b92rOhcimHbVUrZTvUgExMerNh-M9_RVNrIoQXECEOkY3sHLhpcPtXWtMWOYRn5rsyVEz8WHahAZruRXCmV98UU)


Then, run `pm2 startup ubuntu` to ensure that the application runs anytime there is a reboot:  

![](https://lh4.googleusercontent.com/xBpPdtMDFJROfRJED3SQH5s9793weLhTGADEeNosci3S6_jxJkE6JY8lHGw595btm966m1VIQnPwULPkwnnshuea93UnxN8dYAZ_gMelAIp8Y3nSTRDu_NdYgQJogm-i0cSGEMsO)


Also, you need to enable the firewalls with `ufw enable`. Type 'y' at the prompt:

![](https://lh5.googleusercontent.com/aDs5pD_iQxz6RxkFb_wbvC0afeoRUx5IELDyWSS5DUhygRt8dJzCp69k8O6AEAAnF-wJzlxvc2Y9vq8DaKqjwzsAeIEgMJEIhgRriY27DbXBr6b_PWkXaNhoYxVTnIetVOHGciBi)


Run `ufw allow ssh` to allow ssh:

![](https://lh6.googleusercontent.com/r3vaHnWmthcdNFBaZn4LENhc2li8CrzeMKQNkhUHZ5k2Epu7yZE2QbvOaxPUX4CwmkLQTESYLJwWAdMOUS_HmarwnhD4PT3bQc5MYlIGCIASDzIhcQolMcetn6nYSArf3rqjjRtd)


Run `ufw status` to confirm that your firewall is enabled:

![](https://lh5.googleusercontent.com/uvWy1rBoTk6bZNc4e2y5dsHv9Jy23IXXwgJJXvo76m8Az1-L2YMfO4a575v7m3SEzKn9B3hN2p0BQoJwLmAS0FqgD8wZxbJ6eo4tHhkTTcJXDLOrOXjntqh32PlcvmzJw3PUWNop)


Next, run `ufw allow http` to allow Nginx to run the application on port 80:

![](https://lh4.googleusercontent.com/3EpYbomN9oCgYLn0ORp5T67wDfRLinx5D99-V4rNojkJGqKthlWdQTsoH43zU029lszinzkVrVLvWw8dMiybj4Q4xmuFSWdYBFayGDC8gU9bzI8Vjp2lta_U9w_RBAVkuum-wAJK)


Also, run `ufw allow https` to allow Port 443 - the HTTPs port. Finally, run `ufw status` to see the ports that have been allowed:

![](https://lh3.googleusercontent.com/u027Dqxi8sUxN860smSHJ5hJpE_Ca3JLaTNcugVlM0RjaNqlzM-2qU3nJ4xlzlB3T5-2ZQKCpU6By8RxnNRR8DgIwmSOPE5eCKFq_EIavSqNSPCd7zbzj0vRCy0Eo6yBP9ZwhwcU)


From the above screenshot, you can see that port 443 and port 80 have been allowed. 


### Setting up NGINX as a reverse proxy server 

Here, you will learn how to set up your NGINX server as a [Reverse Proxy](https://g.co/kgs/56DNpv) to render your application running on port 3000 to access it on port 80. 

To access your application with just your server's IP Address, you can achieve this with NGINX.

To get started with NGINX, use the following steps:

### Install NGINX
Run this command below to install NGINX:

```
sudo apt install nginx
```

To confirm the installation of NGINX, go to your browser and enter the IP address of your server as the URL (the Droplet's IP address). You should see a default message showing 'Welcome to NGINX':

![](https://lh4.googleusercontent.com/pFrjqmlS-SlnhI73vGiaCWijYn-b2L3jtYOMu1c3ov0F9CM3LGJH0K9llhQfzZmnsx6-LGPYsqdCMfJCfVGJ-VVWeD2zLnD8Fm3LWjDp9zQlWe3ph8T3Jguo3SEIWZ1GK6t240Is)


You can now access the default NGINX configuration file at this path - `/etc/nginx/sites-available/default`.


### Editing the configuration file
To edit the configuration file, use the following command:

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

Once you run this command, you should see the following in your terminal:

![](https://lh3.googleusercontent.com/oQKLaNuDoly6tE3vmyiZIC_9ESLSZnhI3M1U7NeyxTQ8VX7mOrUvIWgJ5W2CtFrmlO5VRBsF-4JJI17bET977PXpNHBsVB7u0dt7vMYk6z-oM5ELL1pYaEojY7latQS2jj8TPOjl)


Next, to set up your reverse proxy, scroll down the server block till you get to the location as follows:

![](https://lh6.googleusercontent.com/Fxa-hXRDaaX9IOTnQ9Dxx3LcT9MjoYB_x-LPCRuVHTtSZZ5dJpAZ5XonLTaTZCoe3ouDIfpmpg1lJBDEi5uHIOz2V4ij6DRd0I_VpmmXYnfvdunRRFJB_g7Qkt7CJXYouKijMSXj)


Then, delete the `try_files $uri $uri/ =404` line and replace it with the following:


    proxy_pass http://localhost:3000; 
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection ‘upgrade’;
    proxy_set_header Host $host;
    proxy_cache_bypass $http_upgrade;

Visit [NGINX documentation](https://nginx.org/en/docs/http/ngx_http_proxy_module.html) for more information.

In the location, you just set up your reverse proxy to ensure that when you visit port 80, it loads your application running on port 3000.

In addition, you can add your domain name to the `server_name` to set what NGINX should listen for alongside your port settings.

Otherwise, you can leave it as the default. So, type your domain name in your server block as follows:

![](https://lh5.googleusercontent.com/A0_ykuq9JTX53BnnpRUGK4DnEduE3qRus4R0gx_Fr1xTW05aYUqMj_-HskdguqKzGCbtRH2kS9EM8701tiqYWZ2P0_Qh1CDaAr9feNkz3TOUg2An1DrN-T8n18hh5tCR81pjbZhn)


Now, you save the changes you have made to the configuration file by typing the `CRTL X` command and ’yes’ at the prompt. Then, it will ask for the file you want the configuration saved into; press ‘enter’ as follows:

![](https://lh4.googleusercontent.com/fJPOAijEWAKAKzT1hJlPoS0dnkrclbZdprAr4stycaDox4mQ3CGGjVy6LVX8o_zekI0EmrQAVKcjTK_ZsHAyjq2I5b-icB9JUogTKuN4FqjQc1FLG2grGxs9KT1wAtS8klFN96Vz)


Once you press ‘enter’, the nano configuration window automatically saves and closes.


### Test the NGINX Configuration and Restart the NGINX Service

It is advisable to always run the `sudo nginx -t` command that runs a test on the NGINX configuration anytime you make changes to it. So, run the command as follows:


    sudo nginx -t

Once you run this command, you will have the following output:

![](https://lh5.googleusercontent.com/fHdqmQU62NkuOpU5M7ZEROmTXFXPfuhwhzLvFUMRt7XHGHglTAYT4HGegwA9LBrht37rshAWMTMArbYuGa2h5PE57jDquCC24sZofXI4FCtBBXnIxl8QThKIC35-N60E3ELgPVwp)


So, it says the configuration file test is successful. 

The next step is to restart the service to load the new configuration you just changed for NGINX. NGINX will shut down the former worker processes and start new worker processes by applying the new configuration.

So, run the following command to restart the service:


    sudo service nginx restart

This command doesn’t log any output to the terminal.

As NGINX restarts, navigate to your browser at the IP address and refresh:

![](https://lh5.googleusercontent.com/Eg1DosWaMnMtsmQ_0TvK7Q1oS5ugOZlzuwA3Z6Hsj-3UYQnAKpFlXZB_9qe1AGzblZNP6UmpWwGkPxOJ-d6Z_bsAAo3_23bHBD0cJD8Lpe1j4QYFKOBTAHvGKKCNC3fZMo59iDvz)


Notice that the IP address is now rendering your application, it shows that the configuration you added to NGINX to act as a reverse proxy was successful.


### Include Domain Name in Droplet

The next thing you need to do is add your Domain name to your Droplet in DigitalOcean. Go to the Networking page, enter your domain name in the Domain tab and click ‘Add Domain’:

![](https://lh5.googleusercontent.com/0-WrBRfISF_YHCDgP4ES_B4mqoeAUQLj5zSlIMw2vTcbhXP_vFb8mZITQ2l99XyeAR08z-TQYVTHuzsVFFPkInYtG4rS230oTWrSmtSCFkCrUU4BPtz7csjBAI7BBRA8dQ9xSc44)


Then, create a record for your domain name by following the instructions: 

![](https://lh6.googleusercontent.com/cyPXaZMVgViSEjBujzPke4xj7EGuiwJn3rwIQkzFKkGf3CuImPDXQl-nbFvWXskLFfnIqsVc86T0SrZrfgCyVGpzzpOMdE00rzHdiDdW1WsCwB2VFrWpg3t3iCPVKxiqWDfu0y5j)


Also, add `ns1.digitalocean.com`, `ns2.digitalocean.com`, and `ns3.digitalocean.com` as your custom nameservers in the DNS records.

You have successfully added your domain name. 


### Setting up SSL

To secure your server, you need to set up [SSL](https://www.ssl.com/faqs/faq-what-is-ssl/) for the server. You will use [LetsEncrypt](https://letsencrypt.org/) - a certificate authority that will allow you to get a free SSL certificate for the domain of the application. Run these commands:


    sudo apt install certbot python3-certbot-nginx
    sudo ufw allow 'Nginx Full’
    sudo certbot --nginx -d your_domain_name

 
Now you have successfully set up SSL for your server.

## Conclusion

Finally, you have reached the end of this tutorial, where you learned how to auto-deploy a Node.js application with NGINX by creating a Droplet in DigitalOcean for the application, setting up NGINX as a reverse proxy server, setting up SSL for security, e.t.c. 

The following resources might be helpful: 

- [NGINX documentation](https://nginx.org/en/docs/http/ngx_http_proxy_module.html)
- [Setting up a Digital Ocean account](https://docs.cpanel.net/knowledge-base/web-services/how-to-create-a-digitalocean-account/)