A MongoDB replica set is a group of mongod servers holding the same data: one primary accepts writes, secondaries replicate them, and if the primary fails the members elect a new one automatically within seconds. Replica sets are MongoDB’s foundation for high availability — and they also enable transactions and change streams.
Topology
Three data-bearing members is the standard setup:
| Host | IP | Role |
|---|---|---|
| mongo1 | 10.0.0.51 | primary (initially) |
| mongo2 | 10.0.0.52 | secondary |
| mongo3 | 10.0.0.53 | secondary |
An odd number of voting members is needed to elect a primary when one fails. (A cheaper alternative to the third data node is an arbiter — a voter without data — but it weakens durability guarantees; prefer three data nodes.)
Use a private network or VPN, and ideally hostnames (via DNS or /etc/hosts) rather than raw IPs in the configuration.
1. Install MongoDB on all three
Follow installing MongoDB on Ubuntu on each server, same version.
2. Create a shared keyfile
Members authenticate to each other with a keyfile:
openssl rand -base64 756 > mongo-keyfile
Copy it to every server:
sudo mkdir -p /etc/mongodb
sudo cp mongo-keyfile /etc/mongodb/keyfile
sudo chown mongodb:mongodb /etc/mongodb/keyfile
sudo chmod 400 /etc/mongodb/keyfile
(The service user is mongodb on Debian/Ubuntu packages, mongod on RHEL.)
3. Configure each member
/etc/mongod.conf:
net:
port: 27017
bindIp: 127.0.0.1,10.0.0.51 # this server's private IP
security:
authorization: enabled
keyFile: /etc/mongodb/keyfile
replication:
replSetName: rs0
Change bindIp per server. Firewall: allow 27017 only from the other members and your app servers:
for ip in 10.0.0.51 10.0.0.52 10.0.0.53 10.0.0.60; do sudo ufw allow from $ip to any port 27017 proto tcp; done
sudo systemctl restart mongod
4. Initiate the replica set
On mongo1, connect locally (the localhost exception allows creating the first user while no users exist):
mongosh
rs.initiate({
_id: "rs0",
members: [
{ _id: 0, host: "mongo1:27017", priority: 2 },
{ _id: 1, host: "mongo2:27017", priority: 1 },
{ _id: 2, host: "mongo3:27017", priority: 1 }
]
})
Wait a few seconds; the prompt changes to rs0 [direct: primary]. Create the admin user (replicated to all members):
use admin
db.createUser({ user: "admin", pwd: passwordPrompt(), roles: ["root"] })
Then create application users with least privilege — see the auth section of the install guide.
5. Check status
rs.status().members.map(m => ({ name: m.name, state: m.stateStr, health: m.health }))
rs.conf()
rs.printSecondaryReplicationInfo() // replication lag
6. Connection strings
Applications should connect to the replica set, not a single host — drivers then discover the primary and follow failovers automatically:
mongodb://app:PASSWORD@mongo1:27017,mongo2:27017,mongo3:27017/shop?replicaSet=rs0&authSource=shop
Hostnames in the connection string must resolve from the app servers to the same names used in the replica set config.
Read and write concerns
- Write concern
w: "majority"(default in recent versions) — a write is acknowledged once most members have it; survives a primary failure. - Read preference —
primary(default, always current),primaryPreferred,secondaryPreferred(offload reads; may be slightly stale),nearest.
7. Test failover
On the primary:
rs.stepDown()
Another member becomes primary within seconds; your application (with a proper connection string and retryable writes, on by default) continues after a brief pause.
Maintenance
- Upgrade or restart secondaries first, one at a time, then step down the primary and upgrade it.
- Add a member:
rs.add("mongo4:27017")— it syncs data automatically. - Remove:
rs.remove("mongo3:27017"). - Back up from a secondary with
mongodump --oplog— see MongoDB backup and restore.
Replication protects against server failure, not mistakes — a dropped collection disappears on all members. Keep backups.
Related: database replication explained. Three KVM VPS servers in the same location make a solid MongoDB replica set.