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.
Three Ubuntu 24.04 LTS servers, each with a unique hostname:
mongo-01.db.domain.commongo-02.db.domain.commongo-03.db.domain.comAll hostnames must resolve correctly via DNS (A and/or AAAA records) to their respective servers for proper replica set functionality.
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
On each server, perform the following:
sudo apt-get install gnupg curl
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
sudo apt-get update && sudo apt-get install -y mongodb-org
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.
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
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.
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
Start MongoDB on nodes 2 and 3:
sudo systemctl start mongod.service
Verify all services are active:
sudo systemctl status mongod.service
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.
To enable connection strings like mongodb+srv://username:[email protected]/database, configure DNS records:
TXT Record on mongo.db.domain.com:
authSource=admin&replicaSet=rs0SRV Records on _mongodb._tcp.mongo.db.domain.com:
| Priority | Weight | Port | Target |
|---|---|---|---|
| 0 | 0 | 27017 | mongo-01.db.domain.com |
| 0 | 0 | 27017 | mongo-02.db.domain.com |
| 0 | 0 | 27017 | mongo-03.db.domain.com |
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.