# Hosting MERN app on AWS Ubuntu 22.04 - 2023

This article is for beginners' guide to hosting and deploying their projects to a server or any Ubuntu 22.04 machine. Here is the whole walk through of what is going to do in this article.

---

* Creating AWS instance
    
* Setup by installing library and application
    
    * Npm & Nodejs
        
    * MongoDB
        
    * Pm2 (npm package)
        
    * Nginx
        
    * UFW (firewall)
        
* Starting serving
    
    * Running js using pm2
        
* Securing server with SSL certificate
    

---

#### Preparations you need to take

> Get a domain name for hosting.

### Setting up your Linux server - Ubuntu 22.04 LTS

Whenever we get a server it's a good practice to update the repository and packages, If you are going to download and use new packages. In this case, we are using an apt package manager to install the necessary packages.

It's more like updating the whole system.

```bash
sudo apt update
```

```bash
sudo apt upgrade -y
```

If you are doing it for the first time this may take some time.

### Installing software and required packages

For hosting a NodeJS app successfully we need some packages and dependencies.

1. ### Installing NodeJS
    

So let's start by installing `npm`. Which also comes with `NodeJS`

```bash
sudo apt install npm -y
```

This will install npm with the latest version which is on the apt repository. But as of now, the day I am writing. This will be the download `node of version 12. x.x`. So this could be a problem if you try to use new features like a `ternary operator` or `optional chaining` Which is only supported on the latest versions of NodeJS.

To avoid any kind of problem with the NodeJS version and feature missing we need to update NodeJS and npm.

To update NodeJS we can use an npm package called `n`.

```bash
sudo npm install n -g
```

```bash
sudo n stable
```

This will update the NodeJS to the latest stable version. To check the node version use the following command

```bash
node --version
```

1. ### Installing MongoDB
    

If you are using Atlas (a fully managed database cloud by MongoDB), You can skip this step. Otherwise, you need to install MongoDB locally to run your code.

You can refer to [MongoDB's official installation doc](https://www.mongodb.com/docs/manual/tutorial/install-mongodb-on-ubuntu/) for Ubuntu 22.04. By the time you read this article, the following commands may be outdated so I would recommend checking official installation documentation.

Anyway here is how we install MongoDB.

Install dependencies for the installation of MongoDB.

```bash
sudo apt install gnupg curl
```

Enter the following command to import the MongoDB public GPG Key from [https://pgp.mongodb.com/server-6.0.asc](https://pgp.mongodb.com/server-6.0.asc)

```bash
curl -fsSL https://pgp.mongodb.com/server-6.0.asc | \
   sudo gpg -o /usr/share/keyrings/mongodb-server-6.0.gpg \
   --dearmor
```

Create the `/etc/apt/sources.list.d/mongodb-org-6.0.list` file for **Ubuntu 22.04 (Jammy)** Other version's sources list is on [Official documentation](https://www.mongodb.com/docs/manual/tutorial/install-mongodb-on-ubuntu/)

```bash
echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-6.0.gpg ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/6.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-6.0.list
```

Enter the following command to reload the local package database

```bash
sudo apt update
```

To install the latest stable version, use the following command

```bash
sudo apt install -y mongodb-org
```

The installation is complete. so let's enable Mongodb to start the startup of the system.

```bash
sudo systemctl enable mongod
```

To start MongoDB we can use

```bash
sudo systemctl start mongod
```

we can also view the status of the MongoDB service by simply typing `sudo systemctl status mongod`.

We successfully installed MongoDB and now we can access the MongoDB shell by typing `mongosh`.

1. ### Installing PM2 (npm package)
    

PM2 is a process manager for Node.js applications that simplifies the process of managing and deploying Node.js applications in production environments. It is designed to keep your Node.js applications running continuously, ensuring high availability and improved performance. PM2 stands for "Production Process Manager 2."

PM2 is an npm package, and it's fairly easy to install.

```bash
sudo npm install pm2 -g
```

That's it PM2 is successfully installed globally.

1. ### Installing Nginx
    

NGINX is **an open-source web server software that can be used for web serving, reverse proxying, caching, load balancing, media streaming, and more**. And it is really fast !.

NGINX is designed to handle a high number of connections simultaneously, making it one of the most powerful and scalable server software options on the market

To install `nginx` use the following command

```bash
sudo apt install nginx
```

This will install the latest stable version of Nginx available in the apt repository.

As our machine is a server and we don't need to manually start nginx as a service every time we boot or reboot our system. To address this issue we can enable nginx to run on start-up using the following command.

```bash
sudo systemctl enable nginx
```

To start nginx we can use

```bash
sudo systemctl start nginx
```

we can also view the status of the Nginx service by simply typing `sudo systemctl status nginx`.

1. ### UFW (firewall)
    

UFW stands for "Uncomplicated Firewall." It is a user-friendly command-line tool used in Linux-based systems, such as Ubuntu, to manage the system's firewall settings. UFW provides a simple and easy-to-use interface for configuring and controlling firewall rules, making it accessible to both novice and experienced users.

NOTE: If you are using an AWS instance for hosting configuring UFW is not a necessary stop since AWS comes with its firewall called security groups. Learn more about it from their [official documentation](https://docs.aws.amazon.com/vpc/latest/userguide/security-groups.html)

To install UFW use -

```bash
sudo apt install ufw
```

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">To see available applications for adding in UFW use <code>sudo ufw app list</code>. you should see <code>Nginx Full</code>, <code>Nginx HTTP</code> and <code>Nginx HTTPS</code> is on the list.</div>
</div>

now let's allow full `HTTP` and `HTTPS` access to nginx.

```bash
sudo ufw allow 'Nginx Full'
```

Use the following command to view all apps and ports managed by the firewall.

```bash
sudo ufw status
```

```bash
To                         Action      From
--                         ------      ----
Nginx Full                 ALLOW       Anywhere                  
OpenSSH                    ALLOW       Anywhere                  
Nginx Full (v6)            ALLOW       Anywhere (v6)             
OpenSSH (v6)               ALLOW       Anywhere (v6)
```

IMPORTANT NOTE: If you are using SSL to connect to an instance you must check `OpenSSH` is enabled in the firewall, to access your server. otherwise, you will have some real trouble accessing your server! , If `OpenSSH` is not listed in the `sudo ufw status`.

```bash
sudo ufw allow openssh
```

This will enable ssh to our server.

### Start serving your app

Let's start by serving a simple `express` server.

1. Create and open files in an editor.
    

```bash
cd ~
touch index.js
vim index.js
```

1. wirte simple http sever in nodejs
    

```javascript
const http = require('http');

const hostname = 'localhost';
const port = 3000;

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello World!\n');
});

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});
```

1. Press `escape` and `:wq` to save and exit from Vim
    

Now we can start our server using PM2

```bash
pm2 start index.js --name test-server
```

```bash
# Your screen should looks like this
[PM2] Spawning PM2 daemon with pm2_home=/home/ubuntu/.pm2
[PM2] PM2 Successfully daemonized
[PM2] Starting /home/ubuntu/index.js in fork_mode (1 instance)
[PM2] Done.
┌────┬────────────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──────────┬──────────┐
│ id │ name           │ namespace   │ version │ mode    │ pid      │ uptime │ ↺    │ status    │ cpu      │ mem      │ user     │ watching │
├────┼────────────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──────────┼──────────┤
│ 0  │ test-server    │ default     │ N/A     │ fork    │ 1152923  │ 0s     │ 0    │ online    │ 0%       │ 37.3mb   │ ubuntu   │ disabled │
└────┴────────────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──────────┴──────────┘
```

That's it with the pm2 side. so let's configure Nginx for accessing this on the internet. Nginx default configuration is on `/etc/nginx/sites-available` so we are going to create a file with our domain name there.

```bash
sudo vim /etc/nginx/sites-available/your_domain_name
```

Replace your `your_domain_name` with your actual domain name. This will open an editor and we can add nginx configurations here.

```nginx
server {
   server_name your_domain_name www.your_domain_name;
   location / {
       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;
   }
}
```

Now save and exit the file. To save and exit use `escape` and press `:wqEnder`. The next step is to add a soft link to this file we created to `sites-enabled` folder of nginx.

```bash
sudo ln -s /etc/nginx/sites-available/your_domain_name /etc/nginx/sites-enabled
```

It's a good practice to remove old non used nginx configs from `sites-enabled` folder

```bash
sudo rm /etc/nginx/sites-enabled/default
```

Test our newly added config.

```bash
sudo nginx -t
```

```bash
# Your screen should look like this
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
```

Now let's restart nginx.

```bash
sudo systemctl restart nginx
```

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">use <code>sudo systemctl status nginx</code> to get the status of the nginx service.</div>
</div>

### Check your browser!

If everything is configured correctly so far, you should see "`Hello world`" in your browser by opening a new tab with your instance's public IP as your address.

You can just clone your project from Git Hub or edit index.js and run it in PM2 to customize the response.

If your project runs on a different you need to update the Nginx config to access the project from outside.

### Adding SSL certificates - HTTP to HTTPS

After successfully hosting your project with Nginx now it's time to protect our website with an SSL certificate.

[Let’s Encrypt](https://letsencrypt.org/) is a Certificate Authority (CA) that provides an easy way to obtain and install free [TLS/SSL certificates](https://www.digitalocean.com/community/tutorials/openssl-essentials-working-with-ssl-certificates-private-keys-and-csrs), thereby enabling encrypted HTTPS on web servers. It simplifies the process by providing a software client, Certbot, that attempts to automate most (if not all) of the required steps. Currently, the entire process of obtaining and installing a certificate is fully automated on both Apache and Nginx.

This guide will walk you through the process of using Certbot to secure a free SSL certificate for Nginx on Ubuntu 20.04, and you'll also learn how to set it up for automatic renewal.

Let's install `certbot` along with its `nginx plugin`

```bash
sudo apt install certbot python3-certbot-nginx
```

* Obtaining SSL certificate
    

Certbot needs to be able to find the correct `server` block in your Nginx configuration for it to be able to automatically configure SSL. Specifically, it does this by looking for a `server_name` directive that matches the domain you request a certificate for. In our case its `your_domain_name`.

```bash
sudo certbot --nginx -d your_domain_name -d www.your_domain_name
```

If that’s successful, `certbot` will ask how you’d like to configure your HTTPS settings.

```markdown
OutputPlease choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: No redirect - Make no further changes to the webserver configuration.
2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
new sites, or if you're confident your site works on HTTPS. You can undo this
change by editing your web server's configuration.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel):
```

Select your choice then hit `ENTER`. The configuration will be updated, and Nginx will reload to pick up the new settings. `certbot` will wrap up with a message telling you the process was successful and where your certificates are stored:

```bash
OutputIMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/example.com/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/example.com/privkey.pem
   Your cert will expire on 2020-08-18. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot again
   with the "certonly" option. To non-interactively renew *all* of
   your certificates, run "certbot renew"
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le
```

Your certificates are downloaded, installed, and loaded. Try reloading your website using `https://` and notice your browser’s security indicator. It should indicate that the site is properly secured, usually with a lock icon. If you test your server using the [SSL Labs Server Test](https://www.ssllabs.com/ssltest/), it will get an **A** grade.

With that being set you are good to handle hosting in Ubuntu 22.04.

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">This article is inspired by <code>Digital Ocean's</code> NodeJS hosting documentation. For further reference, you can always refer <a target="_blank" rel="noopener noreferrer nofollow" href="https://www.digitalocean.com/community/tutorials/how-to-set-up-a-node-js-application-for-production-on-ubuntu-20-04" style="pointer-events: none">Digital Oceans doc</a>.</div>
</div>

Hope this article helps.

Stay creative; Thak you : 🤍
