MongoDB is a document database. A fresh install allows anyone who can reach the port to read and write everything, and many public data leaks started exactly that way. This post installs MongoDB 7.0 and secures it before any data goes in.
Versions in use on this date. MongoDB 7.0 is the current stable major release; MongoDB 8.0 is still in release-candidate testing and is not generally available. The shell is mongosh (the legacy mongo shell was removed in 6.0).
Architecture of a secured single node
flowchart TB
APP[Application<br/>connection string with user and TLS] -->|27017 TLS| FW[Firewall allows app subnet only]
ADM[Admin workstation via VPN or bastion] -->|27017 TLS| FW
FW --> M[mongod 7.0<br/>auth enabled bindIp private]
M --> D[(dbPath on XFS volume<br/>journal enabled)]
M --> L[/var/log/mongodb/mongod.log/]
D -->|scheduled dump or snapshot| BK[Backup storage]
Install from the official repository
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 [arch=amd64,arm64 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
mongod --version
Pin the packages if you do not want an automatic jump to a new minor version: sudo apt-mark hold mongodb-org mongodb-org-server.
Host settings recommended by MongoDB
- Use XFS for the data volume (the
WiredTigerengine is tested on it) and mount withnoatime. - Disable transparent huge pages (a small systemd unit, or the
mongodb-orgpackage’s guidance). - Raise the limits: the packaged service already sets
LimitNOFILE, but check withcat /proc/$(pidof mongod)/limits. - Keep swap small and let the WiredTiger cache use its default (about half of RAM minus 1 GB).
Create the admin user, then enable auth
Authorisation is off until you enable it, so create the first user while the localhost exception still applies:
// mongosh
use admin
db.createUser({
user: "admin",
pwd: passwordPrompt(),
roles: [ { role: "userAdminAnyDatabase", db: "admin" }, "readWriteAnyDatabase" ]
})
Then edit /etc/mongod.conf:
storage:
dbPath: /var/lib/mongodb
journal:
enabled: true
systemLog:
destination: file
path: /var/log/mongodb/mongod.log
logAppend: true
net:
port: 27017
bindIp: 127.0.0.1,10.0.1.21
security:
authorization: enabled
sudo systemctl restart mongod
mongosh -u admin -p --authenticationDatabase admin
Never bind to 0.0.0.0 without a firewall, and never leave the port open to the internet. Create least-privilege users per application:
use shop
db.createUser({
user: "shop_app",
pwd: passwordPrompt(),
roles: [ { role: "readWrite", db: "shop" } ]
})
Enable TLS
net:
tls:
mode: requireTLS
certificateKeyFile: /etc/ssl/mongodb/server.pem
CAFile: /etc/ssl/mongodb/ca.pem
mongosh "mongodb://shop_app@db1.example.com:27017/shop?tls=true&tlsCAFile=/etc/ssl/mongodb/ca.pem" -p
The certificate must contain the hostname clients use. Use your internal CA or a public one; avoid tlsAllowInvalidCertificates outside tests.
Verify the security posture
db.runCommand({ connectionStatus: 1, showPrivileges: false })
db.getSiblingDB("admin").getUsers()
From another host without credentials, mongosh --host db1 should connect but fail every command with requires authentication. Also check that the port is closed from networks that should not reach it: nmap -p 27017 db1.
Operations basics
- Enable the slow query log (
operationProfiling.slowOpThresholdMs: 100) and review indexes withexplain(). - Rotate logs with
logRotate: reopenandlogrotate. - Monitor connections, WiredTiger cache usage and replication lag (next post).
- Upgrades go one major version at a time with
featureCompatibilityVersionset last; never skip. - Backups are covered in the next post. A single node has no copy of its data except backups, so do not run important data like this.