Thanks for visiting my GitHub account!
This document provides a comprehensive guide for setting up a MERN (MongoDB, Express, React, Node.js) stack application with Apache SSL configuration, including automatic HTTPS redirection, reverse proxy for API calls, and PM2 process management on a DigitalOcean VPS with Apache as the web server. The application is hosted under the subdomain clientoperation.2ndsource.xyz
.
- Overview
- Architecture
- Prerequisites
- MongoDB Setup
- Quick Start
- Frontend Deployment (In tsstech User)
- Backend Deployment (In tsstech User)
- Process Management
- Service Management
- Testing & Verification
- Maintenance & Updates
- Troubleshooting
- Performance Monitoring
- Security Considerations
- Quick Reference Commands
- Directory Structure
- Contributing
- License
System Configuration:
- Main Domain: 2ndsource.xyz
- Subdomain: clientoperation.2ndsource.xyz
- Frontend Port: 3000 (React)
- Backend Port: 5000 (Node.js)
- Web Server: Apache with Reverse Proxy
- Database: MongoDB
Ensure the subdomain points to your VPS IP address by creating an A record:
Type | Name | Value | TTL |
---|---|---|---|
A | clientoperation | [YOUR_VPS_IP_ADDRESS] | 3600 |
Internet β Apache (Port 80/443) β Static Files (/var/www/html/clientoperation)
β API Proxy β Node.js Backend (Port 5000)
- Ubuntu/Debian server with sudo access
- Domain name configured (clientoperation.2ndsource.xyz)
- SSL certificates obtained via Let's Encrypt
- Apache2 installed
- Basic familiarity with command line
Before starting the deployment, ensure MongoDB is properly configured:
# Import the public key used by the package management system
wget -qO - https://www.mongodb.org/static/pgp/server-6.0.asc | sudo apt-key add -
# Create a list file for MongoDB
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/6.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-6.0.list
# Reload local package database
sudo apt-get update
# Install MongoDB packages
sudo apt-get install -y mongodb-org
# Start MongoDB
sudo systemctl start mongod
# Enable MongoDB to start on boot
sudo systemctl enable mongod
# Check MongoDB status
sudo systemctl status mongod
# Connect to MongoDB
mongo
# Switch to admin database
use admin
# Create admin user
db.createUser({
user: "adminUser",
pwd: "YourDBPassword",
roles: [ { role: "userAdminAnyDatabase", db: "admin" }, "readWriteAnyDatabase" ]
})
# Create application database
use ClientOperation
# Create application user (optional)
db.createUser({
user: "appUser",
pwd: "YourAppPassword",
roles: [ { role: "readWrite", db: "ClientOperation" } ]
})
# Exit MongoDB shell
exit
Create Apache Virtual Host Configuration:
File Path: /etc/apache2/sites-available/clientoperation.2ndsource.xyz.conf
sudo nano /etc/apache2/sites-available/clientoperation.2ndsource.xyz.conf
Configuration Content:
# HTTP to HTTPS Redirect
<VirtualHost *:80>
ServerName clientoperation.2ndsource.xyz
Redirect permanent / https://clientoperation.2ndsource.xyz/
RewriteEngine on
RewriteCond %{SERVER_NAME} =clientoperation.2ndsource.xyz
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>
# HTTPS Virtual Host
<VirtualHost *:443>
ServerName clientoperation.2ndsource.xyz
ServerAdmin webmaster@localhost
# SSL Configuration
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/clientoperation.2ndsource.xyz/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/clientoperation.2ndsource.xyz/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
# Log Configuration
ErrorLog ${APACHE_LOG_DIR}/clientoperation.2ndsource.xyz-error.log
CustomLog ${APACHE_LOG_DIR}/clientoperation.2ndsource.xyz-access.log combined
# Document Root for React Build
DocumentRoot /var/www/html/clientoperation
# Static File Serving
<Directory "/var/www/html/clientoperation">
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
# React Router SPA Configuration
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</Directory>
# MIME Type Configuration
<Files "*.js">
Header set Content-Type "application/javascript"
</Files>
<Files "*.css">
Header set Content-Type "text/css"
</Files>
# API Reverse Proxy
ProxyPass /api/ http://localhost:5000/api/
ProxyPassReverse /api/ http://localhost:5000/api/
</VirtualHost>
# Enable URL rewriting for SPA
sudo a2enmod rewrite
# Enable HTTP headers modification
sudo a2enmod headers
# Enable SSL support
sudo a2enmod ssl
# Enable reverse proxy functionality
sudo a2enmod proxy
sudo a2enmod proxy_http
Expected Output:
Enabling module rewrite.
Enabling module headers.
Enabling module ssl.
Enabling module proxy.
Enabling module proxy_http.
To activate the new configuration, you need to run:
systemctl reload apache2
# Create main web directory
sudo mkdir -p /var/www/html/clientoperation
# Set proper ownership for Apache
sudo chown -R www-data:www-data /var/www/html/clientoperation
# Set appropriate permissions
sudo chmod -R 755 /var/www/html/clientoperation
Directory Structure:
/var/www/html/clientoperation/
βββ index.html
βββ static/
β βββ css/
β βββ js/
β βββ media/
βββ manifest.json
βββ favicon.ico
# Install Node.js 18.x
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt-get install -y nodejs
# Verify installation
node --version
npm --version
# Install PM2 globally for process management
sudo npm install -g pm2
Expected Output:
$ node --version
v18.17.0
$ npm --version
9.6.7
$ pm2 --version
5.3.0
Base Path: /home/tsstech/nodeapp/clientoperation/frontend
# Navigate to frontend directory
cd /home/tsstech/nodeapp/clientoperation/frontend
# Create production environment configuration
cat > .env.production << EOF
REACT_APP_API_URL=https://clientoperation.2ndsource.xyz
REACT_APP_ENV=production
GENERATE_SOURCEMAP=false
EOF
# Install dependencies
npm install
# Create production build
npm run build
Build Output Example:
Creating an optimized production build...
Compiled successfully.
File sizes after gzip:
46.61 KB build/static/js/2.8e5b5f6d.chunk.js
1.4 KB build/static/js/main.2f4b5c8a.chunk.js
1.17 KB build/static/js/runtime-main.e8e9c4f6.js
312 B build/static/css/main.a617e044.chunk.css
The build folder is ready to be deployed.
# Copy build files to web directory
sudo cp -r build/* /var/www/html/clientoperation/
# Set proper ownership
sudo chown -R www-data:www-data /var/www/html/clientoperation/
# Verify deployment
ls -la /var/www/html/clientoperation/
Base Path: /home/tsstech/nodeapp/clientoperation/backend
# Navigate to backend directory
cd /home/tsstech/nodeapp/clientoperation/backend
# Create production environment file
cat > .env << EOF
PORT=5000
NODE_ENV=production
FRONTEND_URL=https://clientoperation.2ndsource.xyz
#Add your database and other configurations:
#MONGO_URI=mongodb://localhost:27017/clientoperation
MONGO_URI=mongodb://adminUser:YourDBPassword@localhost:27017/ClientOperation?authSource=admin
JWT_SECRET=your-super-secret-jwt-key
EOF
# Install production dependencies
npm install --production
import express from 'express';
import connectDB from './config/db.js';
import cors from 'cors';
import dotenv from 'dotenv';
dotenv.config();
const app = express();
connectDB();
// Allowed origins for CORS
const allowedOrigins = [
'https://clientoperation.2ndsource.xyz', // Production domain
'http://localhost:3000', // React dev server
'http://localhost:3001' // Alternate dev port
];
// Configure CORS middleware
app.use(cors({
origin: (origin, callback) => {
if (!origin || allowedOrigins.includes(origin)) {
callback(null, true);
} else {
console.log('CORS blocked origin:', origin);
callback(new Error('Not allowed by CORS'));
}
},
credentials: true,
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization', 'Cookie']
}));
// Health check route
app.get('/api/health', (req, res) => {
res.json({
status: 'OK',
message: 'Backend server is running',
timestamp: new Date().toISOString(),
});
});
// Error handling middleware
app.use((err, req, res, next) => {
console.error('Error:', err.message);
res.status(500).json({
error: 'Internal Server Error',
message: process.env.NODE_ENV === 'development' ? err.message : 'Something went wrong',
});
});
// Start server
const PORT = process.env.PORT || 5001;
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
console.log(`Environment: ${process.env.NODE_ENV || 'development'}`);
console.log('Allowed Origins:', allowedOrigins);
});
// config/db.js
import mongoose from 'mongoose';
import dotenv from 'dotenv';
dotenv.config();
const connectDB = async () => {
try {
const conn = await mongoose.connect(process.env.MONGO_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
console.log(`MongoDB Connected: ${conn.connection.host}`);
} catch (error) {
console.error(`MongoDB connection failed: ${error.message}`);
process.exit(1);
}
};
export default connectDB;
Create PM2 Ecosystem File:
# Create PM2 configuration
cat > ecosystem.config.cjs << EOF
module.exports = {
apps: [{
name: 'clientoperation-backend',
script: './server.js',
instances: 1,
exec_mode: 'fork', //For mongoDB atlas use 'cluster'
env: {
NODE_ENV: 'production',
PORT: 5001,
},
env_production: {
NODE_ENV: 'production',
MONGO_URI: process.env.MONGO_URI, // Uses .env file
JWT_SECRET: process.env.JWT_SECRET,
},
error_file: './logs/err.log',
out_file: './logs/out.log',
log_file: './logs/combined.log',
time: true
}]
};
EOF
# Create logs directory
mkdir -p logs
# Testing purpose
cd /home/tsstech/nodeapp/clientoperation/backend
node server.js
If shown a message like MongoDB connected:
then everything is okay.
curl http://localhost:5000/api/health
Finally stop server then run below:
# Start application with PM2
pm2 start ecosystem.config.js
# Save PM2 configuration
pm2 save
# Setup PM2 to start on system boot
pm2 startup
PM2 Status Output:
βββββββ¬βββββββββββββββββββββββββββ¬ββββββββββββββ¬βββββββ¬βββββββββ¬βββββββββββ¬βββββββββ¬βββββββ¬ββββββββββββ¬βββββββββββ¬βββββββββββ¬βββββββββββ¬βββββββββββ
β id β name β namespace β ver β mode β pid β uptime β βΊ β status β cpu β mem β user β watching β
βββββββΌβββββββββββββββββββββββββββΌββββββββββββββΌβββββββΌβββββββββΌβββββββββββΌβββββββββΌβββββββΌββββββββββββΌβββββββββββΌβββββββββββΌβββββββββββΌβββββββββββ€
β 0 β clientoperation-backend β default β 1.0 β clusterβ 12345 β 5m β 0 β online β 0% β 45.2mb β tsstech β disabled β
βββββββ΄βββββββββββββββββββββββββββ΄ββββββββββββββ΄βββββββ΄βββββββββ΄βββββββββββ΄βββββββββ΄βββββββ΄ββββββββββββ΄βββββββββββ΄βββββββββββ΄βββββββββββ΄βββββββββββ
# Enable the site
sudo a2ensite clientoperation.2ndsource.xyz.conf
# Test Apache configuration
sudo apache2ctl configtest
# Restart Apache to apply changes
sudo systemctl restart apache2
# Enable Apache to start on boot
sudo systemctl enable apache2
Configuration Test Output:
Syntax OK
# Test backend directly
curl http://localhost:5000/api/health
# Expected response
{"status":"OK","timestamp":"2024-01-15T10:30:00.000Z"}
# Test HTTPS redirect
curl -I http://clientoperation.2ndsource.xyz
# Expected response
HTTP/1.1 301 Moved Permanently
Location: https://clientoperation.2ndsource.xyz/
# Test HTTPS access
curl -I https://clientoperation.2ndsource.xyz
# Expected response
HTTP/1.1 200 OK
Content-Type: text/html
# Check Apache status
sudo systemctl status apache2
# Check PM2 status
pm2 status
# Check application logs
pm2 logs clientoperation-backend --lines 50
# Navigate to frontend directory
cd /home/tsstech/nodeapp/clientoperation/frontend
# Pull latest changes (if using Git)
git pull origin main
# Install new dependencies (if any)
npm install
# Create new build
npm run build
# Deploy updated build
sudo cp -r build/* /var/www/html/clientoperation/
sudo chown -R www-data:www-data /var/www/html/clientoperation/
# Clear browser cache or add cache-busting
sudo systemctl reload apache2
# Navigate to backend directory
cd /home/tsstech/nodeapp/clientoperation/backend
# Pull latest changes
git pull origin main
# Install new dependencies
npm install --production
# Restart application
pm2 restart clientoperation-backend
# Monitor restart
pm2 logs clientoperation-backend --lines 20
# Test certificate renewal (dry run)
sudo certbot renew --dry-run
# Renew certificates
sudo certbot renew
# Reload Apache after renewal
sudo systemctl reload apache2
Problem: apache2ctl configtest
fails
# Check syntax errors
sudo apache2ctl configtest
# View detailed error logs
sudo tail -f /var/log/apache2/error.log
Solution: Review configuration file for typos or missing modules.
Problem: SSL certificate not found
# Check certificate files exist
ls -la /etc/letsencrypt/live/clientoperation.2ndsource.xyz/
# Test certificate validity
openssl x509 -in /etc/letsencrypt/live/clientoperation.2ndsource.xyz/cert.pem -text -noout
Problem: API requests failing
# Check if backend is running
pm2 status
# Check backend logs
pm2 logs clientoperation-backend
# Test backend directly
curl -v http://localhost:5000/api/health
# Check port binding
netstat -tlnp | grep :5000
Problem: React app shows blank page
# Check if files exist
ls -la /var/www/html/clientoperation/
# Check Apache error logs
sudo tail -f /var/log/apache2/clientoperation.2ndsource.xyz-error.log
# Check browser console for JavaScript errors
# Verify MIME types are set correctly
# Apache Logs
/var/log/apache2/clientoperation.2ndsource.xyz-error.log
/var/log/apache2/clientoperation.2ndsource.xyz-access.log
# PM2 Logs
/home/tsstech/nodeapp/clientoperation/backend/logs/err.log
/home/tsstech/nodeapp/clientoperation/backend/logs/out.log
/home/tsstech/nodeapp/clientoperation/backend/logs/combined.log
# System Logs
/var/log/syslog
/var/log/apache2/error.log
# Monitor system resources
htop
# Monitor Apache processes
ps aux | grep apache
# Monitor Node.js process
pm2 monit
# Check disk usage
df -h
du -sh /var/www/html/clientoperation/
# Allow HTTP and HTTPS
sudo ufw allow 80
sudo ufw allow 443
# Block direct access to Node.js port
sudo ufw deny 5000
# Ensure proper ownership
sudo chown -R www-data:www-data /var/www/html/clientoperation/
sudo chmod -R 755 /var/www/html/clientoperation/
- Never commit
.env
files to version control - Use strong, unique secrets for JWT and database connections
- Regularly rotate API keys and passwords
# Restart all services
sudo systemctl restart apache2
pm2 restart all
# View all logs
sudo tail -f /var/log/apache2/*error.log
pm2 logs
# Update and deploy
cd /path/to/frontend && npm run build && sudo cp -r build/* /var/www/html/clientoperation/
cd /path/to/backend && pm2 restart clientoperation-backend
# Check service status
sudo systemctl status apache2
pm2 status
curl -I https://clientoperation.2ndsource.xyz
/var/www/html/clientoperation/
βββ index.html
βββ static/
β βββ css/
β βββ js/
β βββ media/
βββ manifest.json
βββ favicon.ico
-
Restart Apache:
sudo systemctl restart apache2
-
Restart MongoDB:
sudo systemctl restart mongod
-
Restart Node.js Applications:
pm2 restart clientoperation-backend pm2 restart clientoperation-frontend
-
Check Service Status:
sudo systemctl status apache2 sudo systemctl status mongod pm2 status
-
Test Apache Configuration:
sudo apachectl configtest
sudo ufw enable
sudo ufw allow ssh
sudo ufw allow 80
sudo ufw allow 443
sudo apt update
sudo apt upgrade
- Ensure MongoDB is only listening on localhost (default)
- Use strong passwords for all MongoDB users
- Regularly review database users and permissions
- Certificates will automatically renew via Certbot
- Test renewal process:
sudo certbot renew --dry-run
- Verify backup integrity periodically:
# Restore to a temporary database for testing mongorestore --authenticationDatabase admin -u adminUser -p SecurePassword123 --db test_restore ~/mongodb-backups/[BACKUP_DATE]/clientoperationdb
- Never expose MongoDB port (27017) to the internet
- Store sensitive credentials in environment variables, not in code
- Keep all software updated (Node.js, MongoDB, system packages)
- Consider implementing rate limiting for API endpoints
- Implement proper authentication and authorization in your application
This documentation was generated on May 28, 2025. Some commands or configurations may need updates based on newer software versions.
cd ~/nodeapp/clientoperation/frontend
pm2 start npm --name clientoperation-frontend -- run start
Expected Output:
[PM2] Starting /usr/bin/npm in fork_mode (1 instance)
[PM2] Done.
βββββββ¬ββββββββββββββββββββββββββββ¬βββββββββ¬βββββββ¬ββββββ¬βββββββββ¬βββββββββ
β id β name β mode β βΊ β status β cpu β memory β
βββββββΌββββββββββββββββββββββββββββΌβββββββββΌβββββββΌβββββββββΌβββββββΌβββββββββ€
β 1 β clientoperation-frontend β fork β 0 β online β 0% β 80.0mb β
βββββββ΄ββββββββββββββββββββββββββββ΄βββββββββ΄βββββββ΄βββββββββ΄βββββββ΄βββββββββ
pm2 save
Expected Output:
[PM2] Saving current process list...
[PM2] Successfully saved in /home/deploy/.pm2/dump.pm2
pm2 startup systemd
Then, run the command it suggests. Example:
sudo env PATH=$PATH:/home/deploy/.nvm/versions/node/v18.16.0/bin pm2 startup systemd -u deploy --hp /home/deploy
Expected Output:
[PM2] Init system already enabled
[PM2] To setup the startup script, copy/paste the following:
sudo env PATH=... pm2 startup systemd -u deploy --hp /home/deploy
pm2 restart clientoperation-frontend
Expected Output:
[PM2] Applying action restartProcessId on app [clientoperation-frontend](id:1)
β
[PM2] Process successfully restarted
pm2 status
Expected Output:
βββββββ¬ββββββββββββββββββββββββββββ¬βββββββββ¬βββββββ¬βββββββββ¬βββββββ¬βββββββββ
β id β name β mode β βΊ β status β cpu β memory β
βββββββΌββββββββββββββββββββββββββββΌβββββββββΌβββββββΌβββββββββΌβββββββΌβββββββββ€
β 0 β clientoperation-backend β fork β 0 β online β 0% β 102mb β
β 1 β clientoperation-frontend β fork β 0 β online β 0% β 80mb β
βββββββ΄ββββββββββββββββββββββββββββ΄βββββββββ΄βββββββ΄βββββββββ΄βββββββ΄βββββββββ
This documentation provides a complete reference for deploying and maintaining a React/Node.js application with Apache SSL configuration. Keep this guide updated as your infrastructure evolves.
This deployment guide is provided as-is for educational and operational purposes.