Comprehensive Guide to Deploying and Managing MERN Stack Applications on RHEL-Based VPS Print

  • 1

Introduction

The MERN stack (MongoDB, React, Express, Node.js) is a powerful and versatile full-stack framework for modern web applications. It offers a streamlined development process, scalability, and performance, making it a preferred choice for developers building everything from small-scale projects to enterprise solutions.

Key Components of the MERN Stack

  1. MongoDB: A NoSQL, document-based database designed for handling large datasets and providing horizontal scalability.
  2. Express.js: A minimal and flexible backend web framework for building RESTful APIs and web applications.
  3. React: A JavaScript library for creating dynamic, high-performance frontend user interfaces using reusable components.
  4. Node.js: A runtime environment that enables efficient, asynchronous backend development by handling concurrent requests seamlessly.

This guide focuses on deploying the MERN stack on RHEL-based VPS platforms such as Rocky Linux, AlmaLinux, and Oracle Linux, leveraging their stability, compatibility, and scalability.


Table of Contents

Introduction

  • Importance of the MERN Stack for Modern Web Development
  • Why Use a RHEL-Based VPS for Development?
  • Prerequisites for Following This Guide

Provisioning Your RHEL-Based VPS

  • Setting Up a KVM VPS from Domain India
  • Configuring Basic Settings: Hostname, Timezone, and SSH Access
  • Updating and Upgrading RHEL Packages

Installing Essential Tools

  • Installing Node.js and npm
  • MongoDB Installation and Configuration
  • Setting Up Git for Version Control
  • Installing Development Tools: curl, wget, and Build Essentials
  • Additional Packages: pm2, yarn

Setting Up the MERN Stack

  • Installing and Configuring Express.js
  • Connecting MongoDB with Mongoose
  • Creating React Projects
  • Integrating Frontend and Backend for Full-Stack Functionality

Server Configuration for MERN Applications

  • Setting Up Environment Variables with .env Files
  • Configuring Reverse Proxy with Nginx
  • Setting Up Custom Domains for Your Application

Optimizing for Performance

  • Enabling Compression for Node.js Applications
  • MongoDB Optimization Techniques
  • Using PM2 for Load Balancing and Application Management

Securing Your RHEL-Based VPS

  • Implementing SSH Key-Based Authentication
  • Configuring firewalld for Application Security
  • Enabling MongoDB Authentication and IP Whitelisting
  • Installing SSL Certificates Using Let’s Encrypt

Automating Backups

  • Backing Up MongoDB Databases Using mongodump
  • Automating File Backups with rsync and Cron Jobs
  • Configuring Cloud Backup Solutions

Monitoring and Maintenance

  • Using Monitoring Tools Like Nagios and Zabbix
  • Tracking Logs for Node.js and MongoDB
  • Setting Up Alerts for Critical Issues

Deploying Your Application

  • Testing Locally and Deploying to VPS
  • Using Git and GitHub for Code Management
  • Implementing CI/CD Pipelines for Faster Updates

Advanced Configurations

  • Setting Up Docker for MERN Projects
  • Using Redis for Caching
  • Configuring WebSockets for Real-Time Features

Troubleshooting Common Issues

  • Debugging MongoDB Errors
  • Resolving npm and Dependency Conflicts
  • Fixing React Build and Deployment Issues

Conclusion

  • Recap of Steps Taken
  • Best Practices for Ongoing Management
  • Useful Links and Resources

Appendix

  • Command Cheat Sheet for MERN Stack Development
  • Sample Configuration Files
  • Links to Official Documentation

Importance of the MERN Stack for Modern Web Development

The MERN stack combines the power of modern web technologies, making it one of the most popular choices for developers:

  1. Unified Development Environment: A single programming language (JavaScript) across the stack simplifies the development process and enhances productivity.
  2. Scalability: MongoDB’s NoSQL model allows seamless handling of large datasets and high user loads.
  3. High Performance: Node.js provides non-blocking I/O, ensuring faster server responses even under heavy traffic.
  4. Rich Ecosystem: React’s extensive library support and reusable components enable dynamic, high-performance frontends.

Why Use a RHEL-Based VPS for Development?

Benefits of RHEL-Based Distributions

RHEL-based operating systems such as Rocky Linux, AlmaLinux, and Oracle Linux provide:

  • Stability and Security: Built for enterprise use, offering long-term support and robust security.
  • Compatibility: Binary compatibility with RHEL ensures seamless application deployment.
  • Cost Efficiency: Free alternatives like Rocky Linux and AlmaLinux eliminate subscription fees while providing enterprise-grade features.
  • Flexibility: Suitable for projects ranging from personal development to large-scale production environments.

Key RHEL-Based Distributions

  1. CentOS Stream (Development Only):

    • A rolling-release distribution providing upstream development access for RHEL. Ideal for testing and development environments but not recommended for production due to its rolling nature and potential instability.
  2. Rocky Linux (Development and Production):

    • A widely adopted, community-driven replacement for CentOS. Designed for production environments, offering robust long-term support (LTS) and stability.
  3. AlmaLinux (Development and Production):

    • A 1:1 binary-compatible RHEL alternative, backed by a non-profit foundation. Provides enterprise-grade features and is highly suitable for both development and production use.
  4. Oracle Linux (Development and Production):

    • Optimized for Oracle applications but also a viable choice for general-purpose development and production environments. Offers strong performance and enterprise support.
  5. ClearOS (Development and Small-Scale Production):

    • A user-friendly RHEL-based distribution aimed at small businesses. Simplified management makes it ideal for small-scale deployments, though not as robust for large-scale production.

Summary:

  • Development Only: CentOS Stream.
  • Development and Production: Rocky Linux, AlmaLinux, Oracle Linux.
  • Small-Scale Use: ClearOS.

With a RHEL VPS, you gain the flexibility to tailor your server for your specific MERN stack requirements, whether for development, production, or small-scale projects.


Prerequisites for Following This Guide

To proceed with the guide, you’ll need the following:

  1. A RHEL 8.x or 9.x VPS: Ensure root or sudo access to the server.
  2. Basic Knowledge of Linux Commands: Familiarity with terminal operations is essential.
  3. SSH Client Installed: A tool like PuTTY (Windows) or the native SSH command (Linux/Mac) for accessing the VPS.
  4. A Domain India KVM VPS Plan: Purchase a VPS plan here.
  5. Internet Connection: Ensure the VPS has internet connectivity for package installations.

Provisioning Your RHEL VPS

Setting Up a KVM VPS from Domain India

  • Log in to your Domain India client area and purchase a suitable KVM VPS plan.
  • After setup, use the credentials sent by Domain India to connect to the VPS:
    ssh root@your-server-ip

Configuring Basic Settings: Hostname, Timezone, and SSH Access

Set the hostname to identify your VPS:
hostnamectl set-hostname my-mern-vps

Configure the timezone for your server:
timedatectl set-timezone Asia/Kolkata

Set Up SSH Key-Based Authentication on RHEL
Before disabling root login, configure SSH key-based access to ensure secure and uninterrupted access to the server.

Step 1: Create a Non-Root User

Log in as the root user:
ssh root@your-server-ip

Add a new user:
adduser newusername

Grant the user sudo privileges:
usermod -aG wheel newusername


Step 2: Generate an SSH Key Pair

On your local machine, generate an SSH key pair if you don’t already have one:
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"

Save the keys in the default location (e.g., ~/.ssh/id_rsa and ~/.ssh/id_rsa.pub).


Step 3: Copy the SSH Key to the Server

Copy your public key to the server for the new user:
ssh-copy-id newusername@your-server-ip

Alternatively, manually copy the contents of the public key file (e.g., ~/.ssh/id_rsa.pub) to the following location on the server:
/home/newusername/.ssh/authorized_keys

Ensure the permissions for the .ssh directory and the authorized_keys file are correct:
chmod 700 /home/newusername/.ssh
chmod 600 /home/newusername/.ssh/authorized_keys

Secure the server by editing the SSH configuration file:

Open the file:
nano /etc/ssh/sshd_config

Disable root login by modifying:
PermitRootLogin no

Save and restart the SSH service:
systemctl restart sshd


Updating and Upgrading RHEL Packages

Update your system packages to the latest versions:
yum update -y

Install additional tools and repositories for better compatibility:
yum install -y epel-release vim wget curl


Installing Essential Tools

Step-by-Step Guide to Installing Node.js and npm

Enable the NodeSource repository:
curl -sL https://rpm.nodesource.com/setup_16.x | bash -

Install Node.js and npm:
yum install -y nodejs

Verify the installation:

Check Node.js version:
node -v

Check npm version:
npm -v


MongoDB Installation on RHEL

Step 1: Add the MongoDB Repository

Create and edit the repository file for MongoDB 6.0:

cat <<EOF | tee /etc/yum.repos.d/mongodb-org-6.0.repo
[mongodb-org-6.0]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/redhat/8/mongodb-org/6.0/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-6.0.asc
EOF

Step 2: Install MongoDB

Install MongoDB using the yum package manager:

sudo yum install -y mongodb-org

Step 3: Start and Enable MongoDB

Enable MongoDB to start automatically and verify it is running:

sudo systemctl start mongod
sudo systemctl enable mongod
sudo systemctl status mongod

Step 4: Test the Installation

Verify that MongoDB is installed and operational:

mongo --version

Additional Notes:

  1. Ensure Repository Accuracy: The repository URL should match your server's architecture and OS version. The above example is for RHEL 8.x and 64-bit architecture.
  2. SELinux and Firewall Configuration: If SELinux is enabled or firewalld is in use, ensure the appropriate ports (default: 27017) are open and policies are configured correctly.


Installing Git for Version Control

Install Git:
yum install -y git

Verify the installation:
git --version

Configure Git with your details:

Set your name:
git config --global user.name "Your Name"

Set your email:
git config --global user.email "youremail@example.com"


Setting Up Development Tools: cURL, wget, and Build Essentials

Install the required tools:
yum install -y curl wget gcc gcc-c++ make

Verify installations:

Check cURL version:
curl --version

Check wget version:
wget --version


Installing Additional Packages: pm2, yarn

Install pm2 globally using npm:
npm install -g pm2

Install yarn package manager:
npm install -g yarn

Verify installations:

Check pm2 version:
pm2 -v

Check yarn version:
yarn -v

Setting Up the MERN Stack

Installing and Configuring Express.js for Backend

Create a directory for your backend application:
mkdir backend && cd backend

Initialize a new Node.js project:
npm init -y

Install Express.js:
npm install express

Create a basic Express.js server in index.js:

const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;

app.get('/', (req, res) => {
    res.send('Hello, MERN Stack!');
});

app.listen(PORT, () => {
    console.log(`Server is running on port ${PORT}`);
});

Run the server:
node index.js


Connecting MongoDB with Mongoose

Install Mongoose in your backend project:
npm install mongoose

Connect to MongoDB in index.js:

 

const mongoose = require('mongoose');

mongoose.connect('mongodb://localhost:27017/mern-stack', {
    useNewUrlParser: true,
    useUnifiedTopology: true,
})
.then(() => console.log('MongoDB connected successfully'))
.catch(err => console.log('MongoDB connection error:', err));

Test the connection by restarting the server:
node index.js


Creating React Projects and Building Frontend Applications

  1. Install create-react-app globally (optional):
    npm install -g create-react-app

  2. Create a new React application:
    npx create-react-app frontend

  3. Navigate to the React project directory:
    cd frontend

  4. Start the development server:
    npm start

  5. Customize the default React component:
    Modify the file src/App.js with the following code:

    function App() {
        return (
            <div className="App">
                <h1>Welcome to the MERN Stack</h1>
            </div>
        );
    }
    
    export default App;
    
    Your React app will be live at http://localhost:3000.

Integrating Frontend and Backend for Full-Stack Functionality

  1. Add a proxy to connect React to the backend:
    Open the file frontend/package.json and add the following line:

    "proxy": "http://localhost:5000"

  2. Update the backend to serve React files in production:
    Modify index.js in the backend directory with the following code:

    const path = require('path');
    const express = require('express');
    const app = express();
    
    // Serve React static files
    app.use(express.static(path.join(__dirname, '../frontend/build')));
    
    // Handle all unmatched routes with the React app
    app.get('*', (req, res) => {
        res.sendFile(path.join(__dirname, '../frontend/build', 'index.html'));
    });
    
    const PORT = process.env.PORT || 5000;
    app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
    
  3. Build the React app for production:
    Run the following command inside the frontend directory:

    npm run build

  4. Start the integrated application:
    Run the backend server with the following command:

    node index.js

Install the dotenv package:
npm install dotenv

Load the environment variables in index.js:

require('dotenv').config();
const PORT = process.env.PORT;
const MONGO_URI = process.env.MONGO_URI;

Configuring Reverse Proxy with Nginx

Install Nginx:
yum install -y nginx

Create a configuration file for your application:

Open /etc/nginx/conf.d/mern-stack.conf and add:

server {
    listen 80;

    server_name your-domain.com;

    location / {
        proxy_pass http://localhost:5000;
        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;
    }
}
​

Restart Nginx to apply changes:
systemctl restart nginx

Setting Up Custom Domains for Your App

Point your domain's DNS to the VPS IP address.

Update the Nginx server_name directive to use your domain (e.g., your-domain.com).

Test the domain in a browser to ensure it resolves correctly.


Optimizing for Performance

Enabling Compression for Node.js Applications

Install the compression package:
npm install compression

Use the package in your Express.js app:

const compression = require('compression');
app.use(compression());

Restart your server to apply compression.

MongoDB Optimization Techniques for Scalability

Enable journaling for better performance and crash recovery:
Edit /etc/mongod.conf and ensure the following is enabled:

storage:
    journal:
        enabled: true

Index frequently queried fields for faster lookups:

const schema = new mongoose.Schema({
    name: { type: String, index: true },
});
​

Monitor MongoDB performance using built-in tools:
Use mongostat and mongotop commands to identify bottlenecks.


Using PM2 for Load Balancing and Application Management

Start your application with PM2:
pm2 start index.js

Monitor running applications:
pm2 list

Enable application auto-restart on server reboot:
pm2 startup
pm2 save

Securing Your RHEL VPS

Implementing SSH Key-Based Authentication

Generate an SSH key pair on your local machine:
ssh-keygen -t rsa -b 4096 -C "your-email@example.com"

Copy the public key to the VPS:
ssh-copy-id root@your-server-ip

Test the SSH connection to ensure it works:
ssh root@your-server-ip

Disable password authentication for added security:

Open the SSH configuration file:
nano /etc/ssh/sshd_config

Modify or add:
PasswordAuthentication no

Restart SSH:
systemctl restart sshd


Configuring firewalld for Application and Database Security

Install firewalld:
yum install -y firewalld

Start and enable firewalld:
systemctl start firewalld
systemctl enable firewalld

Open necessary ports:

HTTP (80) and HTTPS (443):
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https

MongoDB (27017):
firewall-cmd --permanent --add-port=27017/tcp

Reload the firewall to apply changes:
firewall-cmd --reload


Enabling MongoDB Authentication and IP Whitelisting

Open MongoDB configuration:
nano /etc/mongod.conf

Enable authentication by adding:

security:
    authorization: "enabled"

Restart MongoDB:
systemctl restart mongod

Create an admin user:

use admin
db.createUser({
    user: "admin",
    pwd: "strongpassword",
    roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
});

Restrict MongoDB access to specific IPs by editing the bind IP:

net:
    bindIp: 127.0.0.1,192.168.1.100
​

Restart MongoDB to apply changes:
systemctl restart mongod

Installing SSL Certificates Using Let’s Encrypt

Install Certbot:
yum install -y certbot python3-certbot-nginx

Obtain an SSL certificate:
certbot --nginx -d your-domain.com -d www.your-domain.com

Test the SSL configuration:
certbot renew --dry-run

Set up automatic renewal:
systemctl enable certbot-renew.timer


Automating Backups

Backing Up MongoDB Databases Using mongodump

Create a directory for backups:
mkdir -p /backups/mongodb

Run mongodump to create a backup:
mongodump --out /backups/mongodb/$(date +%F)

Schedule daily backups using cron:

Open the crontab:
crontab -e

Add the following line:
0 2 * * * mongodump --out /backups/mongodb/$(date +\%F)


Automating File Backups with rsync and Cron Jobs

Install rsync:
yum install -y rsync

Create a backup script:

rsync -avz /var/www/html /backups/files/

Schedule the script with cron:

Open the crontab:
crontab -e

Add the following line:
0 3 * * * rsync -avz /var/www/html /backups/files/


Configuring Cloud Backup Solutions

Install a cloud storage CLI, such as AWS CLI:
yum install -y aws-cli

Configure the AWS CLI with your credentials:
aws configure

Use the AWS CLI to upload backups to an S3 bucket:

aws s3 cp /backups/mongodb s3://your-s3-bucket/ --recursive

Automate this with a cron job.

Monitoring and Maintenance

Using Monitoring Tools Like Nagios and Zabbix

Install Nagios or Zabbix (choose one based on preference).

Nagios:
yum install -y nagios

For a step-by-step guide to setting up and optimizing Nagios, check out our article on Mastering Nagios: A Comprehensive Guide to Server Monitoring.

Zabbix:
Follow the official Zabbix installation guide.

Configure monitoring for critical services like Node.js, MongoDB, and Nginx.


Tracking Logs for Node.js and MongoDB Applications

View Node.js application logs:
pm2 logs

Monitor MongoDB logs:
tail -f /var/log/mongodb/mongod.log

Use a log analyzer like ELK Stack (Elasticsearch, Logstash, Kibana) for detailed insights.


Setting Up Alerts for Critical Errors

Use a monitoring tool with alerting capabilities, such as Nagios or Zabbix.

Configure email or SMS notifications for critical events like high CPU usage, memory usage, or database errors.

Test alerts to ensure they trigger correctly during failures.


Deploying Your Application

Testing Locally and Deploying to the VPS

Test Locally:

Ensure your application works on your local environment.

Test frontend and backend APIs to ensure functionality.

Run:
npm start for React.
node index.js or pm2 start index.js for Node.js.

Prepare for Deployment:

Build the frontend:
cd frontend && npm run build

Copy the build/ folder to the backend directory.

Deploy to VPS:

Copy project files to the VPS using SCP:
scp -r /path/to/project root@your-server-ip:/var/www/mern-app

Set permissions:
chmod -R 755 /var/www/mern-app

Start the application:
pm2 start index.js


Using Git and GitHub for Code Management

Initialize a Git Repository:

Inside your project directory:
git init

Push Code to GitHub:

Add files to Git:
git add .

Commit changes:
git commit -m "Initial commit"

Push to a GitHub repository:

git remote add origin https://github.com/username/repo.git  
git push -u origin main
​

Deploy Using Git on VPS:

Clone the repository:
git clone https://github.com/username/repo.git /var/www/mern-app

Pull updates when necessary:
cd /var/www/mern-app && git pull origin main

Implementing CI/CD Pipelines for Faster Updates

Use GitHub Actions for CI/CD:

Create a .github/workflows/deploy.yml file:

name: Deploy Application

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v2

      - name: Deploy to Server
        run: |
          scp -r . root@your-server-ip:/var/www/mern-app
          ssh root@your-server-ip "pm2 restart index.js"
​

Test the Pipeline:

Push code to the main branch and verify the deployment.


Advanced Configurations

Setting Up Docker Containers for MERN Projects

Install Docker:
yum install -y docker
systemctl start docker && systemctl enable docker

Create a Dockerfile:

FROM node:16
WORKDIR /app
COPY . .
RUN npm install
CMD ["node", "index.js"]

 

Build and Run the Docker Container:

Build:
docker build -t mern-app .

Run:
docker run -d -p 3000:3000 mern-app


Using Redis for Caching

Install Redis:
yum install -y redis
systemctl start redis && systemctl enable redis

Integrate Redis in Node.js:

Install the package:
npm install redis

Use it in your app:

const redis = require('redis');
const client = redis.createClient();
client.on('connect', () => console.log('Connected to Redis'));
​


Configuring WebSockets for Real-Time Applications

Install socket.io:
npm install socket.io

Integrate WebSockets in Node.js:

const io = require('socket.io')(server);
io.on('connection', (socket) => {
    console.log('A user connected');
    socket.on('disconnect', () => console.log('A user disconnected'));
});

Test with a WebSocket client to ensure real-time communication works.


Troubleshooting Common Issues

Debugging Common MongoDB Errors

Connection Errors:
Ensure MongoDB is running:
systemctl status mongod
Verify the connection string:
mongodb://localhost:27017/your-database

Authentication Errors:
Use the correct user credentials and roles.


Resolving npm and Dependency Conflicts

Delete node_modules and reinstall dependencies:
rm -rf node_modules && npm install

Use a specific version of a conflicting package:
npm install package-name@version


Handling React Build and Deployment Errors

Ensure correct homepage in package.json:

"homepage": "https://your-domain.com",

Rebuild React after updates:
npm run build

Verify React files are served correctly by your backend.


Conclusion

Recap of Steps Taken

Provisioned and configured a RHEL VPS.

Set up the MERN stack with MongoDB, React, Express, and Node.js.

Secured the server using SSH keys, firewalld, and SSL.

Deployed and tested the application.

Optimized for performance and set up monitoring.


Best Practices for Ongoing Management

Regularly update your packages and system.

Use CI/CD pipelines for seamless updates.

Monitor application logs and server performance.

Automate backups to ensure data safety.


Useful Links and Additional Resources

Node.js Official Documentation

MongoDB Documentation

React Official Guide

Express.js Documentation


Appendix

Command Cheat Sheet for MERN Stack Development

Start MongoDB:
systemctl start mongod

Start React:
npm start

Deploy Node.js app with PM2:
pm2 start index.js


Sample Configuration Files

Nginx Configuration:

server {
    listen 80;
    server_name your-domain.com;
    location / {
        proxy_pass http://localhost:5000;
    }
}

MongoDB Configuration:

security:
    authorization: "enabled"
net:
    bindIp: 127.0.0.1
​

Key References from Existing Articles

Before diving into the guide, here are some references to relevant articles that provide foundational knowledge for this guide:

KVM VPS Setup Guide

Mastering the MERN Stack: Your Ultimate Resource Guide

Managing a Sample App with Git, GitHub, and VSCode

Installing Node.js and npm

React.js: A Comprehensive Guide

Unlocking MongoDB and Mongoose

Building a Sample App with MERN Stack on AlmaLinux VPS

 

 


Was this answer helpful?

« Back