MinIO Console Behind a Nginx Reverse Proxy

Feb 19, 2023

Lately, I was playing around with MinIO, an open-source Object Storage, that can also be self-hosted. Basically, it’s S3 in open source.

Getting started is fairly easy: Just run it in a Docker container:

docker run --rm -v $PWD:/data -p 9000:9000 -p 9001:9001 -it minio/minio server --address ":9000" --console-address ":9001" /data

This line will create a new MinIO container, save all data in ./data (on the host machine), makes the Object Storage available on port 9000, the web-based console on http://localhost:9001, and uses /data as storage for all data within the container. --rm will delete the container again when it’s exited (with control + C). But no worries, you can continue where you left off with the exact same command because everything is stored in ./data. The console is also quite self-explanatory. Just open http://localhost:9001 and login with minioadmin as username and password.

One Port

So far so good. I want to host such a MinIO Object Storage on a server. I don’t want to expose multiple ports (here 9000 and 9001), but ideally only port 80. A master-reverse-proxy is already in place that takes care of proxying the right hosts to the right containers. However, it has one limitation: only one host per container is allowed.

Naively trying to just use the same port for --address and --console-address leads to this concise error:

ERROR Unable to start the server: --console-address cannot be same as --address

A little variation --address ":80" --console-address ":80/console", also doesn’t help:

ERROR Unable to split host port :80/console: invalid port number

That’s a pity, but understandable.

More Reverse-Proxies

My solution is to let the master-reverse-proxy connect to port 9000 of the MinIO container, and create a second reverse-proxy that is connected to port 9001 of the MinIO container (the console). Then the master-reverse-proxy can either forward to the MinIO container for the Object Storage itself, or to the console reverse-proxy for the console.

The docker-compose.yml configuration looks like this:

version: "3.9"
    
services: 
  minio.example.com:
    image: minio/minio
    command: server --address ":9000" --console-address ":9001" /data
    container_name: minio_example_com_app
    restart: always
    expose:
      - 9000
      - 9001
    environment:
      - "MINIO_ROOT_USER=admin"
      - "MINIO_ROOT_PASSWORD=my#v3erySECURE_password"
      - "VIRTUAL_HOST=minio.example.com"
      - "VIRTUAL_PORT=9000"
    volumes:
      - minio-data:/data

  minio-console.example.com:
    image: nginx
    restart: always
    expose:
      - 80
    ports:
      - "8082:80" # TODO remove. Allows to access this container via localhost:8082 for testing.
    environment:
      - "VIRTUAL_HOST=minio-console.example.com"
      - "VIRTUAL_PORT=80"
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro"

volumes:
  minio-data:

The nginx.conf, which lives in the same folder as the docker-compose.yml:

server {
  listen 80;
  server_name minio-console.example.com;
  location / {
    proxy_pass http://minio_example_com_app:9001;

    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;
    proxy_set_header Host $http_host;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
    proxy_http_version 1.1;
    chunked_transfer_encoding off;
  }
}

When you run docker compose up --remove-orphans in the folder that contains nginx.conf and docker-compose.yml, you should be able to access the console via http://localhost:8082/.

I first had trouble accessing the “Object Browser” in the console, when it’s behind the reverse-proxy. It only showed an eternal loading indicator and the content of a bucket was never visible. The problem was that the “Object Browser” uses websockets, and the nginx configuration I had before didn’t support that. However, the configuration presented above works for me now.

The master-reverse-proxy is out of scope of this post. But a reverse-proxy like nginxproxy/nginx-proxy) picks up the VIRTUAL_HOST environment varaible, and associates the specified host with the container. With this configuration and the right DNS entries, you should be able to access the MinIO Object Storage using minio.example.com and the console using minio-console.example.com.

I hope this was helpful! It certainly would have for me, before I figured this configuration out. Have fun!

You might also like