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'
- 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'
- 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'
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),
};
};
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),
// ...
};
}
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",
// ...
},
// ...
}
To:
{
// ...
"scripts": {
// ...
"start": "node dist/main",
"start:dev": "nest start --watch",
"start:debug": "nest start --debug --watch",
// ...
},
// ...
}
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:
Server Options
Select the latest version of Ubuntu LTS (22.04):
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"
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:
-
Check and update the server software:
# may take sometime $ sudo apt update $ sudo apt upgrade
-
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
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;
-
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
-
Create a new app and connect git:
$ dokku apps:create app-name
-
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
-
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
-
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
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
Conclusion
With this you are now able to deploy your NestJS Apps in any VPS.
Top comments (0)