# How to deploy - AWS / VM (Simplified)

## Prequests

* Any Debain based linux machine E.g. Ubuntu, Amazon Linux.
    
* A domain name (Optional but required for making connection HTTPS).
    
* Make sure to **enable HTTP and HTTPS in the firewall** (for aws its called security groups).
    

## Step 1 - installations

Before getting into any thing lets first **update your system**.

```bash
sudo apt update -y && sudo apt upgrade -y # This will update all packages installed by apt
```

Next we need to **install node.js**

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

```bash
source ~/.bashrc
```

```bash
nvm install --lts
nvm use --lts
```

Verify installations by running `node -v` and `npm -v`.

Now you should be able to run `node` and see REPL of Node.js. Try to run some file with `node index.js`

Now lets **install PM2**, a process manager used to keep Node.js running even after closing the terminal (running Node.js in background).

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

Verify installations by running `pm2 -v`

Now you should be able to run `pm2 start index.js`, this will create a new process in pm2.

Here are some commands that come in handy

1. `pm2 startup` make pm2 automatically start when the system turn’s on (very helpful). make sure to turn this on so that you don’t need to worry about mannually restarting every time.
    
2. `pm2 list` list all processes.
    
3. `pm2 monit` monitor a process.
    
4. `pm2 save` save current process list.
    
5. `pm2 logs` show logs of all running process.
    

Now let’s install one more team member **Nginx,** a powerfull webserver and reverse proxy (Very helpful).

```bash
sudo apt install -y nginx
```

Verify installations by running `nginx -v`

Here are some commands that come in handy

1. `sudo systemctl start nginx` starts nginx.
    
2. `sudo systemctl enable nginx` make nginx automatically start when the system turns on. Make sure to run this. so that you don’t need to worry about mannally starting nginx every time.
    
3. `sudo systemctl status nginx` view current status on nginx service.
    

If you have a public ip address and if the firewall is enabled you should be able to see nignx welcome page while entring your public ip `http://<your public ip>`.

## Step 2 - Deployment.

before running any commands lets first understand what we are going to do.

We are goning to use nginx as a proxy (distributor of requests to our projects) and a static file server (for serving react).

We have 3 services.

1. Node.js backend (running using pm2) in port 3000. for `/api`
    
2. React.js admin pannel (serving bulid using pm2) in port 5173. for `/admin`
    
3. React.js main website (build files serving using nginx) for requests to `/`,
    

Nginx will listen in the port 80 (HTTP default port) and 443 (HTTPS default port). and redirect/serve requests according to the requests’ path.

So if :

1. Request is coming to `/` then nginx will look at the reacts’ build for for main website and serve static files according to the requests.  
    E.g.. urls `http://12.12.12.12/` or `https://example.com/` (when ever path is or starts with `/`).
    
2. Request is coming to `/api` then nginx will redirect/forward that request to Node.js listening on 3000 and running on pm2.  
    E.g.. urls `http://12.12.12.12/api/` or `https://example.com/api/` (when ever path is or starts with `/api`).
    
3. Request is coming to `/admin` then nginx will redirect/forward that request to React serving using pm2 on port 5173.  
    E.g.. urls `http://12.12.12.12/admin/` or `https://example.com/admin/` (when ever path is or starts with `/admin`).
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1763891313761/9233dba7-ccbd-4c49-93d7-2a0a20a44191.png align="center")

Now lets get into implimentaion

**First lets start our backend**, Clone you code or just create a new js file in the server.

```bash
cd /backend # Open you folder with node.js code
```

For now i am creating a `index.js` file in `/backend` folder

```bash
nano index.js # This will create a new file and open in nano editor
```

```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}/`);
});
```

Use `ctrl + o` to save the changes and `ctrl + x` to exit the nano editor.

```bash
pm2 start index.js --name test-server # Change index.js to you entry poient
```

Ok now backend is ready. To accessing the backend directly enable `3000` port in firewall (security groups if you are in AWS) and request to your servers **public ip address** or if you are in same LAN with the server use its ip address.  
E.g.. link `http://12.12.12.12:3000/`

**Now lets serve React.js admin dashboard usign pm2.**

First clone the repo and get the code to the server. and open that.

```bash
cd admin-page # Open your admin page directory with react project
```

```bash
npm run build # Build the project and create static files
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1763997135642/ef464ba4-1dee-4ccd-b527-d61e3b14d67c.png align="center")

To serve this using PM2’s static file server

```bash
pm2 serve --name admin-pannel ./dist 5173
```

Ok now admin page is ready. To accessing the admin page directly enable `5173` port in firewall (security groups if you are in AWS) and request to your servers **public ip address** or if you are in same LAN with the server use its ip address.  
E.g.. link `http://12.12.12.12:5173/`

**Now lets serve main react page using Nginx**

> Note : You can use pm2 to serve this one also, but for learning purpouse I am serving using Nginx.

To service someting using nginx we need to create a config file.

The default folder for nginx config in Ubuntu is `/etc/nginx/sites-available` and `/etc/nginx/sites-enabled`

What we generally do is we create a config file in `/etc/nginx/sites-available` and create a soft link of that file to `/etc/nginx/sites-enabled`. what ever files/configs is on the sites-enabled folder will get exicuted by Nginx.

So lets create our config file for Nginx.

```bash
sudo nano /etc/nginx/sites-available/deploy # here i am using depoy as file name
```

insdie that file we need to add config for Nginx.

```bash
server {
   # this will match all request, if you have a domain name replace _ with your domain name.
   server_name _; 

    # This is the folder where nginx look for you react dist folder.
    # Make sure to give the correct path or copy dist output to the below folder
    root /var/www/my-react-app; 

    # Configuring default file to serve.
    index index.html; 

    # this will serve static files according to url else index.html
    location / {
       try_files $uri $uri/ /index.html; 
    }

    # Forward all request to Node.js running on PM2 at 3000
    location /api {
       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;
    }

    # Forward all request to React.js serving from PM2 at 5173
    location /admin {    
       proxy_pass http://localhost:5173;
       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;
    }

    # Optional: gzip compression for better performance
    gzip on;
    gzip_types text/plain text/css application/javascript application/json image/svg+xml;
    gzip_min_length 256;
}
```

Use `ctrl + o` to save the changes and `ctrl + x` to exit the nano editor.

Now link the file to `sites-enabled` folder

```bash
sudo ln -s /etc/nginx/sites-available/deploy /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
```

before starting nginx test your config files for errors

```bash
sudo nginx -t
```

```bash
sudo systemctl restart nginx # Start if not running otherwise restart nginx.
```

Hurray, Now you should be able to see your deployment by opening you public ip address in you browser.

E.g.. link

* `http://12.12.12.12:5173/` for your main react app.
    
* `http://12.12.12.12:5173/admin/` for your react admin app.
    
* `http://12.12.12.12:5173/api/` for your node.js backend.
    

## Step 3 - **Adding SSL certificates - HTTP to HTTPS**

[**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.

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

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

Certbot will find correct `server_name` directive that matches the domain name you mentioned on the command and automatically add certificates. It will update our Nginx Confing file that we have created with 443 port binding (for listening to HTTPS requests).

Ok lets run `certbot`

```bash
sudo certbot --nginx -d your_domain_name # Replace your_domain_name with your actucal domain name
```

So select your choice and hit `ENTER`. The configuration will be updated, and Nginx will reload to pic up the new settings.

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** gr](https://www.ssllabs.com/ssltest/)ade.

Happy coding :)
