1

Goal

Access minio server via subdomain from Django server in docker environment (both minio server and Django server are behind nginx proxy)

Expected result: Django can access minio server using the subdomain specified in nginx.

I can successfully open the minio console via s3-console.localhost

Problem

Django service can't connect properly. Docker logs:

api    | Traceback (most recent call last):
api    |   File "manage.py", line 22, in <module>
api    |     main()
api    |   File "manage.py", line 18, in main
api    |     execute_from_command_line(sys.argv)
api    |   File "/usr/local/lib/python3.8/site-packages/django/core/management/__init__.py", line 446, in execute_from_command_line
api    |     utility.execute()
api    |   File "/usr/local/lib/python3.8/site-packages/django/core/management/__init__.py", line 386, in execute        
api    |     settings.INSTALLED_APPS
api    |   File "/usr/local/lib/python3.8/site-packages/django/conf/__init__.py", line 87, in __getattr__
api    |     self._setup(name)
api    |   File "/usr/local/lib/python3.8/site-packages/django/conf/__init__.py", line 74, in _setup
api    |     self._wrapped = Settings(settings_module)
api    |   File "/usr/local/lib/python3.8/site-packages/django/conf/__init__.py", line 183, in __init__
api    |     mod = importlib.import_module(self.SETTINGS_MODULE)
api    |   File "/usr/local/lib/python3.8/importlib/__init__.py", line 127, in import_module
api    |     return _bootstrap._gcd_import(name[level:], package, level)
api    |   File "<frozen importlib._bootstrap>", line 1014, in _gcd_import
api    |   File "<frozen importlib._bootstrap>", line 991, in _find_and_load
api    |   File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked
api    |   File "<frozen importlib._bootstrap>", line 671, in _load_unlocked
api    |   File "<frozen importlib._bootstrap_external>", line 843, in exec_module
api    |   File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
api    |   File "/code/ezevent_api/settings.py", line 235, in <module>
api    |     found = client.bucket_exists(AWS_STORAGE_BUCKET_NAME)
api    |   File "/usr/local/lib/python3.8/site-packages/minio/api.py", line 658, in bucket_exists
api    |     self._execute("HEAD", bucket_name)
api    |   File "/usr/local/lib/python3.8/site-packages/minio/api.py", line 400, in _execute
api    |     region = self._get_region(bucket_name, None)
api    |   File "/usr/local/lib/python3.8/site-packages/minio/api.py", line 467, in _get_region
api    |     response = self._url_open(
api    |   File "/usr/local/lib/python3.8/site-packages/minio/api.py", line 311, in _url_open
api    |     raise InvalidResponseError(
api    | minio.error.InvalidResponseError: non-XML response from server; Response code: 500, Content-Type: text/html; charset=UTF-8, Body: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 
api    | <html><head>
api    | <title>Revive Adserver</title>
api    | <meta name="generator" content="Revive Adserver v5.2.1 - http://www.revive-adserver.com">
api    | <meta name="robots" content="noindex, nofollow">
api    | <meta http-equiv="X-UA-Compatible" content="IE=7">
api    | <link rel="shortcut icon" type="image/vnd.microsoft.icon" href="https://a03.uadexchange.com/admin/assets/images/favicon.ico" />
api    | 
api    |     <link rel="stylesheet" type="text/css" href="https://a03.uadexchange.com/admin/assets/min.php?g=oxp-css-ltr&amp;v=5.2.1">
api    | 
api    | 
api    | <script type="text/javascript">
api    | <!--
api    |     var validatorPreferences = {
api    |         'strFieldContainsErrors': "The following fields contain errors:",
api    |         'strFieldFixBeforeContinue1': "Before you can continue you need",
api    |         'strFieldFixBeforeContinue2': "to correct these errors.",
api    |         'strWarningMissing': "Warning, possibly missing ",
api    |         'strWarningMissingOpening': " opening tag \'<\'",
api    |         'strWarningMissingClosing': " closing tag \'>\'",
api    |         'strSubmitAnyway': "Submit Anyway",
api    |         'thousandsSeperator': ","
api    |     };
api    | 
api    |        var tablePreferences = {
api    |                'warningBeforeDelete': false
api    |     };
api    | //-->
api    | </script>
api    | <script type="text/javascript" src="https://a03.uadexchange.com/admin/assets/min.php?g=oxp-js&amp;v=5.2.1"></script>
api    | 
api    | 
api    | 
api    | 
api    | 
api    | 
api    | 
api    | 
api    | </head>
api    | <body class="hasInterface hasGradient hasSidebar " onload="initPage();">
api    | 
api    | 
api    | 
api    | 
api    | <div id="oaHeader">
api    | 
api    |     <div id="oaHeaderBranding" class="brandingAdServer">Revive Adserver</div>
api    |   <div id="oaNavigationExtraTop">
api    |     <ul>
api    | 
api    | 
api    | 
api    | 
api    | 
api    |     </ul>
api    |     </div>
api    | 
api    | 
api    | </div>
api    | 
api    | <div id="oaNavigation">
api    |     <ul id="oaNavigationTabs">
api    |       <li class="active  first last">
api    |         <div class="left"><div class="right">
api    |           <a href="https://a03.uadexchange.com/admin/index.php" accesskey="Home">Authentication</a>
api    |         </div></div>
api    |       </li>
api    |     </ul>
api    |
api    | </div>
api    |
api    | <div id="firstLevelContent">
api    |
api    |
api    | <div id="secondLevelContent">

Context

nginx.config

user  nginx;
events {
  worker_connections   1000;
}

http {
  server {
    server_name api.lamanin.com api.localhost;
    location / {
      proxy_pass http://api:8000;
    }
  }
  server {
    server_name s3.lamanin.com s3.localhost;
    listen 80;
    location / {
       proxy_pass http://s3:9000;
       proxy_http_version 1.1;
       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;
    }
  }
  server {
    server_name s3-console.lamanin.com s3-console.localhost;
    listen 80;
    location / {
      proxy_pass http://s3:9090;
    }
  }
  server {
    server_name lamanin.com *.lamanin.com localhost *.localhost;
    listen 80;

    location / {
      proxy_pass http://web:3000;
    }
    
    location /ws {
      proxy_pass http://web:3000;
      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "Upgrade";
    }
  }
}

docker-compose.yml

version: "3.8"

services:
  s3:
    image: minio/minio
    container_name: s3
    restart: on-failure
    ports:
      - "9000:9000"
      - "9090:9090"
    volumes:
      - s3:/data
    environment:
      - MINIO_ROOT_USER=${MINIO_ROOT_USER}
      - MINIO_ROOT_PASSWORD=${MINIO_ROOT_PASSWORD}
    command: server --console-address :9090 --address :9000 /data
  web:
    image: lamanin/web
    container_name: web
    environment:
      - WDS_SOCKET_PORT=${WDS_SOCKET_PORT}
      - ESLINT_NO_DEV_ERRORS=${ESLINT_NO_DEV_ERRORS}
      - REACT_APP_API_URL=${REACT_APP_API_URL}
      - REACT_APP_SHOW_COMING_SOON=${REACT_APP_SHOW_COMING_SOON}
    build:
      context: ./web
      dockerfile: Dockerfile.${ENVIRONMENT}
    restart: on-failure
    volumes:
      - web:/app/src
    ports:
      - "${WEB_PORT}"
    depends_on:
      - api
  db:
    image: postgres
    container_name: "db"
    hostname: "db"
    volumes:
      - db:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=${POSTGRES_DB}
      - POSTGRES_USER=${POSTGRES_USER}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
  api:
    image: lamanin/api
    environment:
      - SECRET_KEY=${SECRET_KEY}
      - POSTGRES_DB=${POSTGRES_DB}
      - POSTGRES_USER=${POSTGRES_USER}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
      - DJANGO_SUPERUSER_USERNAME=${DJANGO_SUPERUSER_USERNAME}
      - DJANGO_SUPERUSER_PASSWORD=${DJANGO_SUPERUSER_PASSWORD}
      - MINIO_URL=${MINIO_URL}
      - MINIO_DOMAIN=${MINIO_DOMAIN}
      - MINIO_SA_ACCESS_KEY=${MINIO_SA_ACCESS_KEY}
      - MINIO_SA_SECRET_KEY=${MINIO_SA_SECRET_KEY}
      - API_URL=${API_URL}
    container_name: api
    build:
      context: ./api
    restart: on-failure
    command: >
      sh -c "sleep 10 && python3 manage.py collectstatic --no-input &&
            python3 manage.py migrate &&
            python3 manage.py ensure_admin &&
            python3 manage.py runserver 0.0.0.0:8000"
    volumes:
      - api:/code
    ports:
      - "${API_PORT}"
    depends_on:
      - db
      - s3
  nginx:
    build:
      context: .
      dockerfile: Dockerfile.nginx
    container_name: "nginx"
    restart: on-failure
    depends_on:
      - api
      - web
      - s3
    ports:
      - "80:80"

volumes:
  api:
  web:
  db:
  s3:

Relevant Django settings

AWS_ACCESS_KEY_ID = os.getenv('MINIO_SA_ACCESS_KEY')
AWS_SECRET_ACCESS_KEY = os.getenv('MINIO_SA_SECRET_KEY')
AWS_STORAGE_BUCKET_NAME = 'main'
AWS_S3_ENDPOINT_URL = os.getenv('MINIO_URL')

AWS_S3_OBJECT_PARAMETERS = {
    'CacheControl': 'max-age=86400',
}

AWS_STATIC_LOCATION = 'static'
STATICFILES_STORAGE = 'ezevent_api.storage_backends.StaticStorage'
STATIC_URL = f'{AWS_S3_ENDPOINT_URL}/{AWS_STORAGE_BUCKET_NAME}/'

AWS_PUBLIC_MEDIA_LOCATION = 'media/public'
DEFAULT_FILE_STORAGE = 'ezevent_api.storage_backends.PublicMediaStorage'

AWS_PRIVATE_MEDIA_LOCATION = 'media/private'
PRIVATE_FILE_STORAGE = 'ezevent_api.storage_backends.PrivateMediaStorage'

client = Minio(
    os.getenv('MINIO_DOMAIN'),
    access_key=AWS_ACCESS_KEY_ID,
    secret_key=AWS_SECRET_ACCESS_KEY,
    secure=os.getenv('MINIO_SECURE') == 'True'
)

found = client.bucket_exists(AWS_STORAGE_BUCKET_NAME)
if not found: client.make_bucket(AWS_STORAGE_BUCKET_NAME)

Relevant Environment Variables

MINIO_URL=http://s3.localhost
MINIO_DOMAIN=s3.localhost
MINIO_ROOT_USER=admin
MINIO_ROOT_PASSWORD=[REDACTED]
MINIO_SA_ACCESS_KEY=service-account-1
MINIO_SA_SECRET_KEY=[REDACTED]
MINIO_SECURE=False

Relevant Packages

https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html

Things I Have Tried

  1. Initially I didn't use any headers in the proxy settings, so I added several headers that I found from this github thread: https://github.com/minio/minio/issues/7661.

  2. I suspected that the http://s3:9000 address isn't recognized by nginx so I used http://localhost:9000 but the localhost of nginx is probably different from the s3 service because they are in different containers.

  3. When running the s3 & nginx service using docker, and running the Django server outside of docker (running it manually using the python manage.py runserver command) it successfully connect's to the minio server if localhost:9000 is used. But failes if the subdomain http://s3.localhost is used.

Greennerd
  • 11
  • 1
  • 2
  • 1
    I solved this by accessing minio directly using the docker network via `http://s3:9000`. I couldn't make this to work using the proxy. – Greennerd Jul 26 '22 at 12:55

0 Answers0