Connecting LobeChat with MinIO: A Simple Guide to Fixing S3 Path-Style Configuration
Content
## The Problem
When deploying the database version of LobeChat with Docker and integrating MinIO as the S3 storage, many users encounter an issue where files are uploaded successfully, but the generated access URL is incorrect. For instance, the expected URL is `https://s3.wiki.lib00.com/lobechat/filename.png`, but the application generates `https://lobechat.s3.wiki.lib00.com/filename.png`. This problem makes all uploaded files inaccessible.
The user's initial Docker run command looked like this:
```docker
docker run -it -d --name ee-lobe-chat-db-1.142.8 \
-p 3210:3210 \
-e S3_ACCESS_KEY_ID=xyxyxyx \
-e S3_SECRET_ACCESS_KEY=xyxyxyx \
-e S3_ENDPOINT=https://s3.lib00.com \
-e S3_BUCKET=lobechat \
-e S3_PUBLIC_DOMAIN=https://s3.lib00.com \
lobehub/lobe-chat-database:1.142.8
```
---
## Root Cause: Path-Style vs. Virtual-Hosted Style
The core of the issue lies in two different S3 URL addressing modes:
1. **Virtual-Hosted Style**: This is the default and recommended mode for AWS S3. It places the bucket name as part of the domain name. The format is `https://<bucket>.<endpoint>/<object>`. Example: `https://lobechat.s3.lib00.com/image.png`. This mode requires specific DNS configurations (like wildcard certificates and records), which can be complex in self-hosted environments.
2. **Path-Style**: This is the default and most common mode for S3-compatible storage solutions like MinIO and Ceph. It includes the bucket name as part of the URL path. The format is `https://<endpoint>/<bucket>/<object>`. Example: `https://s3.lib00.com/lobechat/image.png`.
The S3 client used internally by LobeChat defaults to the virtual-hosted style, which conflicts with how MinIO typically operates, leading to the incorrect URL generation.
---
## The Solution
To resolve this, we need to force LobeChat's S3 client to use Path-Style URLs. This can be achieved by adding a specific environment variable.
Based on community feedback and verification (credit to user DP@lib00), the correct environment variable is `S3_ENABLE_PATH_STYLE`.
Here is the corrected Docker run command:
```docker
docker run -it -d --name ee-lobe-chat-db-1.142.8 \
-p 3210:3210 \
-e S3_ACCESS_KEY_ID=xyxyxyx \
-e S3_SECRET_ACCESS_KEY=xyxyxyx \
-e S3_ENDPOINT=https://s3.wiki.lib00.com \
-e S3_BUCKET=wiki.lib00-bucket \
-e S3_ENABLE_PATH_STYLE=true \
-e S3_PUBLIC_DOMAIN=https://s3.wiki.lib00.com \
lobehub/lobe-chat-database:1.142.8
```
---
## Key Environment Variables Explained
1. **`-e S3_ENABLE_PATH_STYLE=true`**
* **Purpose**: This is the core of the solution. It explicitly tells the S3 client within LobeChat: "Please use path-style for all S3 URLs." After adding this, both upload and access URLs will follow the `https://<endpoint>/<bucket>/...` format.
* **Note**: In some other applications or older AWS SDKs, the variable `S3_FORCE_PATH_STYLE` might be used. However, for this version of LobeChat, `S3_ENABLE_PATH_STYLE` has been tested and confirmed as the correct choice.
2. **`-e S3_PUBLIC_DOMAIN=https://s3.wiki.lib00.com`**
* **Purpose**: This variable defines the base part of the public-facing domain for your files. LobeChat automatically appends the bucket name and filename to this URL to construct the final access link. The internal logic is: `Final URL = <S3_PUBLIC_DOMAIN>/<S3_BUCKET>/<filename>`.
* Therefore, you **should not** include the bucket name in this variable, as it would lead to a duplicated path, such as `.../lobechat/lobechat/filename.png`.
---
## Conclusion
By simply adding the `S3_ENABLE_PATH_STYLE=true` environment variable, we can easily switch LobeChat's S3 request mode from the default virtual-hosted style to path-style, ensuring perfect compatibility with self-hosted object storage services like MinIO. This small tweak is a crucial step for running LobeChat reliably on your own infrastructure. For more tech insights, follow wiki.lib00.com.
Related Contents
Ultimate Guide to Configuring Model Pricing in CLIProxyAPI: Ratios and Billing Explained
Duration: 00:00 | DP | 2026-07-13 20:23:25Complete Guide to Installing and Configuring Git Server on Synology NAS: Basic to Advanced
Duration: 00:00 | DP | 2026-07-16 20:39:02Why Do .smbdelete Hidden Files Appear After Deleting on Mac SMB Shares? Causes & Ultimate Solutions
Duration: 00:00 | DP | 2026-06-27 19:10:00Complete Guide to Setting Docker Container Timezone to UTC+8 (Asia/Shanghai)
Duration: 00:00 | DP | 2026-06-30 20:43:30Fixing 'Unable to locate package openjdk-17-jdk' in PHP 8 Docker (Debian Trixie)
Duration: 00:00 | DP | 2026-07-25 09:23:18Docker Compose Advanced: Configuring Static IPs and Cross-Container SOCKS5 Proxies
Duration: 00:00 | DP | 2026-07-26 09:28:30Nginx Reverse Proxy Guide: Elegantly Routing Specific Subdirectories to Docker Containers
Duration: 00:00 | DP | 2026-07-26 21:31:06DevOps Practice: How to Safely Clear Logs of a Running Docker Container?
Duration: 00:00 | DP | 2026-07-27 09:33:42Practical Guide: Translating Complex Docker Compose to Docker Run Commands
Duration: 00:00 | DP | 2026-07-29 09:44:07The Ultimate Guide to Docker Cron Logging: Host vs. Container Redirection - Are You Doing It Right?
Duration: 00:00 | DP | 2026-01-05 08:03:52Cron Job Failing? The Ultimate Guide to Fixing 'docker: command not found'
Duration: 00:00 | DP | 2026-08-01 09:59:44The Ultimate 'Connection Refused' Guide: A PHP PDO & Docker Debugging Saga of a Forgotten Port
Duration: 00:00 | DP | 2025-12-03 09:03:20Solving the MySQL Docker "Permission Denied" Error on Synology NAS: A Step-by-Step Guide
Duration: 00:00 | DP | 2025-12-03 21:19:10How Can a Docker Container Access the Mac Host? The Ultimate Guide to Connecting to Nginx
Duration: 00:00 | DP | 2025-12-08 23:57:30Docker Exec Mastery: The Right Way to Run Commands in Containers
Duration: 00:00 | DP | 2026-01-08 08:07:44How to Fix the "tsx: not found" Error During Vue Vite Builds in Docker
Duration: 00:00 | DP | 2026-01-10 08:10:19The Ultimate Guide to Docker Cron Jobs: Effortlessly Scheduling PHP Tasks in Containers from the Host
Duration: 00:00 | DP | 2025-12-29 10:30:50From Phantom Conflicts to Docker Permissions: A Deep Dive into Debugging an Infinite Loop in a Git Hook for an AI Assistant
Duration: 00:00 | DP | 2025-11-09 16:39:00Recommended
Why Encode Hashes with Base64/Base16 After MD5? A Deep Dive into Hashing vs. Encoding
00:00 | 177Many developers are familiar with hashing algorith...
Silence the Accessibility Warning: 4 Ultimate Ways to Fix 'textarea Missing associated label'
00:00 | 98Encountering the 'textarea Missing associated labe...
Mastering Markdown Images: A Complete Guide from Basic Syntax to Advanced Tricks
00:00 | 242Want to effortlessly insert images into your Markd...
Nginx Redirect Trap: How to Fix Incorrectly Encoded Ampersands ('&') in URLs?
00:00 | 99Have you ever encountered an issue where the amper...