Introduction
MongoDB is a JSON-document NoSQL database:
- Flexible schema (each document can differ)
- Secondary indexes, aggregation pipeline
- Replica sets for HA
- Sharding for horizontal scaling
- Drivers for all languages
- Heavily used in the Node.js world (Mongoose)
⚠️ By default, MongoDB listens on all interfaces without auth. Unsecured internet-facing MongoDBs are a classic ransomware target. Always enable auth and restrict binding.
Prerequisites
- Linux VPS Debian 12 / Ubuntu 24.04
- 2 vCPU, 4 GB RAM
- Root access
Step 1: Installation
sudo apt update
sudo apt install -y gnupg curl
curl -fsSL https://www.mongodb.org/static/pgp/server-7.0.asc | sudo gpg --dearmor -o /usr/share/keyrings/mongodb-server-7.0.gpg
echo "deb [signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list
sudo apt update
sudo apt install -y mongodb-org
sudo systemctl enable --now mongod
sudo systemctl status mongod
mongosh --eval "db.runCommand({ ping: 1 })"
Step 2: Secure binding
/etc/mongod.conf:
net:
port: 27017
bindIp: 127.0.0.1
For LAN access:
net:
port: 27017
bindIp: 127.0.0.1,10.0.0.5
⚠️ Never 0.0.0.0 unless strict firewall in front.
Step 3: Enable authentication
mongosh
use admin
db.createUser({
user: "admin",
pwd: "very-strong-pass",
roles: [{ role: "userAdminAnyDatabase", db: "admin" },
{ role: "readWriteAnyDatabase", db: "admin" }]
})
exit
/etc/mongod.conf:
security:
authorization: enabled
sudo systemctl restart mongod
mongosh -u admin -p --authenticationDatabase admin
Step 4: Application user
use myapp
db.createUser({
user: "myapp_user",
pwd: "strong-app-pass",
roles: [{ role: "readWrite", db: "myapp" }]
})
Minimum privilege.
Step 5: First insertion
use myapp
db.users.insertOne({
name: "Alice",
email: "[email protected]",
age: 30,
tags: ["dev", "admin"]
})
db.users.find({ age: { $gte: 25 } })
Step 6: Indexes
db.users.createIndex({ email: 1 }, { unique: true })
db.users.createIndex({ age: 1, name: 1 })
db.users.getIndexes()
Execution plan:
db.users.find({ email: "[email protected]" }).explain("executionStats")
Look for stage: "IXSCAN" (good) vs COLLSCAN (slow).
Step 7: Replica Set for HA
3-node replica set:
On each node, /etc/mongod.conf:
replication:
replSetName: rs0
net:
bindIp: 127.0.0.1,10.0.0.X
security:
authorization: enabled
keyFile: /etc/mongodb-keyfile
Generate keyFile (one, copied to all 3 nodes):
openssl rand -base64 756 | sudo tee /etc/mongodb-keyfile
sudo chmod 400 /etc/mongodb-keyfile
sudo chown mongodb:mongodb /etc/mongodb-keyfile
On primary node:
rs.initiate({
_id: "rs0",
members: [
{ _id: 0, host: "10.0.0.1:27017" },
{ _id: 1, host: "10.0.0.2:27017" },
{ _id: 2, host: "10.0.0.3:27017" }
]
})
rs.status()
Primary auto-elected.
Step 8: Application connection string
mongodb://myapp_user:[email protected],10.0.0.2,10.0.0.3:27017/myapp?replicaSet=rs0&authSource=myapp
Driver handles failover automatically.
Step 9: Backup with mongodump
mongodump --uri="mongodb://admin:[email protected]:27017" --out=/var/backups/mongo-$(date +%F)
Compressed archive:
mongodump --uri="..." --archive | gzip > /var/backups/mongo-$(date +%F).archive.gz
Restore:
gunzip -c /var/backups/mongo-2026-05-17.archive.gz | mongorestore --uri="..." --archive
Step 10: Backup to S3
#!/bin/bash
DATE=$(date +%F)
mongodump --uri="..." --archive | gzip | aws s3 cp - s3://my-backups/mongo-$DATE.archive.gz
0 2 * * * /root/backup-mongo.sh
Step 11: Monitoring
mongosh --eval "db.serverStatus()"
mongosh --eval "db.stats()"
mongostat --uri="..."
mongotop --uri="..."
For Prometheus, use mongodb_exporter:
docker run -d -p 9216:9216 percona/mongodb_exporter:0.40 \
--mongodb.uri=mongodb://admin:pass@host:27017
Step 12: Performance tuning
WiredTiger cache
storage:
wiredTiger:
engineConfig:
cacheSizeGB: 2 # 50% available RAM
Profile slow queries
db.setProfilingLevel(1, { slowms: 100 })
db.system.profile.find().sort({ ts: -1 }).limit(10)
No $where
$where disables indexes. Use aggregation pipeline instead.
Troubleshooting
"Authentication failed"
Check authSource in connection string. User in admin → authSource=admin. User in myapp → authSource=myapp.
"exceeded connection limit"
db.serverStatus().connections
Increase net.maxIncomingConnections or reduce client connections (pool).
Replica set: "not master"
You're on a secondary. To read:
rs.secondaryOk()
db.users.find()
For writes, connect to primary.
Disk full
sudo du -sh /var/lib/mongodb
Compact:
db.runCommand({ compact: "users" })
Useful commands
sudo systemctl status mongod
sudo systemctl restart mongod
sudo tail -f /var/log/mongodb/mongod.log
mongostat --uri="..."
mongotop --uri="..."
mongosh -u admin -p --authenticationDatabase admin
mongodump --uri="..." --archive | gzip > backup.archive.gz
mongorestore --uri="..." --archive < backup.archive
mongosh --eval "rs.status()"
mongosh --eval "rs.stepDown()"
mongosh --eval "db.setProfilingLevel(1, { slowms: 100 })"
Conclusion
MongoDB is powerful for flexible workloads:
- Dynamic schema
- Horizontal scaling (sharding)
- HA via replica sets
- Rich aggregation framework
Limits:
- ACID transactions less mature than SQL
- High memory consumption
- Limited joins (vs SQL)
Going further:
- Configure sharding for >1 TB databases
- Explore MongoDB Atlas (managed)
- For analytics, consider MongoDB Charts or export to BigQuery
Resources
- Official docs: https://www.mongodb.com/docs/
- Atlas: https://www.mongodb.com/atlas
- Security best practices: https://www.mongodb.com/docs/manual/security/
- Drivers: https://www.mongodb.com/docs/drivers/


















