Garage Setup
Overview
Garage is an open-source distributed object storage service compatible with the Amazon S3 API. It lets you self-host S3-compatible storage on your own infrastructure — useful for backing up files, hosting app data, or serving as object storage for self-hosted services like Nextcloud.
Unlike cloud S3 services, Garage keeps your data on your own servers with no egress fees.
Prerequisites
- Docker installed and configured (see Docker Setup)
- Docker Compose installed (see Docker Compose)
- Caddy running with external
caddynetwork (see Caddy Setup) - Domain name pointed to your VPS
Docker Compose Setup
Create the Garage directory:
sudo mkdir -p /opt/garage
cd /opt/garage
Create garage.toml:
metadata_dir = "/var/lib/garage/meta"
data_dir = "/var/lib/garage/data"
db_engine = "sqlite"
replication_factor = 1
rpc_bind_addr = "[::]:3901"
rpc_public_addr = "127.0.0.1:3901"
rpc_secret = "<rpc-secret>"
[s3_api]
s3_region = "garage"
api_bind_addr = "[::]:3900"
root_domain = ".s3.<yourdomain>.com"
[s3_web]
bind_addr = "[::]:3902"
root_domain = ".web.<yourdomain>.com"
index = "index.html"
[admin]
api_bind_addr = "[::]:3903"
admin_token = "<admin-token>"
metrics_token = "<metrics-token>"
Generate secrets and replace the placeholders:
openssl rand -hex 32 # rpc-secret
openssl rand -base64 32 # admin-token
openssl rand -base64 32 # metrics-token
What are these secrets?
rpc_secret: Encrypts communication between Garage nodes (only matters in multi-node clusters)admin_token: Authentication token for admin CLI commandsmetrics_token: Token for accessing Prometheus metrics
Create docker-compose.yml:
services:
garage:
image: dxflrs/garage:v2.2.0
container_name: garage
ports:
- "3900:3900"
volumes:
- ./garage.toml:/etc/garage.toml
- garage_meta:/var/lib/garage/meta
- garage_data:/var/lib/garage/data
networks:
- caddy
restart: unless-stopped
volumes:
garage_meta:
garage_data:
networks:
caddy:
external: true
Start Garage:
sudo docker compose up -d
Note: Check Docker Hub for the latest version tag. Replace
v2.2.0with the newest stable release.
Initialize Garage
Garage requires a one-time initialization before it can store data.
1. Check node status
docker exec garage /garage status
Copy the node ID from the output (first column, e.g., 563e1ac825ee3323).
2. Assign cluster layout
Replace <node-id> with the ID from the previous step:
docker exec garage /garage layout assign -z dc1 -c 1G <node-id>
docker exec garage /garage layout apply --version 1
3. Create a bucket
docker exec garage /garage bucket create my-bucket
4. Create an API key
docker exec garage /garage key create my-key
5. Allow key access to the bucket
docker exec garage /garage bucket allow --read --write my-bucket --key my-key
6. Get key credentials
docker exec garage /garage key info my-key
Save the Key ID and Secret key — you’ll need them for S3 clients.
Caddy Configuration
Garage serves static websites from buckets through the S3 web endpoint (port 3902). To expose your buckets as websites via HTTPS, add to your Caddyfile:
garage.<yourdomain>.com {
reverse_proxy garage:3902
}
Note: Port 3902 is the S3 web endpoint — it serves static website files stored in your buckets. It is NOT a web admin UI. Garage v2 does not include a graphical admin panel; you manage buckets via the CLI or S3-compatible tools.
S3 API Access
For S3 API access through Caddy, you need wildcard subdomain support. S3 clients access buckets as my-bucket.s3.<yourdomain>.com. Caddy can handle this with wildcard certificates, but requires a DNS challenge:
*.s3.<yourdomain>.com {
tls {
dns <provider>
}
reverse_proxy garage:3900
}
Setting up DNS challenges requires Caddy DNS plugins and is beyond the scope of this guide. For most use cases, accessing Garage directly via Tailscale or the awscli endpoint (shown below) is simpler.
Restart Caddy after any changes:
docker compose -f /opt/caddy/docker-compose.yml restart caddy
Access Garage
Garage is managed via the CLI or any S3-compatible client. There is no web admin UI.
Using awscli
Install awscli:
sudo apt install -y awscli
Configure your credentials (the interactive setup stores them securely in ~/.aws/credentials):
aws configure
When prompted:
- AWS Access Key ID: Your Garage key ID from step 6 above
- AWS Secret Access Key: Your Garage secret key from step 6
- Default region name:
garage - Default output format: (leave blank or type
json)
Then set the endpoint URL:
export AWS_ENDPOINT_URL=https://127.0.0.1:3900
Tip: Add the
exportline to your~/.bashrcso it’s set automatically in new sessions.
Use Garage:
aws s3 ls
aws s3 cp file.txt s3://my-bucket/
aws s3 ls s3://my-bucket/
Managing Buckets
docker exec garage /garage bucket list # List all buckets
docker exec garage /garage bucket info my-bucket # Show bucket details
docker exec garage /garage key list # List API keys
docker exec garage /garage status # Cluster node status
Key Commands
docker compose -f /opt/garage/docker-compose.yml up -d # Start
docker compose -f /opt/garage/docker-compose.yml down # Stop
docker compose -f /opt/garage/docker-compose.yml logs -f # View logs
Data Persistence
Garage stores bucket metadata in the garage_meta volume and object data in the garage_data volume. Your data persists across container restarts.