node.jsmongodbdockerexpressdocker-compose

MongoDB Authentication Issues with Node.js and Mongo-Express in Docker Compose setup


I was trying to use docker in a project I built a while back and I'm having trouble with MongoDB authentication when using Docker Compose. Here's my docker-compose.yml:

services:
  web:
    build: .
    ports:
      - "${PORT}:${PORT}"
    environment:
      - PORT=${PORT}
      - CONNECTION_STRING=${CONNECTION_STRING}
      - ACCESS_TOKEN_SECRET=${ACCESS_TOKEN_SECRET}
    depends_on:
      - mongo
  mongo:
    image: mongo:latest
    ports:
      - "27017:27017"
    volumes:
      - ./data:/data/db
    environment:
      - MONGO_INITDB_ROOT_USERNAME=${MONGO_INITDB_ROOT_USERNAME}
      - MONGO_INITDB_ROOT_PASSWORD=${MONGO_INITDB_ROOT_PASSWORD}

  mongo-express:
    image: mongo-express
    ports:
      - 8081:8081
    environment:
      - ME_CONFIG_MONGODB_SERVER=mongo
      - ME_CONFIG_MONGODB_ADMINUSERNAME=${MONGO_INITDB_ROOT_USERNAME}
      - ME_CONFIG_MONGODB_ADMINPASSWORD=${MONGO_INITDB_ROOT_PASSWORD}

The Dockerfile for building the web-app image is:

FROM node:20-alpine3.19

WORKDIR /usr/src/app

COPY package*.json ./

RUN npm install

COPY . .

EXPOSE 5001

CMD ["npm", "run", "start"]

The .env file used is:

PORT=5001

CONNECTION_STRING=mongodb://admin:adminpassword@mongo:27017/key_ring_backend_3

MONGO_INITDB_ROOT_USERNAME=admin
MONGO_INITDB_ROOT_PASSWORD=adminpassword

The mongo runs without any problem, but the web app and mongo-express can't connect to the mongo.

The web app gives the following error:

2024-06-27 06:34:30 
2024-06-27 06:34:30 > key_ring_backend_api@1.0.0 start
2024-06-27 06:34:30 > node ./src/server.js
2024-06-27 06:34:30 
2024-06-27 06:34:30 Server running on port 5001
2024-06-27 06:34:43 Error: MongoServerError: Authentication failed.

Mongo-express gives the following error

2024-06-27 06:34:40 Welcome to mongo-express 1.0.2
2024-06-27 06:34:40 ------------------------
2024-06-27 06:34:30 /docker-entrypoint.sh: connect: Connection refused
2024-06-27 06:34:30 /docker-entrypoint.sh: line 15: /dev/tcp/mongo/27017: Connection refused
2024-06-27 06:34:31 /docker-entrypoint.sh: connect: Connection refused
2024-06-27 06:34:31 /docker-entrypoint.sh: line 15: /dev/tcp/mongo/27017: Connection refused
2024-06-27 06:34:32 /docker-entrypoint.sh: connect: Connection refused
2024-06-27 06:34:32 /docker-entrypoint.sh: line 15: /dev/tcp/mongo/27017: Connection refused
2024-06-27 06:34:33 /docker-entrypoint.sh: connect: Connection refused
2024-06-27 06:34:33 /docker-entrypoint.sh: line 15: /dev/tcp/mongo/27017: Connection refused
2024-06-27 06:34:34 /docker-entrypoint.sh: connect: Connection refused
2024-06-27 06:34:34 /docker-entrypoint.sh: line 15: /dev/tcp/mongo/27017: Connection refused
2024-06-27 06:34:35 /docker-entrypoint.sh: connect: Connection refused
2024-06-27 06:34:35 /docker-entrypoint.sh: line 15: /dev/tcp/mongo/27017: Connection refused
2024-06-27 06:34:36 /docker-entrypoint.sh: connect: Connection refused
2024-06-27 06:34:36 /docker-entrypoint.sh: line 15: /dev/tcp/mongo/27017: Connection refused
2024-06-27 06:34:37 /docker-entrypoint.sh: connect: Connection refused
2024-06-27 06:34:37 /docker-entrypoint.sh: line 15: /dev/tcp/mongo/27017: Connection refused
2024-06-27 06:34:38 /docker-entrypoint.sh: connect: Connection refused
2024-06-27 06:34:38 /docker-entrypoint.sh: line 15: /dev/tcp/mongo/27017: Connection refused
2024-06-27 06:34:39 /docker-entrypoint.sh: connect: Connection refused
2024-06-27 06:34:39 /docker-entrypoint.sh: line 15: /dev/tcp/mongo/27017: Connection refused
2024-06-27 06:34:43 Could not connect to database using connectionString: mongodb://admin:****@mongo:27017/"
2024-06-27 06:34:43 /app/node_modules/mongodb/lib/cmap/connection.js:227
2024-06-27 06:34:43                     callback(new error_1.MongoServerError(document));
2024-06-27 06:34:43                              ^
2024-06-27 06:34:43 
2024-06-27 06:34:43 MongoServerError: Authentication failed.
2024-06-27 06:34:43     at Connection.onMessage (/app/node_modules/mongodb/lib/cmap/connection.js:227:30)
2024-06-27 06:34:43     at MessageStream.<anonymous> (/app/node_modules/mongodb/lib/cmap/connection.js:60:60)
2024-06-27 06:34:43     at MessageStream.emit (node:events:517:28)
2024-06-27 06:34:43     at processIncomingData (/app/node_modules/mongodb/lib/cmap/message_stream.js:125:16)
2024-06-27 06:34:43     at MessageStream._write (/app/node_modules/mongodb/lib/cmap/message_stream.js:33:9)
2024-06-27 06:34:43     at writeOrBuffer (node:internal/streams/writable:392:12)
2024-06-27 06:34:43     at _write (node:internal/streams/writable:333:10)
2024-06-27 06:34:43     at Writable.write (node:internal/streams/writable:337:10)
2024-06-27 06:34:43     at Socket.ondata (node:internal/streams/readable:809:22)
2024-06-27 06:34:43     at Socket.emit (node:events:517:28) {
2024-06-27 06:34:43   ok: 0,
2024-06-27 06:34:43   code: 18,
2024-06-27 06:34:43   codeName: 'AuthenticationFailed',
2024-06-27 06:34:43   connectionGeneration: 7,
2024-06-27 06:34:43   [Symbol(errorLabels)]: Set(2) { 'HandshakeError', 'ResetPool' }
2024-06-27 06:34:43 }
2024-06-27 06:34:43 
2024-06-27 06:34:43 Node.js v18.20.3
2024-06-27 06:34:40 
2024-06-27 06:34:40

Everything worked fine when I didn't pass the user and password data like following:

services:
  web:
    build: .
    ports:
      - "${PORT}:${PORT}"
    environment:
      - PORT=${PORT}
      - CONNECTION_STRING=${CONNECTION_STRING}
      - ACCESS_TOKEN_SECRET=${ACCESS_TOKEN_SECRET}
    depends_on:
      - mongo
  mongo:
    image: mongo:latest
    ports:
      - "27017:27017"
    volumes:
      - ./data:/data/db

  mongo-express:
    image: mongo-express
    ports:
      - 8081:8081

The .env was also like:

CONNECTION_STRING=mongodb://mongo:27017/key_ring_backend_3

I don't have any issues when working this way during development. But is it okay to create a mongo server without setting root user and password during production. Or should I not create a mongo server in this way using docker and instead use something like the online mongodb service.


Solution

  • So I found the issue. For the mongo connection I added the volume as

    volumes:
      - ./data:/data/db
    

    When the using docker-compose and creating the containers, mongo initializes it's admin using the values provided the first time the docker-compose up command is run.

    In my case I had run the docker-compose.yml file initially without setting any MONGO_INITDB_ROOT_USERNAME and MONGO_INITDB_ROOT_PASSWORD. This caused the admin db to be empty without any users. This meant that I wouldn't even be able to run commands like db.getUsers() even in the mongosh.

    Now even if I add MONGO_INITDB_ROOT_USERNAME and MONGO_INITDB_ROOT_PASSWORD to the docker-compose.yml and run it, it won't be added to the admin db because the volume I set took only the values that was used during the first time it was initialised.

    Fix:

    I deleted the data directory from my local system , deleted the running containers and ran the docker-compose.yml file after setting MONGO_INITDB_ROOT_USERNAME and MONGO_INITDB_ROOT_PASSWORD values. This fixed things.