⚠️ Security Notice: This deployment uses private CA certificates for enhanced security in MongoDB configuration. The deployment is secured through strong authentication, custom port usage, and firewall rules. Always use strong passwords and restrict network access for production deployments.
This repository contains a comprehensive set of scripts for deploying, securing, and monitoring MongoDB instances. The scripts are designed to be modular, allowing you to set up MongoDB with proper security, TLS encryption, and monitoring capabilities.
- Overview
- Prerequisites
- Initial Setup
- Step 1: Bootstrap MongoDB
- Step 2: Provision TLS Certificates
- Step 3: Set Up Monitoring
- Managing Replica Sets
- Connection Information
- Password Rotation
- Backup and Restore
- Troubleshooting
- Scaling
- Reset and Cleanup
This deployment solution consists of several scripts that handle different aspects of MongoDB deployment:
- bootstrap.sh: Sets up MongoDB with proper configuration, security, and backup capabilities
- provision_ssl.sh: Provisions SSL certificates and configures MongoDB to use TLS
- monitoring.sh: Sets up email alerts and a monitoring endpoint
- Utility scripts: Additional scripts for managing replica sets, backups, and more
Before you begin, ensure you have:
- A Ubuntu server (preferably Ubuntu 20.04 LTS or newer)
- Root or sudo access to the server
- A domain name pointing to your server's IP address (for SSL certificates)
- Open ports:
- 22 (SSH)
- 80 (HTTP)
- 443 (HTTPS)
- The port you specify for MongoDB in config.json (e.g., 27017, 2610, etc.)
- AWS account (if you plan to use S3 for backups)
-
Clone this repository to your server:
git clone https://github.com/cheatcode/mongodb.git cd mongodb
-
Make the setup script executable:
chmod +x setup.sh
-
Run the setup script to make all scripts executable:
./setup.sh
Note: The setup script will also install the Micro text editor, which provides a user-friendly interface for editing files via the command line. After installation, you can edit files using:
micro filename
-
Create and configure the config.json file:
Create a file named
config.json
in the repository root with the following content:{ "db_username": "admin", "db_password": "your_secure_password", "aws_bucket": "your-s3-bucket-name", "aws_region": "us-east-1", "aws_access_key": "YOUR_AWS_ACCESS_KEY", "aws_secret_key": "YOUR_AWS_SECRET_KEY", "alert_email": "[email protected]", "smtp_server": "smtp.example.com", "smtp_port": "587", "smtp_user": "your-smtp-username", "smtp_pass": "your-smtp-password", "monitor_token": "your_secure_monitor_token", "replica_set_key": "your_replica_set_key", "mongo_port": "27017", "domain_name": "your.domain.com" }
Replace the placeholder values with your actual configuration:
db_username
anddb_password
: Credentials for the MongoDB admin useraws_*
parameters: Your AWS credentials and S3 bucket information for backupsalert_email
: Email address to receive monitoring alertssmtp_*
parameters: SMTP server details for sending alert emailsmonitor_token
: A secure token for accessing the monitoring endpointreplica_set_key
: A secure key for MongoDB replica set authenticationmongo_port
: The port MongoDB will listen on (e.g., 27017, 2610, etc.)
To generate a secure
replica_set_key
, you can use:openssl rand -base64 32
For
monitor_token
, you can use:openssl rand -hex 16
The bootstrap script installs MongoDB, configures it with proper security settings, and sets up backup capabilities.
-
Run the bootstrap script:
./bootstrap.sh primary rs0 your-domain.com
Parameters:
primary
: The role of this node (can beprimary
,secondary
, orarbiter
)rs0
: The name of the replica setyour-domain.com
: Your server's domain name
-
What the bootstrap script does:
- Installs MongoDB 8.0
- Creates a keyfile for replica set authentication
- Configures MongoDB to use the port specified in config.json
- Sets up user authentication
- Configures log rotation
- Sets up AWS CLI and S3 backup script (if you're the primary)
- Configures firewall rules with UFW
-
Verify MongoDB is running:
sudo systemctl status mongod
You should see that MongoDB is active and running.
The provision_ssl script configures MongoDB to use pre-generated private CA certificates for enhanced security instead of Let's Encrypt certificates. This approach provides better security and easier maintenance for MongoDB deployments.
-
Place your private CA certificates in the required locations:
sudo mkdir -p /etc/ssl/mongodb sudo cp /path/to/your/certificate.pem /etc/ssl/mongodb/certificate.pem sudo cp /path/to/your/ca_certificate.pem /etc/ssl/mongodb/certificate_authority.pem sudo chmod 600 /etc/ssl/mongodb/certificate.pem sudo chmod 600 /etc/ssl/mongodb/certificate_authority.pem sudo chown mongodb:mongodb /etc/ssl/mongodb/certificate.pem sudo chown mongodb:mongodb /etc/ssl/mongodb/certificate_authority.pem
Replace
/path/to/your/certificate.pem
and/path/to/your/ca_certificate.pem
with the actual paths to your certificate files. -
Generate a client certificate (required for connecting to MongoDB):
You'll need to create a client certificate signed by the same CA that signed your server certificate. If you're using the certificate generation script from the repository, you can add a function to generate client certificates:
const generate_client_certificate = (client_name) => { const ca_key = 'ca.key'; const ca_crt = 'ca.crt'; const client_key = `${client_name}.key`; const client_csr = `${client_name}.csr`; const client_crt = `${client_name}.crt`; const client_pem = `${client_name}.pem`; // Generate client key execSync(`openssl genrsa -out ${client_key} 2048`); // Generate CSR execSync(`openssl req -new -key ${client_key} -out ${client_csr} -subj "/CN=${client_name}"`); // Sign with CA execSync(`openssl x509 -req -in ${client_csr} -CA ${ca_crt} -CAkey ${ca_key} -CAcreateserial -out ${client_crt} -days 7300 -sha256`); // Create combined PEM file const crtContent = fs.readFileSync(client_crt); const keyContent = fs.readFileSync(client_key); fs.writeFileSync(client_pem, Buffer.concat([crtContent, keyContent])); return client_pem; };
-
Run the TLS provisioning script:
./provision_ssl.sh
-
What the provision_ssl script does:
- Checks for the existence of the certificate files
- Updates the MongoDB configuration to use TLS with proper settings
- Configures MongoDB to allow connections from outside the server (bindIp: 0.0.0.0)
- Adds the replica set configuration
- Initializes the replica set using the domain name from config.json
- Restarts MongoDB with the new TLS configuration
-
Connecting to MongoDB with client certificates:
After running provision_ssl.sh, you must use client certificates to connect:
mongosh --host your-domain.com --port $MONGO_PORT --tls --tlsCAFile /etc/ssl/mongodb/certificate_authority.pem --tlsCertificateKeyFile /etc/ssl/mongodb/client.pem -u admin -p your_password --authenticationDatabase admin
Ensure the client certificate exists at
/etc/ssl/mongodb/client.pem
.For GUI tools like Studio 3T:
You'll need to configure the connection to use:
- TLS/SSL enabled
- CA file:
/etc/ssl/mongodb/certificate_authority.pem
- Client certificate: Your generated client.pem file
- Authentication: Username/Password with admin database
For application connections:
In your application code, you'll need to specify both the CA file and client certificate:
mongodb://admin:[email protected]:27017/?tls=true&tlsCAFile=/etc/ssl/mongodb/certificate_authority.pem&tlsCertificateKeyFile=/etc/ssl/mongodb/client.pem&authSource=admin
-
Verify TLS is working:
The script will attempt to verify that MongoDB is running with TLS. You can also check manually, but remember you'll need to use your client certificate:
mongosh --host your-domain.com --port $MONGO_PORT --tls --tlsCAFile /etc/ssl/mongodb/certificate_authority.pem --tlsCertificateKeyFile /etc/ssl/mongodb/client.pem -u admin -p your_password --authenticationDatabase admin --eval "db.adminCommand({ getParameter: 1, tlsMode: 1 })"
Replace
$MONGO_PORT
with the port you specified in config.json.You should see output indicating that
tlsMode
is set torequireTLS
.
The monitoring script sets up email alerts and a monitoring endpoint for your MongoDB instance.
-
Run the monitoring script:
./monitoring.sh your-domain.com
Parameter:
your-domain.com
: Your server's domain name
-
What the monitoring script does:
- Installs required dependencies (msmtp, nginx, fcgiwrap)
- Configures email alerts via SMTP
- Sets up health checks that run every 30 seconds
- Creates a monitoring endpoint accessible via HTTP
- Configures nginx to serve the monitoring endpoint
- Sends alerts when MongoDB goes down AND when it comes back up
-
Access the monitoring endpoint:
You can access the monitoring endpoint via HTTP at:
http://your-domain.com/monitor?token=your_secure_monitor_token
Replace
your_secure_monitor_token
with the value you set inconfig.json
.Note: The monitoring endpoint is only available over HTTP, not HTTPS, as it uses a simple configuration that doesn't require SSL certificates.
-
Email alerts:
The monitoring system will:
- Check MongoDB status every 30 seconds
- Send an alert email when MongoDB goes down
- Send another alert email when MongoDB comes back up
You can test this by temporarily stopping and starting MongoDB:
# Stop MongoDB to trigger a DOWN alert sudo systemctl stop mongod # Wait a minute, then start MongoDB to trigger an UP alert sudo systemctl start mongod
This deployment uses x509 certificate authentication for replica set members, providing enhanced security compared to the traditional keyFile authentication method.
-
Set up secondary nodes:
On each secondary node, follow the same steps as above:
# On secondary node ./bootstrap.sh secondary rs0 secondary-node-domain.com # Place your private CA certificates in the required locations sudo mkdir -p /etc/ssl/mongodb sudo cp /path/to/your/certificate.pem /etc/ssl/mongodb/certificate.pem sudo cp /path/to/your/ca_certificate.pem /etc/ssl/mongodb/certificate_authority.pem sudo cp /path/to/your/replicas.pem /etc/ssl/mongodb/replicas.pem sudo chmod 600 /etc/ssl/mongodb/certificate.pem sudo chmod 600 /etc/ssl/mongodb/certificate_authority.pem sudo chmod 600 /etc/ssl/mongodb/replicas.pem sudo chown mongodb:mongodb /etc/ssl/mongodb/certificate.pem sudo chown mongodb:mongodb /etc/ssl/mongodb/certificate_authority.pem sudo chown mongodb:mongodb /etc/ssl/mongodb/replicas.pem # Configure TLS and set up monitoring ./provision_ssl.sh ./monitoring.sh secondary-node-domain.com
The
provision_ssl.sh
script will automatically get the domain name from your config.json file and use it to configure the replica set.Note about x509 Authentication: This deployment uses x509 certificate authentication for replica set members instead of the traditional keyFile method. The x509 certificates provide stronger security and are more flexible for certificate rotation.
The replica certificate should be placed at
/etc/ssl/mongodb/replicas.pem
on each node. This file must contain both the certificate and its private key in PEM format, similar to the server certificate. The certificate should be signed by the same CA as the server certificate.Example of generating a replica certificate:
# Generate private key openssl genrsa -out replicas.key 2048 # Generate CSR (Certificate Signing Request) openssl req -new -key replicas.key -out replicas.csr -subj "/CN=mongodb-replicas" # Sign with your CA openssl x509 -req -in replicas.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out replicas.crt -days 7300 -sha256 # Combine certificate and key into a single PEM file cat replicas.crt replicas.key > replicas.pem
-
Add secondary nodes to the replica set:
From the primary node, use the replica_sets.sh utility script:
./utils/replica_sets.sh add secondary-node-domain.com:$MONGO_PORT
Replace
$MONGO_PORT
with the port you specified in config.json. -
Remove nodes from the replica set (if needed):
./utils/replica_sets.sh remove secondary-node-domain.com:$MONGO_PORT
Replace
$MONGO_PORT
with the port you specified in config.json.
After setting up MongoDB, you can get the connection information in JSON format:
./connection_info.sh
This will output a JSON object containing:
- Username and password
- List of all hosts in the replica set with their roles
- SSL status
- Connection string for use in applications
Example output:
{
"username": "admin",
"password": "your_secure_password",
"hosts": [
{ "hostname": "mdb1.example.com", "port": "27017", "state": "primary" },
{ "hostname": "mdb2.example.com", "port": "27017", "state": "secondary" }
],
"tls_enabled": true,
"replica_set": "rs0",
"connection_string": "mongodb://admin:[email protected]:27017,mdb2.example.com:27017/?tls=true&tlsCAFile=/etc/ssl/mongodb/certificate_authority.pem&tlsCertificateKeyFile=/etc/ssl/mongodb/client.pem&authSource=admin&replicaSet=rs0"
}
For security best practices, you should regularly rotate the MongoDB admin password. This needs to be done on the primary node and will automatically propagate to all secondary nodes in the replica set.
-
Connect to the primary node:
mongosh --host your-domain.com --port $MONGO_PORT --tls --tlsCAFile /etc/ssl/mongodb/certificate_authority.pem --tlsCertificateKeyFile /etc/ssl/mongodb/client.pem -u admin -p current_password --authenticationDatabase admin
Replace
$MONGO_PORT
with the port you specified in config.json andcurrent_password
with your current password. -
Change the admin user's password:
db.getSiblingDB("admin").changeUserPassword("admin", "new_secure_password")
Replace
new_secure_password
with your new secure password. -
Update the config.json file:
After changing the password, update the
db_password
field in your config.json file:micro config.json
This ensures that all scripts will continue to work with the new password.
-
Verify the new password:
mongosh --host your-domain.com --port $MONGO_PORT --tls --tlsCAFile /etc/ssl/mongodb/certificate_authority.pem --tlsCertificateKeyFile /etc/ssl/mongodb/client.pem -u admin -p new_secure_password --authenticationDatabase admin --eval "db.adminCommand('ping')"
You should see a successful response with
{ ok: 1 }
. -
Password Rotation Schedule:
Consider implementing a regular password rotation schedule (e.g., every 90 days) as part of your security policy. You can use system cron jobs to remind you when it's time to rotate passwords.
The bootstrap script sets up automatic backups to S3 for the primary node. You can also manage backups manually.
-
List available backups:
./utils/list_backups.sh
-
Create a manual backup:
./utils/create_backup.sh [prefix]
The optional
prefix
parameter allows you to add a custom prefix to the backup filename (default is "manual").Example:
./utils/create_backup.sh pre-update
This will create a backup with a filename like
pre-update-20250504-193245.gz
. -
Restore from a backup:
./utils/restore_backup.sh backup-filename.gz
Replace
backup-filename.gz
with the actual backup file name from the list.
If you encounter issues during the setup process, here are some common troubleshooting steps:
-
Check MongoDB logs:
sudo journalctl -u mongod --no-pager -n 100
-
Verify MongoDB is running:
sudo systemctl status mongod
-
Check SSL certificate files:
ls -la /etc/ssl/mongodb/
-
Test MongoDB connection with TLS:
mongosh --host your-domain.com --port $MONGO_PORT --tls --tlsCAFile /etc/ssl/mongodb/certificate_authority.pem --tlsCertificateKeyFile /etc/ssl/mongodb/client.pem -u admin -p your_password --authenticationDatabase admin
Replace
$MONGO_PORT
with the port you specified in config.json andyour-domain.com
with your actual domain name. -
Check nginx configuration:
sudo nginx -t sudo systemctl status nginx
-
Verify monitoring endpoint:
curl -v "http://your-domain.com/monitor?token=your_secure_monitor_token"
Scaling is managed directly via your host. Before scaling, ALWAYS make sure to take a manual backup and confirm it:
./utils/create_backup.sh
This will take a manual snapshot and upload it to S3. You can pass an additional prefix like this: ./utils/create_backup.sh <prefix>
where <prefix>
is something like before_scale
.
After this, just use the manual scaling GUI on your host. If need be, once the server restarts, you can do a manual restore from the backup you took with:
./utils/restore_backup.sh <timestamp>
You can get the specific backup timestamp by running:
./utils/list_backups.sh
If you need to reset your server and remove all installed components, you can use the reset script:
./utils/reset.sh
WARNING: This will permanently delete MongoDB, nginx, certbot, AWS CLI, fcgiwrap, and all configurations. Use with caution!
This deployment solution provides a secure, monitored MongoDB installation with TLS encryption and automatic backups. If you have any questions or issues, please open an issue on the GitHub repository.