Deploying Nestjs app to VPS with nginx, postgres, redis
Tags: devops, nginx, nestjs, vps
Published: 2023-12-13 13:51:39

Let’s deploy nestjs + postgres + redis + docker app to VPS. Everything is from scratch, hopefully understandable for beginners.

> Written by Full stack developer (not a master devops :)

Setting up a basic nginx is not hard. Just a few things you should do:

- Install nginx to Linux (ubuntu 20.04)
- Create Nginx config file + proxy server
- Generate an SSL certificate for your domain name (if you have one)
- That’s all. Don’t worry we’ll cover all of these.

## Starting nestjs app
**First of all, clone your project to the server via git.** After that, you run your project. First of all, you need nodejs to run nestjs application. If you use Docker, you can skip these steps & run the Dockerfile.

1. I recommend to install nvm (Node Version Manager):
```bash
curl https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash
source ~/.bashrc
```
Once you’ve installed nvm, you need to install node (v18):
```bash
nvm i 18
```
If you use yarn, install it too:
```bash
npm i -g yarn
```
Then go to your project dir, and install packages via npm or yarn, then build your app. After that, install [pm2](https://pm2.keymetrics.io/) to run your app (forever):
```bash
npm i -g pm2
```
Once you have installed pm2, check if it’s working:
```bash
pm2
```
If so, you can run your app by following the command. If there is postgres or redis, you need to run them first then run your app (see 2)
```bash
pm2 start ./dist/main.js --name my-nestjs-app
# pm2 start <script_file_path.js> --name <name_optional>
```
2. If you use Postgres or Redis, I recommend using a Docker Compose for these. This is my sample docker-compose.yml file for Postgres and Redis:
```yaml
version: "3"
services:
  postgres:
    image: postgres
    restart: always
    environment:
      POSTGRES_DB: ${POSTGRES_DB}
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    ports:
      - '5432:5432'
    volumes:
      - my-nestjs-app:/var/lib/postgresql/data
  redis:
    image: "bitnami/redis:7.2"
    restart: unless-stopped
    ports:
      - "6379:6379"
#    volumes:
#      - "redis_data:/bitnami/redis/data"
    environment:
      REDIS_PASSWORD: ${REDIS_PASSWORD}
      REDIS_PORT: ${REDIS_PORT}
      REDIS_DB: ${REDIS_DB}
      REDIS_IO_THREADS: 4
      REDIS_IO_THREADS_DO_READS: yes
      REDIS_DISABLE_COMMANDS: FLUSHDB,FLUSHALL

volumes:
  my-nestjs-app:
```
To run docker compose you need to have docker. [Complete guide to install docker on ubuntu.](https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-20-04#step-1-installing-docker) Once you have installed docker, run docker-compose:
```bash
sudo docker compose up -d
```

## Setup nginx
So let’s set up nginx for nestjs app. Before installing nginx, update your existing list of packages:
```bash
sudo apt update
```
Then install nginx:
```bash
sudo apt install nginx
```
Check nginx if it is working:
```bash
sudo systemctl status nginx
```
You will get:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y0vuhk5xce7xxiw9dypo.png)
Create an nginx configuration file in /etc/nginx/sites-available/my-nestjs-app
```bash
sudo vim /etc/nginx/sites-available/my-nestjs-app
```
Then copy/paste this configuration:
```nginx
server {
    server_name domain.com;
    client_max_body_size 300M;
    
    # add_header 'Access-Control-Allow-Origin' '*';

    location = /favicon.ico { access_log off; log_not_found off; }

    location / {
        proxy_set_header Host $http_host;
        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 https;
        proxy_pass http://127.0.0.1:3000;
    }
}
```
Let’s understand this configuration:
- **server_name** — According to [nginx docs](https://nginx.org/en/docs/http/server_names.html): it is used for a given request. They may be defined using exact names, wildcard names (like domain.com sub.dobmain.com), or regular expressions.
- **client_max_body_size** — the maximum size of a client request body. If this size is exceeded, nginx returns a 413 status code error. If you don’t want that just comment it.
- **location /** — means if the request matches this “/” or the value of location then nginx runs “the code inside of its block”. We used proxy_set_header and proxy_pass directives. proxy_set_header sets the header for the defined request. proxy_pass kinda forwards requests to the given URL or path. We set localhost 3000 so, every request in server_name and location forwards to location 3000 (domain.com/ -> localhost:3000/)

After that, save the file (in vim type :wq) and test the conf file with nginx command:
```bash
sudo nginx -t
```
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t8skmb2kq5ubev9scnr4.png)

If you make a syntax error, it will be shown. If everything is ok, create a link:
```bash
sudo ln -s /etc/nginx/sites-available/my-nestjs-app /etc/nginx/sites-enabled/my-nestjs-app
```
then test nginx & restart nginx:
```bash
sudo systemctl restart nginx
```

## Setup domain name
First of all, you need to forward the domain name to your VPS. Go to your domain provider dashboard > DNS Records > create a record with A name, and put the IP address of your VPS in the “name” field ([example](https://help.one.com/hc/en-us/articles/360000799298-How-do-I-create-an-A-record-)). Then check it’s forwarded to your IP address (`$ hostname -I` to see IP):
```bash
ping domain.com
```
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zo4mbtsiwm4iwt7gk9fw.png)
If these IP addresses are not the same as the IP address of your VPS, you should wait to be the same (it might take minutes to days depending on your domain registrar), otherwise you will face problems.

You need to add an SSL certificate to your domain. It’s easy with certbot, so install cerbot:
```bash
sudo apt update
sudo apt install certbot python3-certbot-nginx
```
After that run this command to generate SSL certificates for your domain:
```bash
sudo certbot --nginx -d example.com
```
After that test the nginx conf file:
```bash
sudo nginx -t
```
If it’s ok, restart nginx:
```bash
sudo systemctl restart nginx
```
That’s all! I apologize for any mistake I made. If you find any mistake, please let me know.
_I hope it’s helpful_