The Ultimate MinIO Docker Deployment Guide: From Public Access to Nginx Reverse Proxy Pitfalls

Published: 2026-02-24
Author: DP
Views: 0
Category: Docker
Content
## Background When deploying the MinIO object storage service with Docker, it's common practice to use Nginx as a reverse proxy for domain-based access and HTTPS encryption. However, this seemingly standard procedure hides several configuration pitfalls. This article, based on a complete technical Q&A session, chronicles the entire process from deploying MinIO and configuring public access to resolving a series of cascading issues. DP@lib00 presents this detailed guide to help you navigate the challenges. ### Initial Deployment Command We start with a standard `docker run` command: ```docker docker run -d --name ee_minio --network eeLan --ip 172.18.0.8 \ -p 9000:9000 \ -p 9001:9001 \ -v /data/minio-wiki.lib00/data:/data \ -e "MINIO_ROOT_USER=admin_dp" \ -e "MINIO_ROOT_PASSWORD=admin_dp_password" \ minio/minio server /data --console-address ":9001" ``` At this point, the admin console `s3-admin.lib00.com` (pointing to port 9001) and the API endpoint `s3.lib00.com` (pointing to port 9000) are configured. We successfully uploaded an image, but the first question arose: How do we access it via `https://s3.lib00.com`? --- ## Level 1: Enabling Public File Access By default, buckets in MinIO are private. To access files directly via a URL, the bucket's policy must be set to public. 1. **Log in to the Admin Console**: Visit `https://s3-admin.lib00.com`. 2. **Set Access Policy**: Navigate to the relevant Bucket -> Access Policy and change it to **Public**. After this change, the file access URL format is: `https://s3.lib00.com/<BucketName>/<FileName>`. To ensure MinIO automatically uses the correct domain when generating links, we need to introduce a key environment variable: `MINIO_SERVER_URL`. --- ## Level 2: Fixing Startup Failure Caused by `MINIO_SERVER_URL` Following official advice, we added `-e "MINIO_SERVER_URL=http://s3.lib00.com"`, but the container failed to start, reporting a `301 Moved Permanently` error. **Root Cause**: MinIO performs a health check on `MINIO_SERVER_URL` at startup. Our Nginx configuration enforces an HTTP-to-HTTPS redirect. Consequently, MinIO's `http://` request was redirected with a 301 status, causing the health check to fail. **Solution**: The `MINIO_SERVER_URL` must be the final, public-facing URL that end-users access, complete with the correct protocol. It must be `https`. **Corrected Environment Variable**: `-e "MINIO_SERVER_URL=https://s3.lib00.com"` --- ## Level 3: Correcting Wrong Links Generated by the Admin Console The previous issue was solved, but a new one appeared. When clicking "Share" or "Preview" in the admin console, the generated link still used the admin domain `s3-admin.lib00.com` instead of the desired API domain `s3.lib00.com`. **Root Cause**: `MINIO_SERVER_URL` primarily serves the server backend. The frontend application in the browser (the admin console) needs another specific environment variable to know the correct redirect address for object access. **Solution**: Add the `MINIO_BROWSER_REDIRECT_URL` environment variable and set its value to the API domain. **Corrected Environment Variable**: `-e "MINIO_BROWSER_REDIRECT_URL=https://s3.lib00.com"` --- ## Level 4: Understanding Pre-signed URLs (Long Links) vs. Direct Access URLs (Short Links) With the configuration corrected, clicking the "Share" button yielded a very long URL containing a hash, completely different from the expected `https://s3.lib00.com/test01/a.jpg`. Is this a bug? **Answer: It's not a bug, it's a feature.** * **Pre-signed URL (Long Link)**: Generated via the "Share" button, it creates a secure, expiring access token (default 7 days) for a **private** object. Even if the bucket is private, anyone with this link can access the specific file within its validity period. * **Direct Access URL (Short Link)**: Only available when the bucket policy is **Public**. It is a permanent, clean resource locator. **How to get the short link?** After setting the bucket to **Public**, a "chain" icon will appear below the object name in the object details page. Clicking it copies the short, direct access URL. --- ## Final Boss: Solving the `AccessDenied` Signature Validation Failure The most challenging problem emerged: generated share links (pre-signed URLs) worked only once, after which all new links returned an `AccessDenied` error. **Root Cause**: The `X-Amz-Date` field in the error log revealed the truth: `20251009T190054Z`. The MinIO server's system clock was incorrect! The S3 protocol requires the request timestamp to be within 15 minutes of the server's current time. A future timestamp guarantees signature validation failure. Simply setting a timezone (e.g., `-e TZ=Asia/Shanghai`) is ineffective because it only changes the time's display format, not the underlying absolute UTC time used for calculations. **Solution**: 1. **Correct the Host's System Time**: You must synchronize the system time on the host machine running Docker. ```bash # Using timedatectl (recommended) sudo timedatectl set-ntp true # Or using ntpdate sudo ntpdate ntp.aliyun.com ``` 2. **Set Container Timezone Correctly (Best Practice)**: Ensure container and host timezones are identical by mounting the host's timezone file. `-v /etc/localtime:/etc/localtime:ro` --- ## The Final Deployment Command Incorporating all the fixes, here is the final recommended deployment command from wiki.lib00.com: ```docker docker run -d --name ee_minio --network eeLan --ip 172.18.0.8 \ -p 9000:9000 \ -p 9001:9001 \ -v /data/minio-wiki.lib00/data:/data \ -v /etc/localtime:/etc/localtime:ro \ -e "MINIO_ROOT_USER=admin_dp" \ -e "MINIO_ROOT_PASSWORD=admin_dp_password" \ -e "MINIO_SERVER_URL=https://s3.lib00.com" \ -e "MINIO_BROWSER_REDIRECT_URL=https://s3.lib00.com" \ minio/minio server /data --console-address ":9001" ``` By resolving this series of issues, we not only successfully deployed MinIO but also gained a deep understanding of its core configurations in a reverse proxy environment, its URL mechanisms, and the critical importance of time synchronization.
Related Contents