Step 1 — Verify Ubuntu 24.04 and the architecture
Confirm the operating system and architecture:
. /etc/os-release
printf '%s\n%s\n%s\n' "$PRETTY_NAME" "$VERSION_CODENAME" "$(dpkg --print-architecture)"
Expected Ubuntu values include:
MongoDB publishes Community packages for Ubuntu 24.04 on x64 and ARM64 platforms. Before making package changes, check CPU, memory, and disk headroom:
Verify: the server reports Ubuntu 24.04 with codename noble, uses a supported 64-bit architecture, and has enough free disk for the dataset plus backups.
Step 2 — Check for conflicting MongoDB packages
Refresh package metadata and install repository prerequisites:
sudo apt update
sudo apt install -y gnupg curl ca-certificates ufw
Check for existing MongoDB packages:
dpkg -l | grep -E '^ii[[:space:]]+(mongodb|mongodb-server|mongodb-server-core|mongodb-org)' || true
MongoDB's official package family is mongodb-org. Ubuntu-provided packages such as mongodb or mongodb-server-core can conflict with it.
Do not remove an existing package blindly. First identify its data directory, configuration, installed version, and recovery path. If this is a fresh VM, the command should normally return no MongoDB server package.
Verify: there is no unexplained existing MongoDB installation or data directory that could be overwritten by the new official package.
Step 3 — Add the official MongoDB 8.3 repository
Import MongoDB's release signing key:
curl -fsSL https://pgp.mongodb.com/server-8.0.asc | \
sudo gpg -o /usr/share/keyrings/mongodb-server-8.0.gpg \
--dearmor
Create the Ubuntu 24.04 Noble repository file for MongoDB Community 8.3:
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.3 multiverse" | \
sudo tee /etc/apt/sources.list.d/mongodb-org-8.3.list >/dev/null
Refresh package metadata:
Inspect the candidate and source:
apt-cache policy mongodb-org | sed -n '1,20p'
Do not hard-code a patch version unless you intentionally maintain a package pinning policy. The 8.3 repository should provide the current supported 8.3 patch.
Verify: apt-cache policy mongodb-org shows a non-empty candidate from repo.mongodb.org under the Noble mongodb-org/8.3 repository.
Install the official metapackage:
sudo apt install -y mongodb-org
Verify the installed tools:
mongod --version | sed -n '1,8p'
mongosh --version
mongodump --version | sed -n '1,5p'
mongorestore --version | sed -n '1,5p'
Confirm package ownership:
apt-cache policy mongodb-org mongodb-org-server mongodb-mongosh mongodb-database-tools | \
sed -n '1,40p'
Verify: mongod reports an 8.3-series server, mongosh and Database Tools are installed, and package policy points to MongoDB's official repository.
Step 5 — Start MongoDB and verify the local listener
Enable and start the service:
sudo systemctl enable --now mongod
Verify systemd state:
systemctl is-active mongod
systemctl is-enabled mongod
sudo systemctl status mongod --no-pager
Before authorization is enabled, confirm the fresh server responds locally:
mongosh --quiet --eval 'db.runCommand({ ping: 1 })'
Inspect the listener and active network configuration:
sudo ss -lntp | grep ':27017' || true
sudo grep -nE '^[[:space:]]*(port|bindIp):' /etc/mongod.conf
A fresh package installation should remain bound to localhost during authentication bootstrap.
Verify: mongod is active and enabled, local ping succeeds, and TCP 27017 is not listening on a public interface.
Step 6 — Enable authorization while MongoDB is local-only
Back up the configuration:
sudo cp -a /etc/mongod.conf \
"/etc/mongod.conf.$(date -u +%Y%m%dT%H%M%SZ).backup"
Edit the configuration:
sudo nano /etc/mongod.conf
Keep MongoDB on loopback and enable authorization:
net:
port: 27017
bindIp: 127.0.0.1
security:
authorization: enabled
Restart the service:
sudo systemctl restart mongod
systemctl is-active mongod
MongoDB's localhost exception allows the first administrator to be created from localhost while no users or roles exist. The exception closes after the first user or role is created.
Verify: MongoDB restarts with authorization enabled, remains bound to 127.0.0.1, and no user exists before the bootstrap step.
Step 7 — Create the first administrator
Generate a strong administrator password and store it in your secrets manager:
MONGO_ADMIN_PASSWORD="$(openssl rand -hex 32)"
printf 'Store this MongoDB admin password securely: %s\n' "$MONGO_ADMIN_PASSWORD"
export MONGO_ADMIN_PASSWORD
Use the localhost exception to create the first administrator in the admin database:
mongosh --quiet --host 127.0.0.1 --eval '
const adminDb = db.getSiblingDB("admin");
adminDb.createUser({
user: "raffadmin",
pwd: process.env.MONGO_ADMIN_PASSWORD,
roles: [ { role: "root", db: "admin" } ]
});
// The localhost exception ends after this user is created.
// Verify the account using the authenticated command below.
'
Remove the shell variable after storing the credential:
unset MONGO_ADMIN_PASSWORD
Confirm unauthenticated user administration is now rejected:
mongosh --quiet --host 127.0.0.1 \
--eval 'db.getSiblingDB("admin").getUsers()'
Authenticate as the administrator. Omitting the password value makes mongosh prompt securely:
mongosh --quiet \
--host 127.0.0.1 \
--username raffadmin \
--authenticationDatabase admin \
--password \
--eval 'printjson(db.runCommand({ connectionStatus: 1 }).authInfo.authenticatedUsers)'
Verify: unauthenticated user-management commands fail and raffadmin authenticates successfully against admin.
Step 8 — Create a database-scoped application user
Generate a separate application password:
MONGO_APP_PASSWORD="$(openssl rand -hex 32)"
printf 'Store this MongoDB application password securely: %s\n' "$MONGO_APP_PASSWORD"
export MONGO_APP_PASSWORD
Create the application account with readWrite only on raffapp:
mongosh --quiet \
--host 127.0.0.1 \
--username raffadmin \
--authenticationDatabase admin \
--password \
--eval '
const appDb = db.getSiblingDB("raffapp");
appDb.createUser({
user: "raffappuser",
pwd: process.env.MONGO_APP_PASSWORD,
roles: [ { role: "readWrite", db: "raffapp" } ]
});
printjson(appDb.getUser("raffappuser"));
'
Remove the shell variable:
Do not use the administrator credential in application configuration. The application account should authenticate against the database where it was created.
Verify: raffappuser exists in raffapp, has only the required application role, and has no administrative role.
Step 9 — Run an authenticated CRUD test
Connect as the application user and test create, read, update, and delete operations:
mongosh "mongodb://127.0.0.1:27017/raffapp" \
--quiet \
--username raffappuser \
--authenticationDatabase raffapp \
--password \
--eval '
const c = db.getSiblingDB("raffapp").tutorial_check;
c.deleteMany({ name: "raff-mongodb-test" });
const inserted = c.insertOne({
name: "raff-mongodb-test",
status: "created",
createdAt: new Date()
});
const created = c.findOne({ name: "raff-mongodb-test" });
const updated = c.updateOne(
{ name: "raff-mongodb-test" },
{ $set: { status: "verified" } }
);
const verified = c.findOne({ name: "raff-mongodb-test" });
const deleted = c.deleteOne({ name: "raff-mongodb-test" });
printjson({
insertedId: inserted.insertedId,
createdStatus: created.status,
modifiedCount: updated.modifiedCount,
verifiedStatus: verified.status,
deletedCount: deleted.deletedCount
});
'
Expected fields include created, modifiedCount: 1, verified, and deletedCount: 1.
Verify: the non-admin application user completes CRUD operations only inside its assigned database.
Step 10 — Keep port 27017 private
Confirm the configured bind address and active listener:
sudo grep -nE '^[[:space:]]*(port|bindIp):' /etc/mongod.conf
sudo ss -lntp | grep ':27017' || true
For an application on the same VM, keep:
net:
port: 27017
bindIp: 127.0.0.1
Do not bind MongoDB to 0.0.0.0 simply to make Compass or another client convenient.
Before changing UFW, open a second SSH session and inspect the current rules:
If UFW is already active and no private MongoDB rule is intended, add a defense-in-depth deny:
If UFW is inactive, follow Set Up UFW Firewall on Ubuntu 24.04 rather than enabling it blindly from one remote shell.
Verify: MongoDB listens only on loopback for this deployment and no public firewall rule permits TCP 27017.
Step 11 — Create a logical backup with mongodump
MongoDB Database Tools provide mongodump and mongorestore for logical BSON backups. For a standalone server, a live mongodump is not a transactionally consistent multi-collection point-in-time snapshot while writes continue. Quiesce writes or use an appropriate maintenance window when that consistency matters.
Create a protected root-owned backup directory:
sudo install -d -m 700 /var/backups/mongodb
STAMP="$(date -u +%Y%m%d-%H%M%S)"
BACKUP_FILE="/var/backups/mongodb/raffapp-${STAMP}.archive.gz"
Create a compressed archive. Running mongodump with sudo allows it to write into the protected backup directory while --password still prompts instead of placing the secret in command history:
sudo mongodump \
--host 127.0.0.1 \
--username raffadmin \
--authenticationDatabase admin \
--password \
--db raffapp \
--archive="$BACKUP_FILE" \
--gzip
Restrict and inspect the archive:
sudo chmod 600 "$BACKUP_FILE"
sudo ls -lh "$BACKUP_FILE"
Back up the server configuration separately:
sudo cp /etc/mongod.conf "/var/backups/mongodb/mongod.conf-${STAMP}"
sudo chmod 600 "/var/backups/mongodb/mongod.conf-${STAMP}"
Keep production backup copies outside the database VM. Raff Object Storage can be used by S3-compatible backup tooling, while Data Protection provides an additional VM-level recovery layer.
Verify: the archive and configuration backup exist with restrictive permissions, application writes were controlled when consistency required it, and production recovery includes an off-server copy.
Step 12 — Restore-test into an isolated namespace
Never test a backup by overwriting raffapp.
Select the latest archive:
LATEST_BACKUP="$(sudo find /var/backups/mongodb -maxdepth 1 -type f -name 'raffapp-*.archive.gz' -print | LC_ALL=C sort | tail -n 1)"
# Stop here if no readable backup was selected.
if [ -z "$LATEST_BACKUP" ] || ! sudo test -s "$LATEST_BACKUP"; then
printf '%s\n' 'No non-empty backup found. Do not continue with restore.' >&2
false
fi
printf '%s\n' "$LATEST_BACKUP"
Restore raffapp.* into a disposable namespace:
sudo mongorestore \
--host 127.0.0.1 \
--username raffadmin \
--authenticationDatabase admin \
--password \
--archive="$LATEST_BACKUP" \
--gzip \
--nsFrom='raffapp.*' \
--nsTo='raffapp_restore_test.*'
Inspect restored collections:
mongosh --quiet \
--host 127.0.0.1 \
--username raffadmin \
--authenticationDatabase admin \
--password \
--eval '
const restoreDb = db.getSiblingDB("raffapp_restore_test");
printjson(restoreDb.getCollectionNames());
'
For a production recovery rehearsal, also verify representative documents and indexes.
Remove only the disposable restore database:
mongosh --quiet \
--host 127.0.0.1 \
--username raffadmin \
--authenticationDatabase admin \
--password \
--eval 'printjson(db.getSiblingDB("raffapp_restore_test").dropDatabase())'
Verify: the archive restores into raffapp_restore_test, expected collections and documents are readable, and production raffapp remains untouched.
Step 13 — Optionally allow one private application VM with TLS
Use this only when the application and MongoDB run on separate VMs connected through Raff VPC. Authorization alone does not encrypt database traffic.
Example design:
MongoDB private IP: 10.0.0.5
Application private IP: 10.0.0.10
Private DNS name in certificate SAN: mongo.internal.example
Use a CA you control to issue the MongoDB server certificate. Store the combined server certificate and private key plus the CA certificate at controlled paths:
/etc/mongodb/tls/server.pem
/etc/mongodb/tls/ca.pem
Protect the files:
sudo chown -R root:mongodb /etc/mongodb/tls
sudo chmod 750 /etc/mongodb/tls
sudo chmod 640 /etc/mongodb/tls/server.pem
sudo chmod 644 /etc/mongodb/tls/ca.pem
This example uses SCRAM username/password authentication over required TLS, not client-certificate authentication. allowConnectionsWithoutCertificates: true permits clients without a client certificate; authorization and server-certificate validation remain enabled. Create the certificate files first and ensure the private DNS name resolves on both hosts.
Before enabling a private listener, require an active firewall and review existing rules. If UFW is inactive, complete the linked UFW setup first while preserving SSH. Place the exact-source rule before the earlier blanket deny; remove any conflicting broad allow rule only after reviewing its purpose.
sudo ufw insert 1 allow from 10.0.0.10 to 10.0.0.5 port 27017 proto tcp
sudo ufw status numbered
Configure the private listener and required TLS in /etc/mongod.conf:
net:
port: 27017
bindIp: 127.0.0.1,10.0.0.5
tls:
mode: requireTLS
certificateKeyFile: /etc/mongodb/tls/server.pem
CAFile: /etc/mongodb/tls/ca.pem
allowConnectionsWithoutCertificates: true
security:
authorization: enabled
Restart and verify:
sudo systemctl restart mongod
systemctl is-active mongod
sudo ss -lntp | grep ':27017'
Recheck the firewall rules configured before enabling the private listener.
Copy only the CA certificate to the application VM and connect using the DNS name represented in the certificate:
mongosh "mongodb://mongo.internal.example:27017/raffapp" \
--tls \
--tlsCAFile /path/to/ca.pem \
--username raffappuser \
--authenticationDatabase raffapp \
--password \
--eval 'db.runCommand({ ping: 1 })'
Do not use --tlsAllowInvalidCertificates or --tlsAllowInvalidHostnames as a production shortcut.
Verify: MongoDB listens only on loopback plus the intended private interface, UFW allows only the application VM, and the client connects with valid certificate verification.
Step 14 — Apply updates and verify MongoDB end to end
Check pending MongoDB packages:
apt list --upgradable 2>/dev/null | grep -E '^mongodb-' || true
Patch updates within the configured release line can use the package manager. Major and minor release changes require the corresponding MongoDB upgrade procedure and Feature Compatibility Version review.
Apply normal package updates:
sudo apt update
sudo apt upgrade
Verify package, service, listener, and firewall state:
echo 'Package:'
apt-cache policy mongodb-org | sed -n '1,14p'
echo 'Version:'
mongod --version | sed -n '1,8p'
echo 'Service:'
systemctl is-active mongod
systemctl is-enabled mongod
echo 'Listener:'
sudo ss -lntp | grep ':27017' || true
echo 'Firewall:'
sudo ufw status numbered
Verify the administrator, application user, and FCV:
mongosh --quiet \
--host 127.0.0.1 \
--username raffadmin \
--authenticationDatabase admin \
--password \
--eval '
printjson({
admin: db.getSiblingDB("admin").getUser("raffadmin"),
app: db.getSiblingDB("raffapp").getUser("raffappuser"),
fcv: db.adminCommand({ getParameter: 1, featureCompatibilityVersion: 1 })
});
'
If you enabled requireTLS, replace --host 127.0.0.1 in subsequent mongosh, backup, restore, and cleanup commands with --host mongo.internal.example --tls --tlsCAFile /etc/mongodb/tls/ca.pem. The hostname must resolve locally and match the certificate SAN. Plaintext commands will fail after this change.
The deployment is complete when all of these are true:
- MongoDB comes from the intended official 8.3 repository;
mongod is active and enabled;
- authorization is enabled;
- the localhost exception has closed;
- administrator and application identities are separate;
- the application user is scoped to
raffapp;
- public TCP 27017 is blocked;
- optional private remote access uses exact source filtering and validated TLS;
- a logical backup exists off-server;
- an isolated restore test has succeeded;
- package updates and release upgrades are treated as different operations.
Verify: every final check above succeeds and the CRUD and restore tests still pass after maintenance.
Cleanup (optional)
Use this section only when the users, database, backups, firewall rules, and TLS configuration were created solely for this tutorial.
Warning
These commands can permanently delete tutorial data and credentials.
Drop the application database as the administrator:
mongosh --quiet \
--host 127.0.0.1 \
--username raffadmin \
--authenticationDatabase admin \
--password \
--eval 'printjson(db.getSiblingDB("raffapp").dropDatabase())'
Drop the application user if the database drop did not already remove it:
mongosh --quiet \
--host 127.0.0.1 \
--username raffadmin \
--authenticationDatabase admin \
--password \
--eval '
const appDb = db.getSiblingDB("raffapp");
if (appDb.getUser("raffappuser")) printjson(appDb.dropUser("raffappuser"));
'
Warning: The next commands permanently delete all backups matching these tutorial filenames. Keep an off-server copy of anything you need. Run them only in a disposable tutorial environment:
sudo find /var/backups/mongodb -maxdepth 1 -type f -name 'raffapp-*.archive.gz' -print -delete
sudo find /var/backups/mongodb -maxdepth 1 -type f -name 'mongod.conf-*' -print -delete
Delete only the UFW rules you added for this tutorial:
sudo ufw delete allow from 10.0.0.10 to 10.0.0.5 port 27017 proto tcp
sudo ufw delete deny 27017/tcp
If you added private TLS solely for this tutorial, restore your timestamped /etc/mongod.conf.*.backup file before deleting certificate files.
Do not remove raffadmin unless you are intentionally decommissioning this MongoDB instance and have another tested administrative and recovery path.
Troubleshooting
mongodb-org has no installation candidate
Check the Ubuntu codename, repository file, and package candidate:
. /etc/os-release
echo "$VERSION_CODENAME"
cat /etc/apt/sources.list.d/mongodb-org-8.3.list
sudo apt update
apt-cache policy mongodb-org
Expected signals include noble, repo.mongodb.org, mongodb-org/8.3, and a non-empty candidate.
gpg: no valid OpenPGP data found
Re-run the official key command exactly and verify the downloaded data before writing the keyring:
curl -fsSL https://pgp.mongodb.com/server-8.0.asc | head
Then import it:
curl -fsSL https://pgp.mongodb.com/server-8.0.asc | \
sudo gpg -o /usr/share/keyrings/mongodb-server-8.0.gpg \
--dearmor
If the first command returns an HTML error, proxy page, or empty response, fix that network or DNS problem before continuing.
mongosh: command not found
Verify the shell package:
dpkg -l | grep mongodb-mongosh
apt-cache policy mongodb-mongosh
Install or repair the package from the official repository:
sudo apt update
sudo apt install -y mongodb-mongosh
mongosh --version
mongod.service is not found
This usually means mongodb-org-server was not installed successfully. Check package state:
dpkg -l | grep -E '^ii[[:space:]]+mongodb-org-server'
apt-cache policy mongodb-org-server
Install the official metapackage if needed:
sudo apt update
sudo apt install -y mongodb-org
sudo systemctl enable --now mongod
Confirm the 8.3 repository is active and inspect the package candidate:
sudo apt update
apt-cache policy mongodb-database-tools
If the candidate is empty, fix the repository or key error first. Do not add unrelated Ubuntu MongoDB packages to work around a broken official repository.
Authentication fails after first-user creation
The localhost exception closes after the first user or role exists. Authenticate with the correct authentication database:
mongosh --quiet \
--host 127.0.0.1 \
--username raffadmin \
--authenticationDatabase admin \
--password \
--eval 'printjson(db.runCommand({ connectionStatus: 1 }).authInfo)'
For raffappuser, use --authenticationDatabase raffapp.
MongoDB listens on a public interface
Restore a local-only listener:
net:
port: 27017
bindIp: 127.0.0.1
Restart and verify:
sudo systemctl restart mongod
sudo ss -lntp | grep ':27017'
mongodump or mongorestore returns permission denied
The backup directory in this tutorial is root-owned with mode 700. Run the backup and restore commands with sudo as shown in Steps 11 and 12, or use a separate protected directory owned by the dedicated backup operator.
TLS connections fail after requireTLS
Check file permissions, certificate SANs, listener state, and service logs:
sudo ls -l /etc/mongodb/tls
sudo ss -lntp | grep ':27017'
sudo journalctl -u mongod --no-pager -n 100
Use the hostname represented in the server certificate and the correct CA file. Do not bypass certificate or hostname validation to hide a trust-chain problem.
FAQ
How do I install MongoDB on Ubuntu 24.04?
Add MongoDB's official 8.3 APT repository for Ubuntu Noble, run sudo apt install -y mongodb-org, then enable and verify the mongod service.
What MongoDB version should I install on Ubuntu 24.04?
MongoDB 8.3 is the current minor release line. As of September 17, 2026, the latest listed patch is 8.3.11. Install the current candidate from the official 8.3 repository.
Does MongoDB support Ubuntu 24.04?
Yes. MongoDB publishes Ubuntu 24.04 Community packages for supported 64-bit x64 and ARM64 platforms.
Should MongoDB port 27017 be public?
No. Keep it on loopback for same-VM applications. For a separate app VM, use private networking, exact source filtering, authorization, and validated TLS.
Why is mongosh command not found?
The MongoDB Shell is provided by the mongodb-mongosh package. Verify the official repository is configured, then install or repair that package with APT.
How should I back up MongoDB?
Use mongodump for a logical archive, keep an off-server copy, and prove recovery with mongorestore into an isolated namespace. Coordinate writes when standalone cross-collection consistency matters.
Is MongoDB 8.0 to 8.3 a normal patch update?
No. Patch updates stay inside the configured release line. Moving from 8.0 to 8.3 is a release upgrade that requires MongoDB's documented upgrade and FCV procedure.
Conclusion
You now have MongoDB 8.3 Community Edition on a Raff Ubuntu 24.04 VM with official packages, authorization, separate administrator and application users, authenticated CRUD, private-by-default networking, and an isolated backup restore test.
MongoDB 8.3.11 is the latest 8.3 patch listed as of September 17, 2026. Keep routine patch maintenance separate from release upgrades, and review MongoDB's documented upgrade path before moving an existing deployment between release lines.
Continue with MongoDB Hosting, MongoDB vs PostgreSQL, and Set Up UFW Firewall on Ubuntu 24.04.
Sources