Skip to content

How to Run MongoDB in Docker: Authentication, Volumes, Compose and Backups

4 min read

Applies to: the official mongo Docker image, tested with mongo:8 (MongoDB 8.3.11, mongosh 2.11.1, database tools 100.18.0) on Docker Engine 29.1.3 (arm64)

To run MongoDB in Docker, start the official mongo image with a root user, a named volume for the data and the port published only on the server itself:

docker volume create mongo-data
docker run -d --name mongo --restart unless-stopped \
  -p 127.0.0.1:27017:27017 \
  -v mongo-data:/data/db \
  -e MONGO_INITDB_ROOT_USERNAME=admin \
  -e MONGO_INITDB_ROOT_PASSWORD='S3cret-Pass' \
  mongo:8

Then check that it answers:

$ docker exec mongo mongosh --quiet -u admin -p 'S3cret-Pass' --eval 'db.runCommand({ping:1})'
{ ok: 1 }

The image includes the mongosh shell and the database tools (mongodump, mongorestore), so you don’t need to install anything else on the server. If Docker isn’t installed yet, see how to install Docker on Debian and Ubuntu.

Which tag to use

At the time of writing, mongo:8 and mongo:latest point to MongoDB 8.3.11, mongo:8.0 to 8.0.32 and mongo:7 to 7.0.43. Pin the version your application supports (for example mongo:8.0) so that pulling a new image never jumps to another release series by surprise. The image is available for amd64 and arm64.

Three things to know before you start

  1. Without the two MONGO_INITDB_ROOT_ variables there is no password at all. The image documentation says the default configuration “requires no authentication for access”. In our test, a container started without them listed its databases to anyone who connected.
  2. Publish the port on 127.0.0.1. -p 27017:27017 alone publishes it on every address (docker port showed 0.0.0.0:27017 and [::]:27017). Docker also notes that traffic to published ports is diverted before it reaches UFW rules, so a UFW firewall won’t protect it. Applications in containers on the same user-defined network (for example, services in the same Compose project) reach MongoDB by its name without any published port. On Docker’s default network the name doesn’t resolve: we got getaddrinfo ENOTFOUND.
  3. The variables only work on the first start. They create the root user when /data/db is empty. We recreated the container on the same volume with a new MONGO_INITDB_ROOT_PASSWORD: the new password failed with MongoServerError: Authentication failed. and the old one still worked. Change passwords inside MongoDB instead.

Create a user for your application

Don’t let the application use the root account. Create a user that can only read and write its own database:

$ docker exec mongo mongosh --quiet -u admin -p 'S3cret-Pass' --eval \
  'db.getSiblingDB("shop").createUser({user:"shopapp", pwd:"App-Pass-1", roles:[{role:"readWrite", db:"shop"}]})'
{ ok: 1 }

The application then connects with:

mongodb://shopapp:App-Pass-1@127.0.0.1:27017/shop

A user is stored in the database where you created it. The root user lives in admin, so when you connect as root to another database, add ?authSource=admin. Without it we got Authentication failed. even with the right password:

mongodb://admin:S3cret-Pass@127.0.0.1:27017/shop?authSource=admin

The same with Docker Compose

This keeps the root password in a file instead of the command line, using the image’s _FILE variant, and adds a health check:

services:
  mongo:
    image: mongo:8
    restart: unless-stopped
    ports:
      - "127.0.0.1:27017:27017"
    environment:
      MONGO_INITDB_ROOT_USERNAME: admin
      MONGO_INITDB_ROOT_PASSWORD_FILE: /run/secrets/mongo_root_password
    secrets:
      - mongo_root_password
    volumes:
      - mongo-data:/data/db
    healthcheck:
      test: ["CMD", "mongosh", "--quiet", "--eval", "db.adminCommand('ping').ok"]
      interval: 10s
      timeout: 5s
      retries: 5
volumes:
  mongo-data:
secrets:
  mongo_root_password:
    file: ./mongo_root_password.txt

Put the password in mongo_root_password.txt, run chmod 600 on it and start with docker compose up -d. After about 15 seconds docker compose ps showed the service as Up (healthy). If it doesn’t start, read the Compose logs. Note that docker compose down -v deletes the volume and all data.

Back up and restore

Stream a compressed dump out of the container into a file on the server:

docker exec mongo mongodump -u admin -p 'S3cret-Pass' --authenticationDatabase admin \
  --db shop --archive --gzip > shop.archive.gz

Restore it the same way, with -i so the file reaches the container:

$ docker exec -i mongo mongorestore -u admin -p 'S3cret-Pass' --authenticationDatabase admin \
  --archive --gzip < shop.archive.gz
1 document(s) restored successfully. 0 document(s) failed to restore.

Copy the dump to another machine as well.

Memory

According to MongoDB, its WiredTiger cache uses by default the larger of 50% of (RAM minus 1 GB) or 256 MB, and it may not notice a container memory limit. If you limit the container with --memory, set the cache size yourself by adding the option after the image name:

docker run -d --name mongo --memory 1g ... mongo:8 --wiredTigerCacheSizeGB 0.25

In our test, db.serverStatus().wiredTiger.cache then reported a maximum of 256 MB. On a KVM VPS you have full root access, so you can size Docker and MongoDB to the plan’s RAM.

Official documentation: mongo image documentation and Docker packet filtering and firewalls.

Was this answer helpful?

Still stuck? Open a ticket