DEV Community

Cover image for Easily deploy a NestJS app for only 5€ a month (before VAT)
Afonso Barracha
Afonso Barracha

Posted on

Easily deploy a NestJS app for only 5€ a month (before VAT)

Introduction

Free Heroku being gone makes developer need to search for alternative deployment options for their NodeJS APPs, in particular for this article NestJS APIs.

In this short tutorial I am going to show an alternative way to deploy your API, although not for free, for only 5€ a month on a cloud vps.

Cloud Providers

There are multiple clouds that provide VPS (virtual private servers) which are VM (virtual machines) running an OS (operating system) mainly Linux.

The cheapest cloud providers are Linode, DigitalOcean, Vultr and Hetzner, Hetzner being the cheapest.

Changes to your NestJS API

Before deployment you need to make some changes to your NestJS API.

Configuration and Environment Variables

For the intent and purpose of maintaining this tutorial short I will assume your app already have the Config Module set up with the necessary Environment Variables. However you will need to do some changes to your configurations:

  • If you are using a PostgreSQL database you will need to change your settings from an options object to a Postgres URL, so have a variable as follows:
DATABASE_URL='postgresql://USER:PASSWORD@HOST:PORT/DATABASE'
Enter fullscreen mode Exit fullscreen mode
  • If you are using MongoDB you will need to do the same, so you will need the following variable:
MONGO_URL='mongodb://username:password@host:port/defaultauthdb?options'
Enter fullscreen mode Exit fullscreen mode
  • If you are using Redis with the IORedis library it can become a little bit more complicated, but as the other two you need to have a URL variable:
REDIS_URL='redis://:PASSWORD@HOST:PORT'
Enter fullscreen mode Exit fullscreen mode

Since IORedis only support URLs if you use TLS I found that having an util function to de-structure the URL into the RedisOptions interface is easier to set-up, so on your config folder add the following redis-url-to-options.util.ts on the utils directory:

import { RedisOptions } from 'ioredis';

export const redisUrlToOptions = (url: string): RedisOptions => {
  if (url.includes('://:')) {
    const arr = url.split('://:')[1].split('@');
    const secondArr = arr[1].split(':');

    return {
      password: arr[0],
      host: secondArr[0],
      port: parseInt(secondArr[1], 10),
    };
  }

  const connectionString = url.split('://')[1];
  const arr = connectionString.split(':');
  return {
    host: arr[0],
    port: parseInt(arr[1], 10),
  };
};
Enter fullscreen mode Exit fullscreen mode

Hence your config.ts file will look something like this:

import { IConfig } from './interfaces/config.interface';
import { redisUrlToOptions } from './utils/redis-url-to-options.util';

export function config(): IConfig {
  return {
    // ...
    redis: redisUrlToOptions(process.env.REDIS_URL),
    // ...
  };
}

Enter fullscreen mode Exit fullscreen mode

Changes on the package.json file

Swap the start script for the start:prod and delete the start:prod script.

So it goes from:

{
  // ...
  "scripts": {
    // ...
    "start": "nest start",
    "start:dev": "nest start --watch",
    "start:debug": "nest start --debug --watch",
    "start:prod": "node dist/main",
    // ...
  },
  // ...
}
Enter fullscreen mode Exit fullscreen mode

To:

{
  // ...
  "scripts": {
    // ...
    "start": "node dist/main",
    "start:dev": "nest start --watch",
    "start:debug": "nest start --debug --watch",
    // ...
  },
  // ...
}
Enter fullscreen mode Exit fullscreen mode

Set Up Hetzner

Firstly create an account, you will need to either send a photo of your passport or do a spendable 20€ deposit to complete the registration process.

After creating an account, login, and on your console create a new project.

Create a Server

On the server tag of your project click on add server:

Hetzner Add Server Button

Server Options

Select the latest version of Ubuntu LTS (22.04):

Hetzner Ubuntu Options

Add your public ssh key as well if you have not already, if you do not have a ssh key pair just run the following command on your PC terminal:

NOTE: For window users you might need to install OpenSSH

$ ssh-keygen -t ed25519 -C "your_email@example.com"
Enter fullscreen mode Exit fullscreen mode

Connecting to the server

In your favourite IDE add the connection settings for your server:

  • In VSC install the following extension SSH FS and add your server configuration where:

    • The host is your server public address;
    • The port is 22;
    • The user is root.
  • In WebStorm just add an ssh configuration with the same options as seen above.

Finally open a terminal for you server inside the IDE.

Initial Server Commands

Before starting deployment we need to run some commands:

  1. Check and update the server software:

    # may take sometime
    $ sudo apt update
    $ sudo apt upgrade
    
  2. Install dokku the PaaS that we will use to deploy our API:

    $ wget https://raw.githubusercontent.com/dokku/dokku/v0.28.1/bootstrap.sh
    $ sudo DOKKU_TAG=v0.28.1 bash bootstrap.sh
    
  3. Assuming you have a valid domain for the API, go to your domain provider and add an A Record and a CNAME Record pointing to the server Public IP. If you do not have one you will need one, I recommend namecheap for the purchase;

  4. Set up dokku's SSH keys and Virtualhost settings:

    $ cat ~/.ssh/authorized_keys | dokku ssh-keys:add admin
    $ dokku domains:set-global your-domain.com
    

Deploying the API

For deploying the API you just need go through the following steps:

On the server terminal

  1. Create a new app and connect git:

    $ dokku apps:create app-name
    
  2. Install your database plugin, create a db instance and link it to your app:

    # For PostgresSQL
    $ sudo dokku plugin:install https://github.com/dokku/dokku-postgres.git postgres
    $ dokku postgres:create app-name-db
    $ dokku postgres:link app-name-db app-name
    
    # For MongoDB
    $ sudo dokku plugin:install https://github.com/dokku/dokku-mongo.git mongo
    $ dokku mongo:create app-name-db
    $ dokku mongo:link app-name-db app-name
    
  3. If you use cache with redis in your API, add Redis plugin to dokku, create a new Redis instance, and link it to your app:

    $ sudo dokku plugin:install https://github.com/dokku/dokku-redis.git redis
    $ dokku redis:create app-name-redis
    $ dokku redis:link app-name-redis app-name
    
  4. Add all the other environment variables that you need for your API to run:

    $ dokku config:set app-name URL=https://your-domain.com ...
    

On your local terminal

Add a git remote to deploy your app named dokku with your server Public IP Address:

$ git remote add dokku dokku@server-public-ip-address:app-name
$ git push dokku main:master
Enter fullscreen mode Exit fullscreen mode

Back on the server terminal

Finally set up SSL (for HTTPS) and the main domain or sub domain for your API:

$ sudo dokku plugin:install https://github.com/dokku/dokku-letsencrypt.git
$ dokku config:set --global DOKKU_LETSENCRYPT_EMAIL=your-email@your.domain.com
$ dokku domains:set app-name your-domain.com
$ dokku letsencrypt:enable app-name
$ dokku letsencrypt:cron-job --add 
Enter fullscreen mode Exit fullscreen mode

Conclusion

With this you are now able to deploy your NestJS Apps in any VPS.

Top comments (0)