MongoDB 8.0 Community on Ubuntu 22.04 on Azure User Guide
Overview
This guide covers the deployment and use of MongoDB 8.0 on Ubuntu 22.04 by cloudimg, a virtual machine image on the Azure Marketplace. The image runs MongoDB 8.0 Community as a single node document database on Ubuntu 22.04 LTS, installed from MongoDB's official apt repository (repo.mongodb.org), with authentication switched on before the server first starts.
On the first boot of every virtual machine, a one time service creates two users with per VM random passwords and writes them to a file only root can read:
marketplaceAdmin, with therootrole on theadmindatabase, for administrationmarketplace, withreadWriteanddbAdminon theappdbdatabase, for your application
No two virtual machines share these credentials, and there is no default login.
Everything below was checked on a virtual machine deployed from the public Marketplace image (cloudimg1647283583153:mongodb-8-0-ubuntu-22-04:default:latest, image version 1.0.20260420), with every command run as azureuser.
What's included
- MongoDB 8.0 Community server (
mongodb-org8.0.21 on the image version above), running as themongodsystemd service under themongodbuser /etc/mongod.confwithsecurity.authorization: enabled, listening on port 27017 on all interfaces (bindIp: 0.0.0.0), data in/var/lib/mongodb, log in/var/log/mongodb/mongod.logmongod-firstboot.service, which creates the two users on the first boot only and records that it has run in/var/lib/mongodb/.firstboot-done- The credentials file
/stage/scripts/mongodb-credentials.log, mode 600, owned by root - The MongoDB Shell (
mongosh2.8.2) and the MongoDB Database Tools (100.16.0):mongodump,mongorestore,mongoexport,mongoimport,bsondump,mongostatandmongotop - The MongoDB 8.0 apt repository, so MongoDB 8.0 patch releases arrive through
apt - Ubuntu 22.04 LTS with the Azure Linux Agent, chrony for time sync and Ubuntu's unattended security upgrades
Platform: Microsoft Azure (Gen2, Hyper-V)
Default user: azureuser (or the administrator name you choose)
MongoDB port: 27017
Credentials file: /stage/scripts/mongodb-credentials.log
Licensing
MongoDB Community is distributed under the Server Side Public License (SSPL) 1.0. It is suitable for internal application use. Offering MongoDB itself as a service to third parties requires separate licensing from MongoDB, Inc. The licence text is at https://www.mongodb.com/legal/licensing/server-side-public-license.
Prerequisites
Before deploying this image, ensure you have:
- An active Microsoft Azure subscription
- Access to the Azure Portal, or the Azure CLI on your workstation
- An SSH key pair for Linux virtual machine access
- A virtual network plan: which application subnets need to reach the database on port 27017
Choose a virtual machine size that suits your workload. MongoDB's WiredTiger storage engine uses, by default, the larger of half of (RAM minus 1 GB) or 256 MB as its cache, so size memory for your working set and indexes.
Step 1: Deploy the Virtual Machine
Option A: Azure Portal
- Open the MongoDB 8.0 on Ubuntu 22.04 by cloudimg listing on the Azure Marketplace and choose Get it now, then Create
- Configure the basics:
- Subscription: Select your Azure subscription
- Resource Group: Create new or select existing
- Virtual Machine Name: Enter a name for your VM
- Region: Select your preferred Azure region
- Size: Select a size for your workload
- Under Administrator Account, select SSH public key and enter your key
- Under Inbound Port Rules, allow SSH (port 22), ideally from your own network only. Do not open port 27017 to the internet
- On the Networking tab, choose the virtual network your application servers use
- Click Review + Create, then Create
Option B: Azure CLI
The image carries a Marketplace purchase plan, so accept its terms once per subscription. Then create a network security group that allows SSH from your own network only, and create the virtual machine. Replace <your-ip> with your workstation's public address and <your-vm-size> with the size you chose:
az vm image terms accept --urn cloudimg1647283583153:mongodb-8-0-ubuntu-22-04:default:latest
az network nsg create --resource-group myResourceGroup --name my-ssh-only-nsg
az network nsg rule create --resource-group myResourceGroup --nsg-name my-ssh-only-nsg \
--name allow-ssh --priority 100 --protocol Tcp --destination-port-ranges 22 \
--source-address-prefixes <your-ip>/32 --access Allow
az vm create \
--resource-group myResourceGroup \
--name my-mongodb-vm \
--image cloudimg1647283583153:mongodb-8-0-ubuntu-22-04:default:latest \
--size <your-vm-size> \
--admin-username azureuser \
--ssh-key-values ~/.ssh/id_ed25519.pub \
--nsg my-ssh-only-nsg \
--public-ip-sku Standard \
--storage-sku StandardSSD_LRS \
--query publicIpAddress -o tsv
The command prints the virtual machine's public IP address. To keep the database server off the internet entirely, add --public-ip-address "" and reach it through Azure Bastion, a VPN or a jump host on the same virtual network instead. Step 9 shows how to let your application servers reach port 27017.
Step 2: Connect via SSH
Run this on your own workstation:
ssh azureuser@<vm-ip>
There is no password to enter. If SSH asks for one, the key your client is offering is not the key you supplied at create time.
The first boot finishes within a minute or two of the virtual machine starting. To wait for it:
sudo cloud-init status --wait
It prints status: done when the first boot has finished.
Step 3: Check the Server
Both services are active once the first boot has finished:
systemctl is-active mongod mongod-firstboot
Expected output:
active
active
mongod listens on port 27017 on all interfaces:
sudo ss -Htlnp '( sport = :27017 )' | awk '{print $4, $6}'
Expected output:
0.0.0.0:27017 users:(("mongod",pid=...,fd=...))
That means anything that can reach the virtual machine on port 27017 can reach the server, so the network security group decides who can connect (Step 9), and every connection still has to authenticate. The configuration that sets this is in /etc/mongod.conf:
grep -A2 -E '^(net|security):' /etc/mongod.conf
Expected output:
net:
port: 27017
bindIp: 0.0.0.0
--
security:
authorization: enabled
Step 4: Retrieve the MongoDB Credentials
The first boot service writes both users to one file, readable only by root:
sudo stat -c '%a %U:%G %n' /stage/scripts/mongodb-credentials.log
sudo cat /stage/scripts/mongodb-credentials.log
The file holds these fields, plus two example connection strings in its comments:
root.user=marketplaceAdmin
root.password=<generated>
root.authSource=admin
app.user=marketplace
app.password=<generated>
app.database=appdb
app.authSource=appdb
host=<private-ip>
port=27017
mechanism=SCRAM-SHA-256
host is the virtual machine's private IP address, which is the address your application servers on the same virtual network use. Both users can authenticate with SCRAM-SHA-256 (MongoDB also keeps SCRAM-SHA-1 credentials for them, its default for new users).
Copy both passwords somewhere safe, such as Azure Key Vault. For the commands in this guide, load them into shell variables, so they are not typed or echoed:
ROOT_PW=$(sudo awk -F= '/^root\.password=/ {print $2}' /stage/scripts/mongodb-credentials.log)
APP_PW=$(sudo awk -F= '/^app\.password=/ {print $2}' /stage/scripts/mongodb-credentials.log)
Step 5: Authentication Is Enforced
A connection without credentials can reach the server, but it can't run commands:
mongosh --quiet --host 127.0.0.1 --eval 'db.adminCommand({ listDatabases: 1 })'
Expected output:
MongoServerError: Command listDatabases requires authentication
A wrong login is refused too:
mongosh --quiet --host 127.0.0.1 -u marketplaceAdmin -p not-the-real-one \
--authenticationDatabase admin --eval 'db.runCommand({ ping: 1 })'
Expected output:
MongoServerError: Authentication failed.
With the administrator's credentials, the server answers:
mongosh --quiet --host 127.0.0.1 -u marketplaceAdmin -p "$ROOT_PW" \
--authenticationDatabase admin --eval 'print(db.version())'
Expected output:
8.0.21
List the users the first boot created, with their roles:
mongosh --quiet --host 127.0.0.1 -u marketplaceAdmin -p "$ROOT_PW" --authenticationDatabase admin --eval '
for (const d of ["admin", "appdb"])
db.getSiblingDB(d).getUsers().users.forEach(u => print(u.user + "@" + u.db, u.roles.map(r => r.role).join(",")));
'
Expected output:
marketplaceAdmin@admin root
marketplace@appdb readWrite,dbAdmin
Step 6: Create a Collection, Insert and Find Documents
Use the application user for application data. MongoDB creates the database and the collection on the first write:
mongosh --quiet --host 127.0.0.1 -u marketplace -p "$APP_PW" --authenticationDatabase appdb appdb --eval '
db.devices.insertMany([
{ serial: "A001", model: "sensor-pro", firmware: "1.4.0" },
{ serial: "A002", model: "sensor-pro", firmware: "1.4.1" },
{ serial: "A003", model: "sensor-lite", firmware: "1.1.0" }
]);
print("inserted:", db.devices.countDocuments({}));
db.devices.find({ firmware: /^1\.4\./ }, { _id: 0 }).forEach(d => print(EJSON.stringify(d)));
'
Expected output:
inserted: 3
{"serial":"A001","model":"sensor-pro","firmware":"1.4.0"}
{"serial":"A002","model":"sensor-pro","firmware":"1.4.1"}
The application user is limited to appdb. It cannot, for example, read the user list in admin:
mongosh --quiet --host 127.0.0.1 -u marketplace -p "$APP_PW" --authenticationDatabase appdb appdb \
--eval 'db.getSiblingDB("admin").getUsers()' 2>&1 | cut -c1-60
Expected output:
MongoServerError: not authorized on admin to execute command
Step 7: Create Indexes for Query Performance
Without an index, a query scans every document in the collection. Index the fields your queries filter on:
mongosh --quiet --host 127.0.0.1 -u marketplace -p "$APP_PW" --authenticationDatabase appdb appdb --eval '
db.devices.createIndex({ serial: 1 }, { unique: true });
db.devices.createIndex({ model: 1, firmware: 1 });
db.devices.getIndexes().forEach(i => print(i.name));
const plan = db.devices.find({ model: "sensor-pro", firmware: "1.4.1" }).explain().queryPlanner.winningPlan;
print("winning stage:", (plan.inputStage || plan).stage);
'
Expected output:
_id_
serial_1
model_1_firmware_1
winning stage: IXSCAN
IXSCAN means the query used the compound index rather than a full collection scan (COLLSCAN). The unique index on serial also rejects a duplicate:
mongosh --quiet --host 127.0.0.1 -u marketplace -p "$APP_PW" --authenticationDatabase appdb appdb \
--eval 'db.devices.insertOne({ serial: "A001", model: "sensor-pro" })' 2>&1 | cut -c1-60
Expected output:
MongoServerError: E11000 duplicate key error collection: app
Step 8: Back Up and Restore with mongodump
mongodump and mongorestore are installed. A dump of the appdb database, as the administrator, into a dated directory:
sudo mkdir -p /var/backups/mongodb
sudo chown "$(id -u):$(id -g)" /var/backups/mongodb
OUT=/var/backups/mongodb/$(date -u +%Y%m%dT%H%M%S)
mongodump --quiet --host 127.0.0.1 -u marketplaceAdmin -p "$ROOT_PW" --authenticationDatabase admin \
--db appdb --out "$OUT"
ls "$OUT/appdb"
Expected output:
devices.bson devices.metadata.json prelude.json
Each run writes one directory named with the UTC time, holding a BSON file and a metadata file per collection, plus a prelude.json describing the dump. If you also see an older dated directory in /var/backups/mongodb from the image build, it holds only sample documents and you can delete it.
To restore a dump into a new database (here restored), leaving appdb untouched:
mongorestore --host 127.0.0.1 -u marketplaceAdmin -p "$ROOT_PW" --authenticationDatabase admin \
--nsInclude 'appdb.*' --nsFrom 'appdb.*' --nsTo 'restored.*' "$OUT" 2>&1 | tail -1
It ends with 3 document(s) restored successfully. 0 document(s) failed to restore. for the example collection. In a new shell, set OUT to the dump directory you want to restore. Add --drop to replace an existing collection. In production, run mongodump from cron or a systemd timer, copy each dump to Azure Blob Storage or another durable location, and keep as many as your recovery point objective needs. The full flag reference is at https://www.mongodb.com/docs/database-tools/mongorestore/.
Step 9: Connect Your Applications
Applications on the same virtual network connect to the private IP address in the credentials file (host=), on port 27017, as the marketplace user:
mongodb://marketplace:<app-password>@<private-ip>:27017/appdb?authSource=appdb
Allow port 27017 in the virtual machine's network security group from your application subnets only. For example, for an application subnet of 10.0.1.0/24:
az network nsg rule create --resource-group myResourceGroup --nsg-name my-ssh-only-nsg \
--name allow-mongodb-app-subnet --priority 110 --protocol Tcp --destination-port-ranges 27017 \
--source-address-prefixes 10.0.1.0/24 --access Allow
Never allow 27017 from the internet. Until you add TLS (Step 10), traffic on 27017 is not encrypted, so keep it on your private network. Every mainstream language has an official MongoDB driver (Node.js, Python, Java, C#, Go, Rust and more) that accepts this connection string; MongoDB Compass connects with it too, through an SSH tunnel or from a host on the virtual network.
Step 10: Enable TLS for the Wire Protocol
The image does not configure TLS. To require it, put your server certificate and key in one PEM file that the mongodb user can read (a certificate from your internal certificate authority, with your server's private DNS name in its subject alternative names), then edit the net section of /etc/mongod.conf:
net:
port: 27017
bindIp: 0.0.0.0
tls:
mode: requireTLS
certificateKeyFile: /etc/ssl/mongodb.pem
CAFile: /etc/ssl/internal-ca.pem
Restart with sudo systemctl restart mongod. Clients then connect with tls=true (for mongosh, --tls --tlsCAFile /etc/ssl/internal-ca.pem --host <private-dns-name>). MongoDB's TLS options, including preferTLS for a gradual move, are described at https://www.mongodb.com/docs/manual/tutorial/configure-ssl/.
Step 11: Plan a Replica Set for High Availability
The image runs a standalone server: replication.replSetName is not set, so there is no automatic failover. For high availability, run a replica set of at least three members, for example in different availability zones. Deploy two more virtual machines from this image, set the same replication.replSetName in each /etc/mongod.conf, configure keyfile authentication between the members, restart mongod on each, and run rs.initiate() once from mongosh on the intended primary. MongoDB's procedure is at https://www.mongodb.com/docs/manual/tutorial/deploy-replica-set-with-keyfile-access-control/. A replica set is also what MongoDB's change streams need.
Step 12: Security Hardening and Updates
Keep MongoDB and Ubuntu up to date. Ubuntu's unattended upgrades apply Ubuntu security updates automatically. MongoDB 8.0 patch releases come from the MongoDB apt repository already configured on the image; check for and apply them in a maintenance window:
sudo apt-get update
apt-cache policy mongodb-org | head -3
sudo apt-get install --only-upgrade mongodb-org
sudo systemctl restart mongod
Upgrading to a new major version (for example 8.0 to the next release) follows MongoDB's own upgrade procedure, including the feature compatibility version: see https://www.mongodb.com/docs/manual/release-notes/.
Rotate the generated passwords if your policy requires it. For the administrator:
NEW_ROOT_PW=$(openssl rand -base64 48 | tr -d '=+/' | cut -c1-32)
mongosh --quiet --host 127.0.0.1 -u marketplaceAdmin -p "$ROOT_PW" --authenticationDatabase admin admin \
--eval "db.changeUserPassword('marketplaceAdmin', '$NEW_ROOT_PW')"
sudo sed -i "s|^root\.password=.*|root.password=$NEW_ROOT_PW|" /stage/scripts/mongodb-credentials.log
ROOT_PW=$NEW_ROOT_PW
The old password stops working at once. The example connection strings in the file's comments still carry the original passwords, so edit or delete those lines too (sudo nano /stage/scripts/mongodb-credentials.log). Rotate the application user the same way, as marketplaceAdmin, with db.getSiblingDB('appdb').changeUserPassword('marketplace', ...), update app.password=, and update your applications.
Use the least privileged user. marketplaceAdmin holds the root role. Use marketplace, or users you create for each application and database, for day to day work, and keep marketplaceAdmin for administration. If you don't use the marketplace user, drop it:
mongosh --quiet --host 127.0.0.1 -u marketplaceAdmin -p "$ROOT_PW" --authenticationDatabase admin appdb \
--eval 'db.dropUser("marketplace")'
Restrict 27017 at the network edge. Allow it only from the application subnets that need it (Step 9), or put the server behind a private endpoint.
Watch the log. /var/log/mongodb/mongod.log records connections, authentication failures and slow operations. Ship it to Azure Monitor or your SIEM with the Azure Monitor Agent. The Enterprise audit log is not part of MongoDB Community.
Encrypt sensitive fields. Client side field level encryption and Queryable Encryption encrypt fields in the driver, with keys held in a key management service such as Azure Key Vault: see https://www.mongodb.com/docs/manual/core/queryable-encryption/.
Step 13: Where to Go Next
- MongoDB manual: https://www.mongodb.com/docs/manual/
- MongoDB 8.0 release notes: https://www.mongodb.com/docs/manual/release-notes/8.0/
- Drivers: https://www.mongodb.com/docs/drivers/
- MongoDB Compass, the official GUI: https://www.mongodb.com/docs/compass/
Support
cloudimg provides 24/7/365 technical support for this image, with a guaranteed response within 24 hours. Contact support@cloudimg.co.uk.
MongoDB is a registered trademark of MongoDB, Inc. This image is a repackaged upstream distribution provided by cloudimg. Additional charges apply for build, maintenance, and 24/7 support.