Deploying Angular SSR and NestJS Application to VPS

Robert Isaac
6 min readSep 17, 2023

--

Deploying Angular SSR and NestJS Application to VPS

recently I published my first website https://interview.community/ and it was a struggle to make it work fully in the server, also I have read ton of comments with people struggling with it too, because deploying Frontend and Backend application on the same server when the Frontend has SSR is a bit confusing, in this article I will show you from A to Z how to deploy Angular SSR application and NestJS together in clean Ubuntu VPS machine using Nginx as reverse proxy, will enable HTTPS for the domains and everything will be explained to you, mostly whatever in this article will also works fine if you have different frontend or backend, you just need to figure out how to do the deployment for your specific framework, even if your backend is in a total different language you can still follow this article for everything else

for the sake of this article I will be using this https://github.com/robertIsaac/nx-ng-nest nx mono repo

  1. create new VPS and add user and SSH to it
  2. clone the repo
  3. install the project dependencies and run the backend and frontend
  4. install nginx and make the project public
  5. enable HTTPS for your project

1. Create new VPS and add user and SSH to it

you shouldn’t use the root user given by your VPS for your day to day usage and deployment, it’s too dangerous if your credentials is exposed

so we will start by creating a new user (let’s call it rob) and give it sudo

first log into the server using ssh root@server-ip-address and enter the root user password

adduser rob # you will be ased to add password use strong password
usermod -aG sudo rob

test the new user using ssh rob@server-ip-address and enter the password to make sure everything is okay

for easier connection let’s setup SSH for this new user

then in your PC run ssh-keygen and follow the instruction, then copy the content of ~/.ssh/id_rsa.pub

and in your server mkdir ~/.ssh if the folder doesn't exist then nano ~/.ssh/authorized_keys and paste the content of your PC id_rsa.pub

now when you disconnect and connect again, it shouldn’t ask for the password anymore (but it may ask for the ssh key if you generated one)

this is good practice because it give your user non-admin access and to do something sanative it asks for the password

Clone the project

now you need to run ssh-keygen in the server then run, and copy the content of ~/.ssh/id_rsa.pub

go to https://github.com/settings/keys and add the new SSH key for the server to give the server access to your repos

then it’s better to clone it inside a repos directory so do mkdir ~/repos & cd ~/repos and start cloning your repo

if you don’t have git in your server install it using sudo apt update & sudo apt install git

install the project dependencies and run the backend and frontend

first let’s install curl using sudo apt install curl and if you haven’t installed git run first sudo apt update

then let’s install nvm using curl https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash

then let’s install node using nvm install latest or you can give it any version you want instead of latest

then in your repo install your dependencies using npm i yarn or pnpm i depending in your repo, if you are using anything other than npm you need to run first corepack enable

then build the project using npm run build

to run the project we should use pm2 install it globally using npm i -g pm2

then in the root of your project you should add ecosystem.config.js with content like

module.exports = {
apps: [
{
name: 'demo-ng',
script: 'dist/ng/server/main.js',
},
{
name: 'demo-nest',
script: 'dist/nest/main.js',
},
],
};

then just run pm2 start ecosystem.config.js to start it, you can see the log using pm2 log to fix any problems you may have

now you can to verify they are running using curl http://localhost:3000 and curl http://localhost:4200

install nginx and make the project public

I believe this is the most confusing part of the setup

first let’s install nginx using sudo apt install nginx

then let’s secure our server using ufw

sudo ufw allow 'OpenSSH'
sudo ufw allow 'Nginx FULL'
sudo ufw enable

be very careful because if ssh is not allowed, you will lose your access to the VPS for good, nginx full will give it both 80 and 443 (http and https)

while in the next step we will enable https, but you still need to give nginx http access so it can correctly redirect your users from http to https, otherwise anyone writing your domain without https will be stuck and will think your website is down

now you need to start adding nginx configuration

nano /etc/nginx/sites-available/website-name

and copy this content there

server {
listen 80;
listen [::]:80;
server_name website.com;
include /etc/nginx/mime.types;

gzip on;
gzip_min_length 1000;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;

location /api {
proxy_pass http://localhost:3000;
}

location / {
proxy_pass http://localhost:4000;
}

location ~* \.(jpg|jpeg|png|gif|swf|svg|ico|mp4|eot|ttf|otf|woff|woff2|css|js)$ {
proxy_pass http://localhost:4200;
add_header Cache-Control "max-age=86400, must-revalidate, s-maxage=2592000";
}
}

here is all the magic happen, first thing is to replace server_name with your website domain without http or https, don’t add port 443 this will happen in the next step

location /api {
proxy_pass http://localhost:3000;
}

this part will direct any traffic that start with /api to your port 3000 which is running using nest (if you are using different port change it here), for this to work correctly your angular application must use https://website.com/api/ as the root for all API calls, using only /api/ will make it work only in the browser but not in the SSR

location / {
proxy_pass http://localhost:4200;
}

this part will redirect anything else to our angular application

location ~* \.(jpg|jpeg|png|gif|swf|svg|ico|mp4|eot|ttf|otf|woff|woff2|css|js)$ {
proxy_pass http://localhost:4200;
add_header Cache-Control "max-age=86400, must-revalidate, s-maxage=2592000";
}

this part say that any of the following file formats (image, videos, fonts … etc, you can extend them if you have other formats) to also be redirected to 4200 but also will enable caching for them

then finally run this last command sudo ln -s /etc/nginx/sites-available/interview.community /etc/nginx/sites-enabled/ to link the configuration to your enabled sites

the last step to be public is that in your domain settings to add A record to your server IP

example for cloudflare

you can check if it’s working by using ping website.com and see if it gives you the server ip or something else, if it’s something else you need to wait till it refresh

then you should go and see yourself if it’s working or not

enable HTTPS for your project

this is the final step in this article, you should make sure that your application is working before trying it (it might not work fully because your API url in Angular has https:// )

it’s one of the most easist things to do, just run these commands

sudo apt install snapd
sudo snap install core; sudo snap refresh core
sudo snap install --classic certbot
sudo certbot --nginx

and that’s it, give it view minutes then go to your https:// to your website and check if it’s working :)

bonus step is to add www.website.com to redirect to your website, you need to also add A record in the domain then sudo nano /etc/nginx/sites-available/www.example.com with this content

server {
listen 80;
server_name www.example.com;
return 301 https://example.com$request_uri;
}

you will need to run the certbot again to generate ssl cert for it, or you can do it before running it so it generate both www and non-www cert together

--

--

Robert Isaac
Robert Isaac

Written by Robert Isaac

I am a Senior Front-End Developer who fall in love with Angular and TypeScript.

No responses yet