Node app with Nginx on Amazon EC2
Tags: node, ec2, nginx, aws
Published: 2019-12-15 15:58:31

How to launch a Node js app behind an Nginx proxy on Amazon EC2 instance in a step by step walkthrough.

## Two things before we start

You need a few things before we start the launch:

1) **Node js app in a git repo** - make sure your Node app is ready and available to clone from a git repo

2) **AWS account** - if you don't have one yet, you can sign up [here](https://aws.amazon.com)

That's it, we are ready to roll!

## Launch an EC2 instance

1) Sign in to your AWS management console

2) Go to **EC2** service

3) Go to **Launch instance**

4) Select the first one from the list: **Amazon Linux 2 AMI** for the 64-bit (x86) - basically the first default option

5) Select instance type. Assuming you are running a simple app then go for the cheapest instance: **t3a.nano**. Click **Review and launch** as we are blasting through the complexity here and will take all the default setting and only change the few we need later. On the next screen confirm again by clicking **Launch**

6) You will be asked to select an existing key pair or create a new key pair - it doesn't matter, we will be using a web based SSH client from AWS console to select any option. Click **Launch Instances**

7) Click **View Instances** and go make yourself a cup of coffee while AWS is launching your new instance. It will take a few minutes.

## Set up security groups

As your instance is being launched, you need to configure AWS security groups so that you and your website visitors will be able to access your app (and you will be able to connect to it via SSH).

1) On EC2 Dashboard, find your new instance and scroll the view to the right to see what Security Group your instance is in. Remember the name of **the security group**

2) In the left hand side menu find and go to **Security Groups**

3) Select the security group and from 'Actions' select **Edit inbound rules**

4) In inbound rules you want to add the following two rules: 

- Type: SSH, Source: Anywhere
- Type: HTTP Source: Anywhere
Click **Save**

5) Go back to **Instances**

## Connect to your instance via SSH

Ok, so you got your coffee and you can see your new instance status is 'running' and the status checks are green on the AWS EC2 Dashboard? Let's go then and connect to the instance via SSH:

1) From the AWS EC2 Instances dashboard, select your instance, press **Connect**

2) From connection options choose **EC2 Instance Connect (browser-based SHH connection)** - this is the easiest and fastest option with no config required!

## Install Node, git, yarn and PM2 to run your app

Now the fun begins, we will blast through the installation of all the software you need. **You will now be working in your SSH terminal**


1) Update the system with the latest packages and basic environment

```shell
sudo yum update
```

2) Install nvm in order to install Node in the next step:

```shell
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.1/install.sh | bash
```

3) Close and re-open your SSH  console for the change to take effect

4) Install Node

```shell
nvm install node
```

5) Install Git

```shell
sudo yum install git
```

6) Install yarn. You are wondering **why not an npm**? Here is an article [why you should use yarn](https://engineering.fb.com/web/yarn-a-new-package-manager-for-javascript/). Bottom line, yarn is quicker and more resilient.

```shell
curl -o- -L https://yarnpkg.com/install.sh | bash
```

7) Re-open the terminal window for changes to take effect


8) Clone your Node app from your git repo

```shell
git clone https://github.com/<username>/<repository-name>.git <folder-name>
-- or --
git clone https://<username>@bitbucket.org/<username>/<repository-name>.git
```

9) Check if it's there

```shell
ls
```

10) Do you see a new folder with your app? Great, go to your app folder

```shell
cd <your-app-folder>
```

11) Install your app packages

```shell
yarn install
```

12) Install Node process manager to run your node app as a service.

You need a **Node process manager** so that it takes care of automatically restarting and reloading your app when something goes wrong. We will use PM2 - a very popular and production ready process manager.

```shell
yarn global add pm2
```

13) Launch your node app with the PM2 process manager. The example below assumes your app starts via index.js. Replace index.js with another file, e.g. app.js or server.js depending on how you would normally start your app in Node.

```shell
pm2 start index.js --name my-app
```

14) Make PM2 automatically restart your app if something goes wrong

```shell
pm2 startup
```

Retype the command the console asks you for in order to create the start up configuration. **You need to re-type it as copy-paste does not really work in the console!** 

It is a bit painful but make sure you get this one right as otherwise PM2 will not re-start.

Now save the PM2 set up:

```shell
pm2 save
```

## Set up Nginx to run your app behind the proxy

1) Install Nginx

```shell
sudo yum install nginx
```

You will get a warning command to install AWS curated Nginx package - great, that's what we need!

```shell
sudo amazon-linux-extras install nginx1.12
```

2) Edit Nginx config to redirect HTTP traffic from port :80 to the port your app is running on the local host.

In the example below I assumed your app is running on port 3000. If your app is running on a different port make sure to reflect that in the line of code `proxy_pass http://127.0.0.1:3000;` in the configuration below:

Open the editor:

```shell
sudo nano /etc/nginx/nginx.conf
```

and edit the config file to contain the following server block (leave everything else as is):

```nginx
server {
   listen         80 default_server;
   listen         [::]:80 default_server;
   server_name    localhost;
   root           /usr/share/nginx/html;
   location / {
       proxy_pass http://127.0.0.1:3000;
   }
}
```

Just in case you are new to the [nano editor](https://www.nano-editor.org/) - you can press `Ctr + X` to finish editing and you will be prompt whether to save the file.

3) Restart Nginx

```shell
sudo service nginx restart
```

4) Set up Nginx to restart automatically if something goes wrong

```shell
sudo chkconfig nginx on
```

**You are done!** Up and running. 

Go to your AWS dashboard with EC2 instances and find the **Public DNS (IPv4)** for your new instance. If you copy the url into the browser you should be able to see the output from your Node app.

## Next steps

1) You still need to think how to set up a proper **domain** for your app

I like to use AWS Route 53 and Cloudfront CDN to forward the traffic into the EC2 instance. That gives me resilience, free SSLs certificates and HTTPs redirects without having to worry about further Nginx configurations and management of certificate on the EC2 instance.

2) You need to configure your **Nginx proxy headers** and learn more about the `server` and `location` blocks configurations.

3) You probably want to set up a Git repo with your **Nginx configuration** files so that you can edit them in a proper code editor and than just pull their latest versions into your EC2 instance

4) Use a **proper SSH** client like [PuTTY](https://www.putty.org/) from your local machine. It will be a bit faster and smoother experience than the web client via AWS Console

5) This about the [caching strategy for your app](https://regbrain.com/article/cache-headers-express-js)