Garage: S3 Object Storage
Introduction
Garage Overview
Garage is an open-source, self-hosted object storage system that implements the Amazon S3 API, specifically designed for small-to-medium deployments on consumer-grade hardware and internet connections. Unlike traditional distributed storage solutions that rely on consensus algorithms like Raft, Garage operates as a geo-distributed cluster where nodes can be added or removed without a central leader, allowing all requests to be processed independently and avoiding single-point bottlenecks.
This architecture emphasizes resilience and low overhead, making it particularly suitable for home or edge environments where nodes can span multiple physical locations. The platform supports standard S3 features including multipart uploads, bucket management, access-key authentication, and static website hosting, while providing an admin API for cluster control and Prometheus-format metrics for performance monitoring. These characteristics make Garage an attractive option for organizations seeking a cost-effective, decentralized storage solution that maintains S3 compatibility without the infrastructure requirements of commercial cloud providers.
Purpose of this Guide
This guide outlines how to join a collaborative Garage storage cluster, a model where participants contribute their own storage capacity to create a resilient, geo-distributed network. By pooling resources, each member gains the security benefit of having their critical data replicated off-site at a trusted peer's home, ensuring redundancy and protection against local hardware failures without relying on commercial cloud providers. This approach transforms individual storage into a shared, secure infrastructure where everyone contributes to and benefits from a decentralized, self-hosted backup ecosystem.
Things to Know Before Setup
Shared Administration
Because this is a collaborative storage cluster, everyone is an administrator. All members can add, remove, view, and modify keys, buckets, the cluster, nodes, etc. Before storing any meaningful data, please consider encrypting it.
Deleting objects in Garage can permanently remove keys or buckets, potentially causing data loss. The Garage WebUI warns you when you try to delete a non-empty bucket, but stay vigilant.
Tip
Never modify keys, buckets, or nodes that belong to someone else without first contacting the owner. Good communication keeps the cluster healthy.
Bring Your Own Storage: Storage-Usage Guidelines
Plan to provide at least three times the total size of your backup data, since each piece of data is replicated three ways across the cluster. This ensures that there is enough space to keep the overall storage cluster healthy.
Example
You have two backup directories that you plan to backup to the Garage storage cluster. Those directories are 600 GB and 400 GB in size for a total of 1.0 TB. You should contribute at least 3 TB of capacity to the cluster layout.
Shared Key for Joining the Collaborative Storage Cluster
This guide will instruct you on how to create your own Garage storage cluster. Once you are familiar with the setup and have some hands-on experience then you can join the collaborative storage cluster. You will need the shared rpc_secret in order to join that cluster. This can be obtained by contacting the administrator.
Recommended Configuration
This section contains the recommended configuration files and directory layout for running a single Garage node and Garage WebUI. Additional nodes can be added once intial setup is complete.
Recommended Directory Layout
garage/
├─ data/
│ ├─ meta/ # Metadata directory for garage (recommended on SSD)
│ ├─ garage/ # Data / blob storage (can be on an SSD or HDD)
│ └─ garage.toml # Configuration file used by garage and garage-webui
└─ docker-compose.yaml
Docker-Compose File
services:
garage:
image: dxflrs/garage:v2.2.0
container_name: garage
ports:
- 3900:3900 # S3 API endpoint
- 3901:3901 # Garage RPC endpoint
- 3903:3903 # Garage admin API endpoint
volumes:
- ./data/garage.toml:/etc/garage.toml # Config file
- ./data/meta:/var/lib/garage/meta # Metadata storage (recommended on SSD)
- ./data/garage:/var/lib/garage/data # Data storage (can be on SSD or HDD)
restart: unless-stopped
webui:
image: khairul169/garage-webui:latest
container_name: garage-webui
volumes:
- ./data/garage.toml:/etc/garage.toml:ro
ports:
- 3909:3909 # WebUI admin panel
environment:
API_BASE_URL: "http://garage:3903"
S3_ENDPOINT_URL: "http://garage:3900"
restart: unless-stopped
garage.toml (Core Settings)
metadata_dir = "/var/lib/garage/meta"
data_dir = "/var/lib/garage/data"
db_engine = "sqlite"
metadata_auto_snapshot_interval = "6h"
metrics_require_token = true
use_local_tz = false
block_size = "1MiB"
block_ram_buffer_max = "512MiB" # Adjust to available RAM
block_max_concurrent_reads = 16
block_max_concurrent_writes_per_request = 15 # 10‑30 for NVMe, 3‑10 for HDD
replication_factor = 3 # DO NOT CHANGE: Must be same on all nodes
consistency_mode = "consistent" # DO NOT CHANGE: this affects failure read/write behavior
compression_level = 2 # fast, decent compression
rpc_bind_addr = "[::]:3901"
rpc_public_addr = "mydomain.co:3901" # <- Replace with your public node address
rpc_secret = "my_secret" # <- Generate with: openssl rand -hex 32 (same on all nodes)
# Peer IDs have the format: "<node public key>@<node public IP or hostname>:<port>"
# TODO: Update bootstrap_peers with the address for each other node this one should connect with.
bootstrap_peers = [
"<node1-public-key>@<node1-public-IP-or-hostname>:<port>",
"<node2-public-key>@<node2-public-IP-or-hostname>:<port>"
]
[s3_api]
s3_region = "garage"
api_bind_addr = "[::]:3900"
root_domain = ".s3.mydomain.co" # <- Enables virtual-hosted-style access (e.g., mybucket.s3.mydomain.co)
[admin]
api_bind_addr = "[::]:3903"
admin_token = "my_token" # Generate with: openssl rand -base64 32
metrics_token = "my_metrics_token" # Generate with: openssl rand -base64 32
Key Configuration Items to Edit
- rpc_public_addr - Public address other nodes will use to reach this node.
- rpc_secret - A 32-byte hex string; generate with
openssl rand -hex 32. Must be identical on every node. - bootstrap_peers - List of known peers (optional but speeds up discovery).
- admin_token - Generate with
openssl rand -base64 32. Keep it secret.
Advanced Configuration
The following are links to external documentation for the Garage and Garage WebUI projects. These are useful for further customizing your installation.
- Garage: Quick Start - Official Garage "quick start" documentation.
- Garage: Clustering - Official Garage guide to deploying a Garage cluster.
- Garage: Configuration - Official Garage configuration reference.
- Garage WebUI - Source code and documentation for Garage WebUI project.
Deploying & Configuring Garage
Running Garage with Docker
- Install Docker and Docker-Compose on your host.
- Place the directory structure shown above.
- Edit garage.toml with your values.
- Run
docker compose up -d. The service will start and expose the ports defined earlier.
Adding a New Node
- Open Garage WebUI (http://localhost:3909) -> Cluster.
- Click Connect, paste the new node's ID (
<public-key>@<hostname>:<port>). - Save - the node appears in the list.
- Assign the node:
- Click the three-dot menu -> Assign.
- Choose a Zone (one per home lab).
- Set the Capacity you're contributing.
- (Recommended) Add Tags for easy identification.
- After confirming, click Apply to push the new cluster layout. The cluster will rebalance data as needed.
Creating a New Key
- Garage WebUI -> Keys -> Create Key.
- Give the key a unique name.
- Record the displayed Key ID and Secret Key (store them securely).
Creating a Bucket & Setting Permissions
- Garage WebUI -> Buckets -> Create Bucket -> give it a unique name.
- Click Manage -> Permissions on the new bucket.
- Press Allow Key, select the desired keys, and grant the needed rights (Read, Write, Owner are typical for write-heavy workloads).
- Submit - the permissions table updates accordingly.
Setting Up a Reverse Proxy
Goal: Expose the S3 API and RPC endpoints via friendly domain names.
- Point a DNS record (e.g., s3.mydomain.co) to the IP of a garage node and configure your reverse proxy (Caddy, Nginx, Traefik, ...) to forward port 3900 to that node.
- Create separate DNS records for each node (e.g., node1.mydomain.co, node2.mydomain.co) and proxy port 3901 to the corresponding node's RPC endpoint.
- Ensure all nodes can resolve each other's domain names; this is required for inter-node communication.
Configuring a Backup Application (Kopia Example)
When adding a new repository in Kopia UI:
| Field | Value |
|---|---|
| Bucket | Name of the Garage bucket |
| Server Endpoint | http://<node-address>:3900 (or the DNS name you created) |
| Override Region | garage (or leave blank) |
| Access Key ID | The Key ID you generated |
| Secret Access Key | The matching Secret Key |
Kopia will encrypt data locally before sending it to Garage.
Running Additional Garage Nodes
Additional nodes only need the garage service in their docker-compose.yaml. The Garage WebUI container is optional and typically runs on a single "management" node.
Each additional node's garage.toml must use the same rpc_secret, replication_factor, and consistency_mode as existing nodes. Set rpc_public_addr to the new node's address and include at least one existing node in bootstrap_peers.
Joining the Collaborative Storage Cluster
When you are ready to join the collaborative storage cluster you will need the shared rpc_secret. This can be obtained by contacting the administrator.
Final Thoughts
- Collaboration is key - keep communication open when modifying shared resources.
- Security matters - never expose
rpc_secretoradmin_tokenpublicly. - Capacity planning - aim for three-times replication storage to avoid saturation.