DokPloy 部署Garage与登录失败排查
背景
MinIO 进入维护模式
2025年12月3日,MinIO 官方宣布开源项目进入维护模式:
- 停止接受新功能和 PR
- 不再积极处理现有 Issue 和 PR
- 仅对严重安全漏洞”视情况而定”修复
- 社区支持仅限”尽力而为”
这一举措在开源社区引发强烈反响。

为什么选择 Garage
Garage 是一个用 Rust 编写的分布式对象存储系统,具有以下特点:
- S3 兼容:可作为 MinIO 的平替
- 轻量级:单二进制文件,资源占用低
- 去中心化:适合边缘部署和多节点场景
- 自托管友好:配置简单,易于维护
配合 Garage WebUI 可以获得可视化管理界面:
Dokploy 部署配置
在 Dokploy 中部署 Garage + WebUI,需要配置以下环境变量:
直接选择模板部署

# WebUI 环境变量API_BASE_URL=http://garage:3903 # Admin API(内部通信,使用服务名)S3_ENDPOINT_URL=http://garage:3900 # S3 API(内部通信)
# 认证配置(使用 htpasswd 生成)AUTH_USER_PASS=admin:$2y$10$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx密码生成
htpasswd -nbBC 10 "YOUR_USERNAME" "YOUR_PASSWORD"如果没有的htpasswd库的,需要安装 apache2-utils
Garage 端口说明:
| 端口 | 用途 | 外部访问域名示例 |
|---|---|---|
| 3900 | S3 API | garage.xx.com |
| 3901 | RPC (节点通信) | 仅内部 |
| 3902 | Web 静态托管 | 可选配置 |
| 3903 | Admin API | 仅内部 |
| 3909 | WebUI | garage-ui.xx.com |
TIP
API_BASE_URL和S3_ENDPOINT_URL使用 Docker 服务名garage而非外部域名,因为这是容器间内部通信。
问题一:登录失败
现象
使用 htpasswd 生成了正确格式的密码哈希:
htpasswd -nbBC 10 "admin" "your-password"# 输出: admin:$2y$10$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx配置到 .env 文件中:
AUTH_USER_PASS=admin:$2y$10$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx但登录时始终提示账户密码错误。
排查过程
使用 docker inspect 查看容器内实际收到的环境变量:
docker inspect garage-webui-1 --format '{{range .Config.Env}}{{println .}}{{end}}'发现问题:
AUTH_USER_PASS=admin:$2y$10密码哈希被截断了!期望的完整值是 admin:$2y$10$xxxxxx...,但实际只有 admin:$2y$10。
原因分析
WARNINGDocker Compose 会将
.env文件中的$解释为变量替换符号。
bcrypt 哈希中包含多个 $ 符号(如 $2y$10$Qtra4...):
$2y被当作变量2y$10被当作变量10$Qtra4...被当作变量Qtra4...
由于这些变量不存在,Docker Compose 将它们替换为空字符串,导致哈希被截断。
解决方案
在 docker-compose.yml 中直接硬编码环境变量,使用 $$ 转义 $ 符号:
services: garage-webui: environment: - AUTH_USER_PASS=admin:$$2y$$10$$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - API_BASE_URL=http://garage:3903 - S3_ENDPOINT_URL=http://garage:3900TIP
$$在 Docker Compose 中会被转义为单个$,这样密码哈希就能完整传递给容器了。
问题二:升级后状态显示 Unavailable
现象
将 Garage 从 v2.0.0 升级到 v2.1.0 后,WebUI 显示连接状态为 Unavailable。
排查过程
查看 Garage 日志:
docker logs garage-1 --tail 30发现大量错误:
WARN Response: error 500 Internal Server Error, Internal error: Layout not ready检查集群状态:
docker exec garage-1 /garage status输出显示节点没有分配角色:
==== HEALTHY NODES ====ID Hostname Address Tags Zone Capacity Version7740e73cc75036ef 67993cf5 [::1]:3901 NO ROLE ASSIGNED v2.1.0原因分析
IMPORTANT升级 Garage 后,需要重新配置集群布局(Cluster Layout)。节点没有分配角色时,无法提供 S3 服务。
解决方案
- 分配节点角色:
docker exec garage-1 /garage layout assign -z dc1 -c 1G 7740e73cc75036ef参数说明:
-z dc1:Zone 名称-c 1G:分配的存储容量7740e73cc75036ef:节点 ID(从 status 命令获取)
- 应用布局更改:
docker exec garage-1 /garage layout apply --version 1- 验证状态:
docker exec garage-1 /garage status现在应该显示:
==== HEALTHY NODES ====ID Hostname Address Tags Zone Capacity DataAvail Version7740e73cc75036ef 67993cf5 [::1]:3901 [] dc1 1000.0 MB 978.9 GB v2.1.0刷新 WebUI,连接状态应恢复正常。
总结
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 登录失败 | Docker Compose $ 变量替换 | 使用 $$ 转义 |
| 登录不稳定 | 多个容器负载均衡 | 删除旧容器 |
| Unavailable | 升级后节点无角色 | layout assign + apply |
NOTE在 Dokploy 中管理 Docker Compose 项目时,环境变量的特殊字符处理需要特别注意。直接在
docker-compose.yml中硬编码可以避免.env文件的变量替换问题。
界面预览
界面还是挺不错,简洁又好看。

