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
- MongoDB: A NoSQL, document-based database designed for handling large datasets and providing horizontal scalability.
- Express.js: A minimal and flexible backend web framework for building RESTful APIs and web applications.
- React: A JavaScript library for creating dynamic, high-performance frontend user interfaces using reusable components.
- 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:
- Unified Development Environment: A single programming language (JavaScript) across the stack simplifies the development process and enhances productivity.
- Scalability: MongoDB’s NoSQL model allows seamless handling of large datasets and high user loads.
- High Performance: Node.js provides non-blocking I/O, ensuring faster server responses even under heavy traffic.
- 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
-
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.
-
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.
-
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.
-
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.
-
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:
- A RHEL 8.x or 9.x VPS: Ensure root or sudo access to the server.
- Basic Knowledge of Linux Commands: Familiarity with terminal operations is essential.
- SSH Client Installed: A tool like PuTTY (Windows) or the native SSH command (Linux/Mac) for accessing the VPS.
- A Domain India KVM VPS Plan: Purchase a VPS plan here.
- 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:
- 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.
- 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
-
Install
create-react-app
globally (optional):npm install -g create-react-app
-
Create a new React application:
npx create-react-app frontend
-
Navigate to the React project directory:
cd frontend
-
Start the development server:
npm start
-
Customize the default React component:
Modify the filesrc/App.js
with the following code:
Your React app will be live atfunction App() { return ( <div className="App"> <h1>Welcome to the MERN Stack</h1> </div> ); } export default App;
http://localhost:3000
.
Integrating Frontend and Backend for Full-Stack Functionality
-
Add a proxy to connect React to the backend:
Open the filefrontend/package.json
and add the following line:"proxy": "http://localhost:5000"
-
Update the backend to serve React files in production:
Modifyindex.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}`));
-
Build the React app for production:
Run the following command inside thefrontend
directory:npm run build
-
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
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:
Mastering the MERN Stack: Your Ultimate Resource Guide
Managing a Sample App with Git, GitHub, and VSCode
React.js: A Comprehensive Guide
Unlocking MongoDB and Mongoose
Building a Sample App with MERN Stack on AlmaLinux VPS