Self-managed MongoDB Replica Set on Ubuntu

in HiveDevsyesterday

0ac21d10-1bfc-400b-a802-6af2668d9a44_original.png

MongoDB is a popular NoSQL database, widely used for its flexibility and scalability. This guide demonstrates how to set up a 3-node MongoDB replica set with a Primary-Secondary-Arbiter (PSA) configuration on Ubuntu 24.04 LTS, securing node communication with Let's Encrypt TLS certificates.


Prerequisites

  • Three Ubuntu 24.04 LTS servers, each with a unique hostname:

    • mongo-01.db.domain.com
    • mongo-02.db.domain.com
    • mongo-03.db.domain.com
  • All hostnames must resolve correctly via DNS (A and/or AAAA records) to their respective servers for proper replica set functionality.


1. Initial Server Setup

Log into each server and update packages:

sudo apt update && sudo apt dist-upgrade -y

Create a non-root user with sudo privileges:

adduser mongoadm
adduser mongoadm sudo

2. Install MongoDB 8.0

On each server, perform the following:

  1. Install prerequisites:
sudo apt-get install gnupg curl
  1. Import MongoDB public GPG key and add the official MongoDB repository:
curl -fsSL https://www.mongodb.org/static/pgp/server-8.0.asc | sudo gpg -o /usr/share/keyrings/mongodb-server-8.0.gpg --dearmor

echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] https://repo.mongodb.org/apt/ubuntu noble/mongodb-org/8.2 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-8.2.list
  1. Update and install MongoDB:
sudo apt-get update && sudo apt-get install -y mongodb-org

3. Setup Key File for Internal Authentication

Generate a key file for encrypted node-to-node communication:

sudo mkdir /etc/mongodb
sudo openssl rand -base64 756 | sudo tee /etc/mongodb/mongo.key
sudo chmod 600 /etc/mongodb/mongo.key
sudo chown mongodb:mongodb /etc/mongodb/mongo.key

Important: Copy this key file identically to all three servers with identical permissions.


4. Install and Configure Let's Encrypt Certbot TLS

Install Certbot and your required DNS plugin to obtain certificates for each node's hostname.

Create a renewal hook script at /etc/letsencrypt/renewal-hooks/deploy/reload-mongodb.sh:

sudo tee /etc/letsencrypt/renewal-hooks/deploy/reload-mongodb.sh > /dev/null <<'EOF'
#!/bin/bash

cat /etc/letsencrypt/live/YOUR_HOST_NAME/fullchain.pem \
    /etc/letsencrypt/live/YOUR_HOST_NAME/privkey.pem \
    > /etc/mongodb/mongodb.pem

chown mongodb:mongodb /etc/mongodb/mongodb.pem
chmod 600 /etc/mongodb/mongodb.pem

# Reload TLS certs in running mongod instances without restart
ps aux | grep mongod | grep -v grep | awk '{print $2}' | xargs -I{} kill -SIGUSR2 {}
EOF

sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-mongodb.sh

Replace YOUR_HOST_NAME with each server's hostname.

We will execute /etc/letsencrypt/renewal-hooks/deploy/reload-mongodb.sh only once on each servers to generate /etc/mongodb/mongodb.pem


5. MongoDB Configuration

Replace the default config at /etc/mongod.conf on all nodes (do not start services yet):

storage:
  dbPath: /var/lib/mongodb

systemLog:
  destination: file
  logAppend: true
  path: /var/log/mongodb/mongod.log

net:
  port: 27017
  bindIp: localhost,mongo-01.db.domain.com
  ipv6: true
  tls:
    mode: requireTLS
    certificateKeyFile: /etc/mongodb/mongodb.pem
    allowConnectionsWithoutCertificates: true
    allowInvalidCertificates: false

processManagement:
  timeZoneInfo: /usr/share/zoneinfo

security:
  authorization: enabled
  clusterAuthMode: keyFile
  keyFile: /etc/mongodb/mongo.key
  javascriptEnabled: false

replication:
  replSetName: rs0

setParameter:
  tlsUseSystemCA: true

Note: Update bindIp with each node's respective hostname.


6. Initialize the Replica Set (First Node Only)

On the first node, temporarily comment out the security and replication sections in /etc/mongod.conf, then start the service:

sudo systemctl start mongod.service

Connect to the first node:

mongosh --host mongo-01.db.domain.com --tls

Create the root admin user:

use admin

db.createUser({
  user: "admin",
  pwd: "SafeASCIIpassword123!",
  roles: ["root"]
})

Exit the shell and uncomment the security and replication sections. Restart MongoDB:

sudo systemctl restart mongod.service

7. Start Services on Remaining Nodes

Start MongoDB on nodes 2 and 3:

sudo systemctl start mongod.service

Verify all services are active:

sudo systemctl status mongod.service

8. Configure the Replica Set

Log back into the first node as the admin user:

mongosh --host mongo-01.db.domain.com --tls --authenticationDatabase admin -u admin -p

Initialize the replica set:

rs.initiate({
  _id: "rs0",
  members: [
    { _id: 0, host: "mongo-01.db.domain.com:27017" },
    { _id: 1, host: "mongo-02.db.domain.com:27017" },
    { _id: 2, host: "mongo-03.db.domain.com:27017" }
  ]
})

You should receive { ok: 1 } upon success. After a few seconds, one node will be elected as primary.


9. Configure MongoDB Atlas-Like Connection URL (Optional)

To enable connection strings like mongodb+srv://username:[email protected]/database, configure DNS records:

  1. TXT Record on mongo.db.domain.com:

    • Content: authSource=admin&replicaSet=rs0
  2. SRV Records on _mongodb._tcp.mongo.db.domain.com:

PriorityWeightPortTarget
0027017mongo-01.db.domain.com
0027017mongo-02.db.domain.com
0027017mongo-03.db.domain.com

Conclusion

Your MongoDB PSA replica set is now fully operational with TLS encryption and automatic certificate renewal!

Note: The primary purpose of this post is for my future reference. AI was used to format the post and generate the thumbnail.