Deploying a Node.js Application on a Virtual Machine Using a Service Manager

Launching a Node.js application on a virtual machine (VM) is a vital process for ensuring that your application remains stable, dependable, and capable of scaling. While many suggest using tools like PM2 and Tmux for managing Node.js applications, it is entirely feasible to deploy your app using a service manager like systemd. This article will provide you with a step-by-step guide to deploying your Node.js application on a VM utilizing systemd.

Why Not Use PM2 or Tmux?

While PM2 and Tmux are excellent tools for managing Node.js applications, there are several reasons to consider using systemd instead:

  1. Built-in Service Management: systemd is a native service manager for many Linux distributions, providing process management capabilities without additional dependencies.
  2. System Integration: Since systemd is integrated into the system's init process, it allows for better control over service lifecycles and resource management.
  3. Automatic Restart: With systemd, you can easily configure services to restart automatically on failure, providing high availability.

Setting Environment

To begin with Node deployment:

  • Setup the node environment.
  • Checkout the application code.
  • Install the dependencies of the application. Either it’s frontend or backend application.
  • Setup Reverse proxy like nginx or apache2 if you want to run multiple application on same server (vm), by adding virtual hosts configurations.
  • Create a service file

Let's begin with installing the dependencies like NodeJS and if willing then nginx or apache.

Update the machine with: 

apt update & apt upgrade

Install Node version, where X as minor version:

curl -sL https://deb.nodesource.com/setup_20.x -o /tmp/nodesource_setup. sh

Verify the node install script:

sudo bash /tmp/nodesource_setup.sh

Begin the node install and nginx

sudo apt install nodejs nginx


Running Application For first Time


Clone Your Application Repository

git clone https://github.com/your-repository/node-app.git

cd node-app

After cloning the repo, install the required dependencies: npm install​ or pnpm install

Run app: npm start​ or npm start

Build the application, so it not compile each time: pnpm run build​ or  npm run build

Now location the application folder by going inside app folder and running pwd​ command. This will return path like: /opt/yourapp/​ Now locate the npm​ or node​ executable path:

which node​ or which npm​, it will return:

/usr/local/bin/node​ or /usr/local/bin/npm

Create a Systemd Service File

Now write the service file for the app, mentioning the paths and executables. Along with pid name, service name,runner. As below:

sudo vim /etc/systemd/system/my-node-app.service

[Unit]
Description=My Node.js Application
After=network.target
[Service]
ExecStart=/usr/local/bin/node node-app​/app.js 
# OR
# ExecStart=/usr/local/bin/npm start
WorkingDirectory=/opt/destination
Environment=PATH=/usr/local/bin:/usr/bin:/bin
Environment=NODE_ENV=production
Restart=always
User=ubuntu
Group=root
StandardOutput=append:/var/log/mylogs/output.log
StandardError=append:/var/log/mylogs/error.log
[Install]
WantedBy=multi-user.target


Key Components of the Service File:

[Unit]: This section contains metadata and dependencies. The After=network.target line ensures that the service starts after the network is available.

[Service]: This section defines how the service behaves:

  • ExecStart: The command to start your Node.js application.
  • Restart: This setting specifies that the service should always restart if it fails.
  • User and Group: Specify the user and group under which the service will run.
  • Environment: Sets environment variables for your application, like NODE_ENV=production.
  • WorkingDirectory: Defines the directory from which your Node.js application runs.


Service Creation Post task:

sudo mkdir –p /var/log/mylogs/

sudo chown –R ubuntu:root /var/log/mylogs/


Reload Systemd and Start Your Service

After creating the service file, reload the systemd manager configuration and start your service:

# Reload systemd to recognize the new service 

sudo systemctl daemon-reload

# Start the Node.js service 

sudo systemctl start my-node-app

# Enable the service to start on boot 

sudo systemctl enable my-node-app

These last 3 commands are for service.

Strat: sudo service my-node-app start

Stop: sudo service my-node-app stop

Restart: sudo service my-node-app restart


Monitoring and Optimization

To ensure your application runs smoothly, regularly monitor the logs and resource usage. You can also configure resource limits in your service file if needed. Adding parameters like LimitNOFILE, MemoryLimit, and CPUShares can help manage system resources effectively.


If need to use nginx as reverse proxy your application, you may follow below steps: as nginx is already installed.

sudo nano /etc/nginx/sites-available/nodeapp


server {
    listen 80;
    server_name nodeapp.example.com;
    location / {
        proxy_pass http://localhost:3000;  # Change the port if your app runs on a different port
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
    # Optional: Serve static files from a directory
    location /static {
        alias /path/to/your/static/files;  # Update with your static files directory
    }
    # Optional: Add a location for error pages
    error_page 404 /404.html;
    location = /404.html {
        root /path/to/your/error/pages;  # Update with your error pages directory
    }
    # Optional: Redirect to HTTPS (if you have SSL)
    # listen 443 ssl;
    # ssl_certificate /path/to/your/certificate.crt;
    # ssl_certificate_key /path/to/your/private.key;
}


Enable the Configuration


sudo ln -s /etc/nginx/sites-available/nodeapp /etc/nginx/sites-enabled/


Test Nginx Configuration

sudo nginx -t

Restart Nginx

sudo systemctl restart nginx


Conclusion

Utilizing systemd to deploy a Node.js application on a virtual machine offers a reliable and streamlined approach to application management, eliminating the need for external tools such as PM2 or Tmux. By taking advantage of systemd's built-in service management features, you can guarantee that your application remains operational, automatically recover from unexpected failures, and achieve smooth integration with the operating system.

This guide will empower you to set up and oversee your Node.js application effectively, allowing you to concentrate on coding rather than on tedious process management. If you prioritize stability and straightforward management, deploying your Node.js applications with systemd is a superb option.


Hope you find this helpful !!!

Do share your views...

Deploying a Node.js Application on a Virtual Machine Using a Service Manager
Ram Krishna September 25, 2024
Share this post
Sign in to leave a comment
Understanding NGINX Common Headers and Their Functions