Co-authored-by: garage-ui-release-bot[bot] <285030457+garage-ui-release-bot[bot]@users.noreply.github.com>
Garage UI - Web Dashboard for Garage S3 Storage
A modern web interface to manage Garage object storage clusters. Browse buckets, manage access keys, monitor your cluster, all from your browser.
![]() |
![]() |
![]() |
![]() |
Features
- Bucket management - create, configure, and browse buckets with drag-and-drop file uploads
- Access key management - create keys, assign per-bucket permissions
- Cluster overview - monitor node status, layout configuration, and storage usage
- Flexible authentication - no auth, basic credentials, or OIDC (Keycloak, Authentik, etc.)
- Multi-user access control - optional OIDC-team-based permissions, see docs/access-control.md
- Easy deployment - single Docker image or Helm chart, configure with one YAML file
- Preview common file types - images, video, PDF, and text without downloading
Quick Start
Prerequisites
- Docker & Docker Compose
- A running Garage cluster (v2.1.0+) - setup guide if you need one
1. Clone & Configure
git clone https://github.com/Noooste/garage-ui.git
cd garage-ui
cp config.example.yaml config.yaml
Edit config.yaml with your Garage endpoints and admin token (from garage.toml).
2. Start
docker compose up -d garage-ui
Access at http://localhost:8080
Deployment
Docker
docker run -d -p 8080:8080 \
-v $(pwd)/config.yaml:/app/config.yaml \
noooste/garage-ui:latest
Kubernetes
helm repo add garage-ui https://helm.noste.dev/
helm install garage-ui garage-ui/garage-ui \
--set garage.endpoint=http://garage:3900 \
--set garage.adminEndpoint=http://garage:3903 \
--set garage.adminToken=your-token
The chart creates a ClusterIP service on port 80. To try it out before setting up an ingress:
kubectl port-forward svc/garage-ui 8080:80
Then open http://localhost:8080
Reusing your garage.toml
If you already have a running Garage instance, you can point Garage UI straight at your garage.toml and skip config.yaml entirely:
./garage-ui --garage-toml /etc/garage.toml
Garage UI reads the S3 endpoint, admin endpoint, admin token, and S3 region straight from the TOML file. When no authentication method is explicitly configured, token auth auto-enables: the login page asks for the Garage admin token, giving you a login wall with zero extra config.
Bind address handling: Wildcard addresses like 0.0.0.0 or [::] are converted to 127.0.0.1 so the UI can reach Garage on localhost. Inside a container this won't work, so override the endpoints explicitly with environment variables or a config file.
Docker:
docker run -d -p 8080:8080 \
-v /etc/garage.toml:/etc/garage.toml:ro \
-e GARAGE_UI_GARAGE_TOML=/etc/garage.toml \
-e GARAGE_UI_GARAGE_ENDPOINT=http://garage:3900 \
-e GARAGE_UI_GARAGE_ADMIN_ENDPOINT=http://garage:3903 \
noooste/garage-ui:latest
The endpoint overrides are needed because the container cannot reach 127.0.0.1 on the host.
Combining flags: Use --garage-toml for Garage connection values and --config for everything else (auth, CORS, logging, etc.):
./garage-ui --garage-toml /etc/garage.toml --config config.yaml
Precedence order (highest wins): built-in defaults < garage.toml < config.yaml < environment variables.
Configuration
Minimum required config:
server:
port: 8080
garage:
endpoint: "http://garage:3900"
admin_endpoint: "http://garage:3903"
admin_token: "your-admin-token"
region: "garage"
Server bind host is configured by server.host (default: ::). IPv6 literals like :: and ::1 are supported.
server:
host: "::" # IPv6 wildcard (dual-stack-preferred)
port: 8080
If your environment needs explicit IPv4-only binding, set server.host: "0.0.0.0".
See config.example.yaml for all options including authentication, CORS, and logging.
Environment Variables
Override any config value with GARAGE_UI_ prefix:
GARAGE_UI_SERVER_PORT=8080
GARAGE_UI_GARAGE_ENDPOINT=http://garage:3900
GARAGE_UI_GARAGE_ADMIN_TOKEN=your-token
Loading sensitive values from files (_FILE suffix)
For Docker and Kubernetes secrets, sensitive env vars can be read from files instead of plain values. Set {VAR}_FILE=/path/to/file and garage-ui uses the file's contents (trailing CR/LF trimmed) as the value. If both {VAR} and {VAR}_FILE are set, _FILE wins and a warning is logged. A missing or unreadable file stops startup.
Supported vars:
GARAGE_UI_GARAGE_ADMIN_TOKEN_FILEGARAGE_UI_AUTH_ADMIN_USERNAME_FILEGARAGE_UI_AUTH_ADMIN_PASSWORD_FILEGARAGE_UI_AUTH_JWT_PRIVATE_KEY_FILEGARAGE_UI_AUTH_OIDC_CLIENT_ID_FILEGARAGE_UI_AUTH_OIDC_CLIENT_SECRET_FILE
Example with Docker Compose secrets:
services:
garage-ui:
image: noooste/garage-ui:latest
environment:
GARAGE_UI_AUTH_ADMIN_PASSWORD_FILE: /run/secrets/admin_password
secrets:
- admin_password
secrets:
admin_password:
file: ./admin_password.txt
This matches the convention used by the official Postgres and MySQL Docker images. Helm users don't need it; the chart already injects secrets via existingSecret references.
Garage Configuration
Garage UI requires these settings in your garage.toml:
# Admin API (required for Garage UI)
[admin]
api_bind_addr = "0.0.0.0:3903" # Default: 127.0.0.1:3903
admin_token = "your-admin-token" # Generate with: openssl rand -base64 32
# S3 API
[s3_api]
s3_region = "garage" # Default: "garage"
api_bind_addr = "[::]:3900" # Default: 127.0.0.1:3900
Important: The admin_token and s3_region in garage.toml must match your Garage UI config.yaml.
For complete Garage configuration, see the official documentation.
Development
Backend (Go 1.25+):
cd backend
go run main.go --config ../config.yaml
Frontend (Node.js 25+):
cd frontend
npm install
npm run dev
API docs: http://localhost:8080/api/v1/
Troubleshooting
Connection failed:
curl http://localhost:3903/status -H "Authorization: Bearer your-token"
Enable debug logs:
logging:
level: "debug"
format: "text" # or "json"
Roadmap
Roughly ordered by value. Open an issue to push something up the list.
- Fine-grained access control: OIDC teams with per-bucket-prefix permissions, see docs/access-control.md
- Object search: recursive substring search across a bucket
- Bucket quotas: size and object count limits from bucket settings
- Zero-config startup: run straight from
garage.toml, log in with the admin token - Broad compatibility: Garage v1 through latest, IPv6-only networks, secrets from files
- Inline object preview: images, video, PDF, and text without downloading (#60)
- Presigned share links: time-limited download links from the object browser
- Resumable uploads: multipart uploads that survive a dropped connection
- Visual layout editor: staged vs. applied diff before committing layout changes
- Admin audit log: who changed what, building on access control
- Table and detail polish: sortable columns, clearer node details (#36, #37)
License
MIT - see LICENSE
Links
Made with ❤️ in France 🇫🇷



