What your database needs to run well
Memory comes first. MongoDB keeps the data and indexes you query often in its WiredTiger cache, and the Linux page cache holds the compressed files behind it. Out of the box the cache gets whichever is larger: half of your RAM after subtracting 1 GB, or 0.256 GB. On a 64 GB server that works out to 31.5 GB for WiredTiger and the remainder for Linux, by our sum. MongoDB's production notes ask you not to raise the cache past that default.
| Part of the machine | What MongoDB's notes ask for |
|---|---|
| Processor | x86_64 with AVX: Intel Haswell or later, AMD Bulldozer or later; at least two real cores per mongod |
| Drives | SSDs where they are affordable; RAID 10 for the best storage performance, not RAID 5 or 6 |
| File system | XFS, strongly recommended with WiredTiger; EXT4 is supported, but it may cause performance issues |
| Kernel settings | swappiness 1 or 0, Transparent Hugepages enabled (MongoDB 8.0 and later), readahead 8 to 32 |
| Clock | an NTP-compatible time daemon such as chrony or systemd-timesyncd |
The server that fits
A database spends its day on small random reads and log flushes, and that is the work an NVMe dedicated server is built for. You get a whole HPE Moonshot cartridge: its processor, memory, drives and port are used by nobody else, and you have root.
- More data in memory: the Xeon D-1500 line goes up to 128 GB of DDR4, with the D-1548 (8 cores) or the D-1587 (16 cores).
- A console of its own: the Xeon E3-1585L v5 build (4 cores, up to 64 GB) is the m710x cartridge, and the m710x is among the cartridges with a console of their own. The other cartridge types, apart from the m510, only power on and off.
- Billed in euros: the 8-core Xeon E-2286M, up to 64 GB, is built in Bucharest only.
All of them are newer than Haswell, and the setup block checks AVX anyway. Each drive can be anywhere from 240 GB up to 3.84 TB. Take two of the same size and the operating system mirrors them (software RAID 1): when one dies, you swap it and keep your data. A mirror does not undo a mistake, though; that is what the backups further down are for.
A racked machine is yours about 30 minutes after your order is approved. A build you configure takes 4 to 24 hours when we hold the parts, and longer when one has to be bought in. The port is never metered, so copying dumps to another server costs nothing extra. Not sure which city? Time all five from your browser.
Up and running, locked down, in one sitting
Log in over SSH and paste this. It is MongoDB's Ubuntu procedure, which we adjusted in a few places: ufw is switched on before anything else with only SSH allowed (IPv6 included), the signing key is saved to a file and converted with --batch --yes so running it twice never stops at a question, logins are switched on in /etc/mongod.conf before MongoDB starts for the first time, and the swappiness setting lives in its own file under /etc/sysctl.d. If the shipped config does not bind to 127.0.0.1, it stops instead of carrying on.
# Ubuntu 24.04 LTS with sudo. Each step runs only if the one before worked.
. /etc/os-release && [ "$VERSION_CODENAME" = noble ] && grep -qw avx /proc/cpuinfo &&
sudo sed -i 's/^IPV6=.*/IPV6=yes/' /etc/default/ufw &&
sudo ufw allow OpenSSH && sudo ufw --force enable &&
sudo apt-get install -y gnupg curl &&
curl -fsSL https://pgp.mongodb.com/server-9.asc -o /tmp/mongodb-9.asc &&
sudo gpg --batch --yes --dearmor -o /usr/share/keyrings/mongodb-server-9.gpg /tmp/mongodb-9.asc &&
echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-9.gpg ] https://repo.mongodb.org/apt/ubuntu noble/mongodb-org/9.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-9.0.list &&
sudo apt-get update && sudo apt-get install -y mongodb-org &&
grep -qx ' bindIp: 127.0.0.1' /etc/mongod.conf &&
if ! grep -q '^security:' /etc/mongod.conf; then printf 'security:\n authorization: enabled\n' | sudo tee -a /etc/mongod.conf >/dev/null; fi &&
grep -qx ' authorization: enabled' /etc/mongod.conf &&
printf 'vm.swappiness = 1\n' | sudo tee /etc/sysctl.d/90-mongod.conf >/dev/null && sudo sysctl --system >/dev/null &&
sudo systemctl enable --now mongod && sleep 5 && systemctl is-active --quiet mongod &&
echo "OK - MongoDB listens on 127.0.0.1 only and asks for a login" ||
echo "STOP - something above did not work; check /var/log/mongodb/mongod.log"
On Ubuntu 22.04 or 26.04, swap noble for jammy or resolute in both places. Next, create your accounts. Because logins are on and no account exists yet, MongoDB's localhost exception lets you create one first user from the server itself. Type mongosh, then enter the lines below one by one: every passwordPrompt() stops and waits for you to type a password, so pasting them all at once would feed the next line in as the password.
mongosh
use admin
db.createUser({ user: "root_admin", pwd: passwordPrompt(), roles: [ { role: "userAdminAnyDatabase", db: "admin" }, { role: "readWriteAnyDatabase", db: "admin" } ] })
db.auth("root_admin", passwordPrompt())
db.createUser({ user: "dumper", pwd: passwordPrompt(), roles: [ "backup", "restore" ] })
db.getSiblingDB("shop").createUser({ user: "shop", pwd: passwordPrompt(), roles: [ { role: "readWrite", db: "shop" } ] })
Now you have an administrator, a dumper account that can only back up and restore, and a shop account limited to the shop database. Your app uses that last one, with authSource=shop in its connection string.
Tune the box the way MongoDB asks
- Turn Transparent Hugepages on. Since 8.0 MongoDB wants them enabled before it starts; its TCMalloc performance page gives a small unit file named
enable-transparent-huge-pages.servicethat runs ahead ofmongod.service. Besides THP itself (always, defragdefer+madvise, khugepagedmax_ptes_none0), that unit also switchesvm.overcommit_memoryto 1. Save the file, then reload systemd (sudo systemctl daemon-reload), start the unit now and at every boot (sudo systemctl start enable-transparent-huge-pagesfollowed bysudo systemctl enable enable-transparent-huge-pages), restart MongoDB withsudo systemctl restart mongod, and check thatcat /sys/kernel/mm/transparent_hugepage/enabledshows[always]selected. Then ask mongosh fordb.serverStatus().tcmalloc.usingPerCPUCaches: you want true. If you get false, the same page says to switch off glibc rseq, so runsudo systemctl edit mongod, putEnvironment=GLIBC_TUNABLES=glibc.pthread.rseq=0beneath a[Service]line, and restart again. - Look at the file system with
df -T /var/lib/mongodb. If the Type column says ext4, move the data directory to an XFS volume while the database is still empty. - Check the open-files limit with
systemctl show mongod -p LimitNOFILE. MongoDB warns at startup when it is under 64000. - Leave NUMA alone on these single-socket cartridges. On a machine with two sockets, the production notes want NUMA disabled in firmware, or else zone reclaiming disabled and mongod launched via
numactl --interleave=all.
Keep 27017 private
MongoDB's own install guide says to secure the deployment before binding it to any address the public can reach. To browse your data with Compass from your laptop, sign in over SSH as yourself with port forwarding, ssh -N -L 27018:127.0.0.1:27017 you@your-server, and point Compass at localhost port 27018.
When your application lives on a different server, do all three of these together: add this server's address to net.bindIp, turn on TLS (the security checklist wants it on every connection), and let in that one client only (sudo ufw allow proto tcp from 198.51.100.7 to any port 27017). Do not run a plain ufw allow 27017: that opens the database to the whole internet.
Back it up so you can actually restore
mongodump writes a logical copy of every database. MongoDB calls it a tool for small deployments, and its guide to the backup tools warns that a dump reads all your data through memory and pushes frequently used data out of the cache, slowing normal traffic while it runs. That is why the cron line below picks 02:30. First, as root, create the password file empty with mode 600 (install -m 0600 /dev/null /etc/mongo-dumper.yaml), then edit it with sudo nano /etc/mongo-dumper.yaml and type a single YAML line, password followed by a colon and the dumper password inside double quotes (choose one with no double quote or backslash). MongoDB recommends that --config file because a password on the command line can show up in ps.
# Run as root once /etc/mongo-dumper.yaml exists (mode 600, see above).
install -d -m 700 /srv/mongo-backups && cat > /usr/local/bin/mongo-dump.sh <<'EOF'
set -euo pipefail
umask 077
out=/srv/mongo-backups/dump-$(date +%F-%H%M%S)
mongodump --config=/etc/mongo-dumper.yaml -u dumper --authenticationDatabase=admin \
--archive="$out.gz" --gzip --quiet
gzip -t "$out.gz"
cp /etc/mongod.conf "$out.mongod.conf"
find /srv/mongo-backups -name 'dump-*' -mtime +14 -delete
echo "saved $out.gz"
EOF
printf '30 2 * * * root bash /usr/local/bin/mongo-dump.sh >>/var/log/mongo-dump.log 2>&1\n' > /etc/cron.d/mongo-dump &&
bash /usr/local/bin/mongo-dump.sh || echo "STOP - the dump did not finish, read the lines above"
The script quits on the first error, tests the compressed archive, saves your config beside it, and only then deletes dumps older than 14 days. Copy /srv/mongo-backups to a second machine with rsync -a (leave --delete out). A single server has no oplog, so a dump is not frozen at one instant; that option needs a replica set.
To restore over your live data, stop your app first so nothing writes, then take a fresh dump (sudo bash /usr/local/bin/mongo-dump.sh) and wait for its saved line: that file is your way back, and the 14-day cleanup leaves it alone. Then, as root, run gzip -t FILE && mongorestore --gzip --archive=FILE --drop --nsExclude='admin.*' --config=/etc/mongo-dumper.yaml -u dumper --authenticationDatabase=admin. Leaving out admin keeps your current accounts, because a --drop restore that includes it swaps every user for the ones in the dump. Unhappy with the result? With the app still stopped, run the same command on the fresh dump. --drop only swaps collections that dump contains, so delete manually every collection that the first restore created but the fresh dump lacks.
Snapshots of the disk are MongoDB's other method. Its LVM guide wants your data files, journal and config together on one logical volume with nothing else on it; with the journal on a different volume, you lock writes with db.fsyncLock() while the snapshot is taken. Each LVM snapshot is a full image, never incremental, and it only protects you once you copy it to another machine. If you want this route, set up LVM for /var/lib/mongodb while the server is still empty.
Growing to three machines, and upgrading later
MongoDB's replica set tutorial uses three members on separate machines, always an odd number, named by DNS hostnames. For production, have the members prove who they are with X.509 certificates: MongoDB's keyfile tutorial says shared keyfiles are for testing and development only. There is no private network between servers here, so the members talk across their public ports: turn TLS on for every member and allow each member's address through ufw, nothing wider.
For new versions, move up a single major version per step. MongoDB 9.0 upgrades from 8.0 or 8.3, and the old feature compatibility version must be set first; a 7.0 server goes to 8.0 before anything else. A replica set upgrades its secondaries one by one, then the primary steps down. MongoDB suggests waiting a while before raising the feature compatibility version, since that makes a downgrade harder.
Is it really free? The licence in plain words
Yes, to download and run. MongoDB's licensing page says Database Server releases after 16 October 2018 come under the SSPL v1.0, a licence MongoDB wrote (earlier releases were AGPL v3.0), while its supported client libraries use Apache 2.0.
Not legal advice; this is simply how we read it. You may run the program unchanged, subject to section 13. Hand a copy to anyone, altered or unaltered, and you must include the licence and the matching source. Section 13 is the unusual part: offer MongoDB's functionality, or your modified version, to other people as a service, and you must publish the source of everything used to run that service, from management and monitoring through backup, storage and hosting software, under the SSPL. If you cannot tell which side your product is on, ask a lawyer; MongoDB also offers commercial licences.
When to choose something else
- Lots of data or RAID 10: the NVMe cartridges hold two mirrored drives at most. Blade and rack machines with a hardware RAID controller are on the enterprise page.
- LDAP, Kerberos or auditing: the security checklist lists those under MongoDB Enterprise, not Community, which signs users in with SCRAM or X.509.
- Search inside the database: MongoDB Search is not part of Community by default; it runs as its own process, mongot, and needs MongoDB 8.3 or later set up as a replica set, so the single server above would have to become one first.
- Tables and joins: a relational engine may suit you better. Compare PostgreSQL on a dedicated server, MariaDB on a dedicated server, and Redis if you only need a fast cache.
Questions people ask
- Can I run MongoDB on just one server in production?
- You can, as long as you can live with downtime while you restore. MongoDB calls replica sets the recommended configuration; a set of three members keeps working when one fails. Start with one server and tested dumps, and add two more when an outage would hurt.
- Which Ubuntu releases does MongoDB 9.0 support?
- MongoDB 9.0 Community supports the 64-bit LTS releases 22.04, 24.04 and 26.04. The setup block above is written for 24.04; change the release name for the other two. Use MongoDB's mongodb-org package rather than Ubuntu's own mongodb package, which MongoDB does not maintain and which conflicts with it.
- What happens if a drive dies?
- With two drives in RAID 1 the server keeps running on the second one, and the part is replaced within four hours of your call or chat under the service agreement. With one drive, you restore from the dumps you copied off the machine. Either way, keep those off-server copies.
- Can I get vector search with Community?
- Not out of the box. Vector Search, like MongoDB Search, is served by mongot, a separate process you install with Docker or on Linux. MongoDB lists what it needs: version 8.3 or later, a replica set that has been initiated and uses keyfile access control, plus a user granted
searchCoordinator. A lone standalone server does not qualify.