Deploy Multiple Adonis.js Applications with PM2 and Nginx on Ubuntu 20.04

Updated on April 1, 2022
Deploy Multiple Adonis.js Applications with PM2 and Nginx on Ubuntu 20.04 header image

AdonisJS is a web framework for Node.js that lets you write web apps or an API server easier. In version 5, AdonisJS uses TypeScript for the core framework and the application. This guide explains how to deploy multiple AdonisJS apps on one server using PM2 and Nginx.

Prerequisites

Before you begin, you should:

Install Node.js

  1. Install Node.js using Ubuntu APT repository:

     $ sudo apt update
     $ sudo apt install nodejs npm
  2. Ubuntu comes with an outdated Node.js. AdonisJS requires at least Node.js version 14, so you need to update it.

     $ node -v
     v10.19.0
  3. Install the n package. It helps you update Node.js.

     $ sudo npm install n -g
  4. Update Node.js using the n package.

     $ sudo n stable
  5. Check the Node.js version.

     $ node -v
     v16.13.2

If the Node.js version is not yet changed, you need to disconnect and reconnect your ssh session.

Create Sample Applications

In this guide, you are creating two sample apps. The first one is a web app and the second one is an API server.

  1. Create a directory to place the apps.

     $ mkdir apps
  2. Change to the directory.

     $ cd apps
  3. Initialize the first sample app and select the web project structure.

     $ npm init adonis-ts-app@latest example1
  4. Initialize the second app and select the API project structure.

     $ npm init adonis-ts-app@latest example2

You have two folders, example1 and example2, containing your two apps. To run them simultaneously, you need to change the second app port.

Go to the example2 directory and edit the .env file:

$ cd example2
$ nano .env

Change the port number to anything you like, for example, 3334.

PORT=3334

Build for Production

Because the AdonisJS application uses TypeScript, you must compile it to JavaScript before running it in production.

  1. Go to the first app folder and run the build Ace command. The compiled result is in the build folder.

     $ cd ~/apps/example1
     $ node ace build --production
  2. After that, copy the .env file to the build folder and edit it.

     $ cp .env build/.env
     $ nano build/.env
  3. Set the NODE_ENV variable in the .env file to production.

     NODE_ENV=production
  4. Install production-only dependencies inside the build folder.

     $ cd build
     $ npm ci --production 

Repeat the process above for the second app.

Using PM2 to Run the Apps

PM2 is a daemon process manager that helps you manage and keep your Node.js applications online.

  1. Install the latest PM2 package.

     $ sudo npm install pm2@latest -g
  2. Create the PM2 ecosystem file to manage all your apps.

     $ cd ~/apps
     $ nano ecosystem.config.js
  3. Add these configurations to the ecosystem.config.js file.

     module.exports = {
         apps : [
             {
                 name   : "example1",
                 script : "./example1/build/server.js"
             },
             {
                 name   : "example2",
                 script : "./example2/build/server.js"
             }
         ]
     }
  4. Run all of your apps.

     $ pm2 start ecosystem.config.js

All your apps are running now, you can check it by using this command:

$ pm2 list

You see the two example apps in that list. You can access your apps from a web browser using your Vultr VPS IP address plus the app port numbers.

// Example 1
http://[VULTR_VPS_IP_ADDRESS]:3333

// Example 2
http://[VULTR_VPS_IP_ADDRESS]:3334

You may need to disable the firewall if you can't access it using the port number. You can enable it again later.

$ sudo ufw disable

At this point, all your apps are running. But, this process is not persistent yet, meaning that if you restart your server, your apps are not automatically run on the startup. You must run them manually again.

To have persistent apps running you need to generate a startup script for PM2.

  1. Run the following command.

     $ pm2 startup
  2. Copy and paste the displayed command onto the terminal.

     $ sudo env PATH=$PATH:/usr/local/bin /usr/local/lib/node_modules/pm2/bin/pm2 startup systemd -u <user> --hp <home-path>
  3. Save your PM2 app list using this command.

     $ pm2 save

Nginx Reverse Proxy

The next step is connecting your domains to your apps. You use Nginx reverse proxy to be able to do that. In general, you put your apps behind the Nginx web server. Nginx accepts all incoming requests and forwards them to your apps.

  1. Install Nginx.

     $ sudo apt update
     $ sudo apt install nginx
  2. Disable the default Nginx configuration.

     $ sudo unlink /etc/nginx/sites-enabled/default
  3. Create an Nginx configuration file for the first sample app.

     $ sudo nano /etc/nginx/sites-available/example1.com
  4. Paste in the following configuration.

     server {
         listen 80;
    
         server_name example1.com;
    
         location / {
             proxy_pass http://localhost:3333;
             proxy_http_version 1.1;
             proxy_set_header Upgrade $http_upgrade;
             proxy_set_header Connection 'upgrade';
             proxy_set_header Host $host;
             proxy_set_header X-Real-IP $remote_addr;
             proxy_set_header X-Forwarded-Proto $scheme;
             proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
             proxy_cache_bypass $http_upgrade;
         }
     }
  5. Create a configuration file for the second app.

     $ sudo nano /etc/nginx/sites-available/example2.com
  6. Paste in the following configuration.

     server {
         listen 80;
    
         server_name example2.com;
    
         location / {
             proxy_pass http://localhost:3334;
             proxy_http_version 1.1;
             proxy_set_header Upgrade $http_upgrade;
             proxy_set_header Connection 'upgrade';
             proxy_set_header Host $host;
             proxy_set_header X-Real-IP $remote_addr;
             proxy_set_header X-Forwarded-Proto $scheme;
             proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
             proxy_cache_bypass $http_upgrade;
         }
     }

    Please note that you must change the domain names (example1.com and example2.com) to your own domains.

  7. Enable the configuration files.

     $ sudo ln -s /etc/nginx/sites-available/example1.com /etc/nginx/sites-enabled/
     $ sudo ln -s /etc/nginx/sites-available/example2.com /etc/nginx/sites-enabled/
  8. Test your configurations for syntax errors.

     $ sudo nginx -t

    If there are no errors then reload the Nginx process.

     $ sudo systemctl reload nginx

Point your domains to your Vultr VPS IP address. And you can access your apps in the browser using the domain names.

Secure Apps with Let’s Encrypt SSL Certificate

Let’s Encrypt provides a free SSL certificate for your apps. It has a software client named Certbot to generate the certificate.

  1. Install Certbot.

     $ sudo snap install core; sudo snap refresh core
     $ sudo snap install --classic certbot
     $ sudo ln -s /snap/bin/certbot /usr/bin/certbot
  2. Generate the SSL certificate.

     $ sudo certbot --nginx
  3. Visit your domains in the browser and confirm they have an HTTPS connection.

Autorenew the SSL Certificate

Let’s Encrypt SSL certificate expires after 90 days. You can set up a Cron job to renew the SSL certificate automatically.

  1. Test certificate renewal command.

     $ sudo certbot renew --dry-run
  2. Set up the Cron job.

     $ sudo crontab -e
  3. Add the following line.

     15 3 * * * /usr/bin/certbot renew --quiet; /bin/systemctl reload nginx

Set Up the Firewall

In the earlier step, you disable the firewall for testing purposes. You need to enable it again to make your server more secure.

  1. Set the firewall to allow the SSH port.

     $ sudo ufw allow 'OpenSSH'
  2. Allow HTTP and HTTPS ports.

     $ sudo ufw allow 'Nginx Full'
  3. Enable the firewall.

     $ sudo ufw enable
  4. Check firewall status.

     $ sudo ufw status

Conclusion

This completes the installation of multiple AdonisJS apps on one server using PM2 and Nginx, secured with a Let’s Encrypt SSL certificate. The firewall only allows SSH, HTTP, and HTTPS connections.

More Information on AdonisJS

[AdonisJS Official Website](https://adonisjs.com)
[AdonisJS Documentation](https://docs.adonisjs.com/guides/introduction)