Search code examples
mongodbdockernginxdocker-composemongo-express

404 not found when retrieving Mongo Express resources inside Docker container, using Nginx proxy


I have a Docker environment containing numerous containers for web, api, mongodb, mongo express and nginx. My goal is to use Nginx to forward traffic onto the correct services. At the moment I have things working so that if i navigate to localhost/api the api appears with a message, same works for web. But if i navigate to localhost/mongo-express the service loads but the resources that mongo-express try to retrieve are all 404 not found: 404 not found shown in console

I'm fairly new to Docker and completely new to Nginx and learning how it works. Here is my docker-compose file: version: '3'

services:
  # Web App Container
  web:
    build:
      context: web
    container_name: web
    networks:
      - mynetwork

  # API Container
  api:
    build:
      context: api
    container_name: api
    networks:
      - mynetwork

  # Nginx Container
  nginx:
    image: nginx:1.21-alpine
    container_name: nginx
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
    ports:
      - "80:80"
      - "403:403"
    depends_on:
      - web
      - api
      - mongodb
      - mongo-express
    networks:
      - mynetwork

  # Mongodb Container
  mongodb:
    image: mongo
    container_name: mongodb
    restart: always
    environment:
      MONGO_INITDB_ROOT_USERNAME: root
      MONGO_INITDB_ROOT_PASSWORD: root
    volumes:
      - mongodb_data:/data/db
    networks:
      - mynetwork

  # Mongo Express Container
  mongo-express:
    image: mongo-express
    container_name: mongo-express
    restart: always
    environment:
      ME_CONFIG_MONGODB_ADMINUSERNAME: admin
      ME_CONFIG_MONGODB_ADMINPASSWORD: admin
      ME_CONFIG_MONGODB_URL: mongodb://root:root@mongodb:27017/
    depends_on:
      - mongodb
    networks:
      - mynetwork

volumes:
  mongodb_data:

networks:
  mynetwork:

And here is my Nginx config file:

# nginx.conf

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
    worker_connections 1024;
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log /var/log/nginx/access.log main;

    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;

    server {
        listen 80;
        server_name example.com www.example.com;

        location / {
            proxy_pass http://web:8080/;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }

        location /api/ {
            rewrite ^/api(/.*)$ $1 break;
            proxy_pass http://api:3000/;
            # Additional proxy settings for the API if needed
        }

        location /mongo-express/ {
            rewrite ^/mongo-express(/.*)$ $1 break;
            proxy_pass http://mongo-express:8081/;
            # Additional proxy settings for Mongo Express if needed
        }

        location /mongodb/ {
            rewrite ^/mongodb(/.*)$ $1 break;
            proxy_pass http://mongodb:27017/;
            # Additional proxy settings for MongoDB if needed
        }

        error_page 404 /404.html/;
        location = /40x.html/ {
        }

        error_page 500 502 503 504 /50x.html/;
        location = /50x.html/ {
        }
    }
}

I was expecting the files being retrieved with mongo-express to resolve no problem due to the reverse proxy. I've tried tweaking the nginx config and docker-compose file by altering the location, setting ME_CONFIG_SITE_BASEURL: mongo-express in the docker-compose file, but nothing has worked for me.

I'm after not just a solution but for information to really help me understand why this is happening.


Solution

  • In your Nginx configuration, any URL that starts with /mongo-express/ is forwarded to the mongo-express container. That container constructs its own URLs, using absolute URL paths, and it isn't immediately aware of that path prefix, so it's generating URLs that start with just e.g. /public/..., without that prefix.

    The Docker Hub mongo-express image has a specific configuration setting for this

    ME_CONFIG_SITE_BASEURL (default /): Set the baseUrl to ease mounting at a subdirectory. Remember to include a leading and trailing slash.

    So you need to make sure to include this in that container's environment: settings.

    services:
      mongo-express:
        environment:
          ME_CONFIG_SITE_BASEURL: /mongo-express/
    

    The specific setting for this winds up being application- and framework-specific; there is not a universal answer that works for all containers. For your own application code, if it's possible to use only a relative URL <img src="assets/test.png"> this avoids the problem entirely, but with standard packaging tools like Webpack this can wind up being a little bit out of your control.