555 字
3 分钟

Deploy Garage with DokPloy and Troubleshoot Login Issues

Background#

MinIO Enters Maintenance Mode#

On December 3, 2025, MinIO officially announced that the open-source project is entering maintenance mode:

  • No new features or PRs will be accepted
  • Existing issues and PRs will not be actively addressed
  • Security vulnerabilities will be fixed on a “case-by-case basis”
  • Community support is limited to “best effort”

This move has sparked strong reactions in the open-source community.

image-20260108175153529

Why Choose Garage#

deuxfleurs-org
/
garage
Waiting for api.github.com...
00K
0K
0K
Waiting...

Garage is a distributed object storage system written in Rust with the following features:

  • S3 Compatible: Can serve as a MinIO replacement
  • Lightweight: Single binary, low resource consumption
  • Decentralized: Suitable for edge deployment and multi-node scenarios
  • Self-hosting Friendly: Simple configuration, easy to maintain

Combined with Garage WebUI, you can get a visual management interface:

khairul169
/
garage-webui
Waiting for api.github.com...
00K
0K
0K
Waiting...

Dokploy Deployment Configuration#

When deploying Garage + WebUI in Dokploy, configure the following environment variables:

Deploy directly using the template

image-20260108174433376

# WebUI environment variables
API_BASE_URL=http://garage:3903 # Admin API (internal communication, using service name)
S3_ENDPOINT_URL=http://garage:3900 # S3 API (internal communication)
# Authentication configuration (generated with htpasswd)
AUTH_USER_PASS=admin:$2y$10$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Password generation

Terminal window
htpasswd -nbBC 10 "YOUR_USERNAME" "YOUR_PASSWORD"

If you don’t have htpasswd, you need to install apache2-utils

Garage Port Reference:

PortPurposeExternal Domain Example
3900S3 APIgarage.xx.com
3901RPC (node communication)Internal only
3902Web static hostingOptional
3903Admin APIInternal only
3909WebUIgarage-ui.xx.com
TIP

API_BASE_URL and S3_ENDPOINT_URL use the Docker service name garage instead of external domains because this is internal container-to-container communication.

Issue 1: Login Failure#

Symptoms#

Generated a properly formatted password hash using htpasswd:

Terminal window
htpasswd -nbBC 10 "admin" "your-password"
# Output: admin:$2y$10$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Configured in the .env file:

Terminal window
AUTH_USER_PASS=admin:$2y$10$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

But login always shows incorrect username/password error.

Investigation#

Used docker inspect to check the actual environment variables received by the container:

Terminal window
docker inspect garage-webui-1 --format '{{range .Config.Env}}{{println .}}{{end}}'

Found the issue:

AUTH_USER_PASS=admin:$2y$10

The password hash was truncated! Expected full value is admin:$2y$10$xxxxxx..., but actual value is only admin:$2y$10.

Root Cause#

WARNING

Docker Compose interprets $ in .env files as variable substitution markers.

The bcrypt hash contains multiple $ symbols (e.g., $2y$10$Qtra4...):

  • $2y is treated as variable 2y
  • $10 is treated as variable 10
  • $Qtra4... is treated as variable Qtra4...

Since these variables don’t exist, Docker Compose replaces them with empty strings, truncating the hash.

Solution#

Hardcode environment variables directly in docker-compose.yml, using $$ to escape $ symbols:

services:
garage-webui:
environment:
- AUTH_USER_PASS=admin:$$2y$$10$$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
- API_BASE_URL=http://garage:3903
- S3_ENDPOINT_URL=http://garage:3900
TIP

$$ in Docker Compose is escaped to a single $, allowing the complete password hash to be passed to the container.

Issue 2: Unavailable Status After Upgrade#

Symptoms#

After upgrading Garage from v2.0.0 to v2.1.0, WebUI shows connection status as Unavailable.

Investigation#

Checked Garage logs:

Terminal window
docker logs garage-1 --tail 30

Found numerous errors:

WARN Response: error 500 Internal Server Error, Internal error: Layout not ready

Checked cluster status:

Terminal window
docker exec garage-1 /garage status

Output showed the node had no assigned role:

==== HEALTHY NODES ====
ID Hostname Address Tags Zone Capacity Version
7740e73cc75036ef 67993cf5 [::1]:3901 NO ROLE ASSIGNED v2.1.0

Root Cause#

IMPORTANT

After upgrading Garage, you need to reconfigure the Cluster Layout. Without an assigned role, the node cannot provide S3 services.

Solution#

  1. Assign node role:
Terminal window
docker exec garage-1 /garage layout assign -z dc1 -c 1G 7740e73cc75036ef

Parameter explanation:

  • -z dc1: Zone name
  • -c 1G: Allocated storage capacity
  • 7740e73cc75036ef: Node ID (obtained from status command)
  1. Apply layout changes:
Terminal window
docker exec garage-1 /garage layout apply --version 1
  1. Verify status:
Terminal window
docker exec garage-1 /garage status

Should now display:

==== HEALTHY NODES ====
ID Hostname Address Tags Zone Capacity DataAvail Version
7740e73cc75036ef 67993cf5 [::1]:3901 [] dc1 1000.0 MB 978.9 GB v2.1.0

Refresh WebUI, and the connection status should return to normal.

Summary#

IssueCauseSolution
Login failureDocker Compose $ variable substitutionUse $$ to escape
Unstable loginMultiple containers load-balancedRemove old container
UnavailableNode has no role after upgradelayout assign + apply
NOTE

When managing Docker Compose projects in Dokploy, special character handling in environment variables requires extra attention. Hardcoding directly in docker-compose.yml can avoid variable substitution issues from .env files.

Interface Preview#

The interface is quite nice, clean and beautiful.

image-20260108174812353

image-20260108174831129

Deploy Garage with DokPloy and Troubleshoot Login Issues
https://catcat.blog/en/2026/01/dokploy-garage-s3-deployment-guide
作者
猫猫博客
发布于
2026-01-08
许可协议
CC BY-NC-SA 4.0