Deploying GarageHQ
Introduction
GarageHQ (commonly called Garage) is a lightweight, self-hosted distributed storage system that provides S3-compatible object storage. Designed for simplicity and resilience, Garage enables you to build your own storage infrastructure that can span multiple locations while remaining easy to operate.
Built in Rust for performance and reliability, Garage is designed to run on commodity hardware and can operate across heterogeneous nodes with varying storage capacities and network conditions. Unlike enterprise storage solutions that require specialized hardware, Garage works on anything from Raspberry Pis to powerful servers.
Key highlights of Garage:
- S3-Compatible API: Use existing S3 tools and libraries without modification
- Distributed Architecture: Spread data across multiple nodes for redundancy
- Geo-Distribution: Design clusters that span data centers or geographic regions
- Lightweight: Written in Rust with minimal resource requirements
- Self-Healing: Automatic data repair and rebalancing
- Simple Operation: No complex cluster management or specialized knowledge required
- Flexible Topology: Mix nodes with different capacities and performance characteristics
- Web Interface: Built-in admin panel for cluster management
- K2V API: Key-value store API for application state (in addition to S3)
- 100% Open Source: Licensed under AGPL-3.0
This guide walks through deploying Garage on Klutch.sh using Docker, configuring a storage cluster, and using the S3-compatible API for your applications.
Why Deploy GarageHQ on Klutch.sh
Deploying Garage on Klutch.sh provides several advantages for your object storage needs:
Simplified Deployment: Klutch.sh automatically detects your Dockerfile and builds Garage without complex orchestration. Push to GitHub, and your storage node deploys automatically.
Persistent Storage: Attach persistent volumes for your object data and metadata. Your files survive container restarts and redeployments without data loss.
HTTPS by Default: Klutch.sh provides automatic SSL certificates, ensuring secure access to your S3 API endpoint from anywhere.
GitHub Integration: Connect your configuration repository directly from GitHub. Updates to your configuration trigger automatic redeployments.
Scalable Resources: Allocate CPU, memory, and storage based on your needs. Start small and scale up as your storage requirements grow.
Environment Variable Management: Securely store sensitive configuration like RPC secrets and access keys through Klutch.sh’s environment variable system.
Custom Domains: Assign a custom domain to your Garage instance for S3 endpoint URLs that match your infrastructure.
Always-On Availability: Your storage service remains accessible 24/7 without managing your own hardware.
Prerequisites
Before deploying Garage on Klutch.sh, ensure you have:
- A Klutch.sh account
- A GitHub account with a repository for your Garage configuration
- Basic familiarity with Docker and containerization concepts
- Understanding of S3 object storage concepts
- (Optional) A custom domain for your S3 endpoint
Understanding Garage Architecture
Garage is built on a distributed architecture:
Nodes: Each Garage instance is a node in the cluster. Nodes communicate via an RPC protocol for coordination and data transfer.
Zones: Nodes are organized into zones (typically representing failure domains like data centers). Garage distributes data across zones for resilience.
Replication: Data is replicated across multiple nodes based on your replication factor. The default is 3 copies across different zones.
Metadata: Garage uses a distributed metadata store for bucket and object information. Metadata is also replicated for durability.
S3 Gateway: Each node can serve S3 API requests, routing reads and writes to the appropriate data locations.
Web Gateway: Serves static websites directly from buckets, similar to AWS S3 static hosting.
Preparing Your Repository
To deploy Garage on Klutch.sh, create a GitHub repository containing your Dockerfile and configuration.
Repository Structure
garage-deploy/├── Dockerfile├── garage.toml├── README.md└── .dockerignoreCreating the Dockerfile
Create a Dockerfile in the root of your repository:
FROM dxflrs/garage:v0.9
# Copy configuration fileCOPY garage.toml /etc/garage.toml
# Create data directoriesRUN mkdir -p /var/lib/garage/data /var/lib/garage/meta
# Expose ports# S3 APIEXPOSE 3900# Web gatewayEXPOSE 3902# Admin APIEXPOSE 3903
# Run Garage with the configuration fileCMD ["garage", "-c", "/etc/garage.toml", "server"]Advanced Dockerfile with Health Checks
For production deployments:
FROM dxflrs/garage:v0.9
# Copy configuration fileCOPY garage.toml /etc/garage.toml
# Create data directoriesRUN mkdir -p /var/lib/garage/data /var/lib/garage/meta
# Set environment variablesENV GARAGE_CONFIG_FILE=/etc/garage.tomlENV RUST_LOG=garage=info
# Health check for S3 APIHEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \ CMD wget --no-verbose --tries=1 --spider http://localhost:3903/health || exit 1
# Expose portsEXPOSE 3900 3902 3903
CMD ["garage", "-c", "/etc/garage.toml", "server"]Creating the Configuration File
Create a garage.toml file:
# Garage configuration file
# Metadata directorymetadata_dir = "/var/lib/garage/meta"
# Data directorydata_dir = "/var/lib/garage/data"
# Size of data blocks (default 1MB)block_size = 1048576
# Replication mode# 1 = none (single copy)# 2 = 2 copies# 3 = 3 copies (recommended for production)replication_mode = "1"
# Compression (none, lz4, zstd)compression_level = "none"
# RPC configuration[rpc]# RPC secret key (32 bytes hex-encoded)# Generate with: openssl rand -hex 32rpc_secret = "${RPC_SECRET}"
# RPC bind addressrpc_bind_addr = "[::]:3901"
# Public RPC address (for other nodes to connect)rpc_public_addr = "${RPC_PUBLIC_ADDR}"
# Bootstrap peers (for multi-node clusters)# bootstrap_peers = []
# S3 API configuration[s3_api]s3_region = "garage"api_bind_addr = "[::]:3900"root_domain = "${S3_ROOT_DOMAIN}"
# S3 Web gateway configuration[s3_web]bind_addr = "[::]:3902"root_domain = "${WEB_ROOT_DOMAIN}"index = "index.html"
# Admin API configuration[admin]api_bind_addr = "[::]:3903"admin_token = "${ADMIN_TOKEN}"metrics_token = "${METRICS_TOKEN}"Creating the .dockerignore File
Create a .dockerignore file:
.git.github*.mdREADME.mdLICENSE.gitignore*.log.DS_Store.env.env.localEnvironment Variables Reference
| Variable | Required | Default | Description |
|---|---|---|---|
RPC_SECRET | Yes | - | 32-byte hex-encoded secret for RPC authentication |
RPC_PUBLIC_ADDR | Yes | - | Public address for RPC (e.g., your-app.klutch.sh:3901) |
S3_ROOT_DOMAIN | No | - | Root domain for virtual-hosted bucket URLs |
WEB_ROOT_DOMAIN | No | - | Root domain for web gateway |
ADMIN_TOKEN | Yes | - | Token for admin API authentication |
METRICS_TOKEN | No | - | Token for metrics endpoint |
Deploying GarageHQ on Klutch.sh
Once your repository is prepared, follow these steps to deploy Garage:
- Select HTTP as the traffic type
- Set the internal port to 3900 (S3 API port)
- Detect your Dockerfile automatically
- Build the container image
- Attach the persistent volumes
- Start the Garage container
- Provision an HTTPS certificate
- S3 API:
https://your-app-name.klutch.sh(port 3900) - Admin API: Port 3903 (if configured)
Generate Security Secrets
Before deployment, generate the required secrets:
# Generate RPC secretopenssl rand -hex 32
# Generate admin tokenopenssl rand -hex 32
# Generate metrics token (optional)openssl rand -hex 32Save these secrets securely for the environment variables configuration.
Push Your Repository to GitHub
Initialize your repository and push to GitHub:
git initgit add Dockerfile garage.toml .dockerignore README.mdgit commit -m "Initial Garage deployment configuration"git remote add origin https://github.com/yourusername/garage-deploy.gitgit push -u origin mainCreate a New Project on Klutch.sh
Navigate to the Klutch.sh dashboard and create a new project. Give it a descriptive name like “garage” or “storage”.
Create a New App
Within your project, create a new app. Connect your GitHub account if you haven’t already, then select the repository containing your Garage Dockerfile.
Configure HTTP Traffic
Garage exposes multiple ports. Configure the primary S3 API port:
Note: For the admin API (3903) and web gateway (3902), you may need additional configuration or separate deployments.
Set Environment Variables
In the environment variables section, add the following:
| Variable | Value |
|---|---|
RPC_SECRET | Your generated 32-byte hex secret |
RPC_PUBLIC_ADDR | your-app-name.klutch.sh:3901 |
ADMIN_TOKEN | Your generated admin token |
METRICS_TOKEN | Your generated metrics token |
S3_ROOT_DOMAIN | .s3.your-app-name.klutch.sh (optional) |
Attach Persistent Volumes
Persistent storage is essential for Garage. Add the following volumes:
| Mount Path | Recommended Size | Purpose |
|---|---|---|
/var/lib/garage/data | 100+ GB | Object data storage |
/var/lib/garage/meta | 10 GB | Metadata storage |
Deploy Your Application
Click Deploy to start the build process. Klutch.sh will:
Configure the Cluster
After deployment, configure your Garage node using the admin CLI:
# Connect to your Garage instancegarage -c /etc/garage.toml status
# Set the node's zone and capacitygarage layout assign <node-id> --zone dc1 --capacity 100G
# Apply the layoutgarage layout apply --version 1Access Garage
Once deployment completes, access your Garage instance:
Initial Setup and Configuration
Node Configuration
After deploying, configure your Garage node:
- Get Node ID: Check the container logs for the node ID
- Assign Layout: Set the zone and capacity for your node
- Apply Layout: Activate the node configuration
Creating Access Keys
Create S3 access keys for your applications:
# Create a new access keygarage key create my-app-key
# List access keysgarage key list
# Get key detailsgarage key info my-app-keyCreating Buckets
Create buckets for your data:
# Create a bucketgarage bucket create my-bucket
# Allow a key to access the bucketgarage bucket allow my-bucket --read --write --key my-app-key
# List bucketsgarage bucket listBucket Permissions
Configure bucket access:
| Permission | Description |
|---|---|
--read | Read objects from bucket |
--write | Write objects to bucket |
--owner | Full bucket management |
Using the S3 API
AWS CLI Configuration
Configure the AWS CLI to use your Garage instance:
aws configure --profile garage# AWS Access Key ID: (your access key id)# AWS Secret Access Key: (your secret key)# Default region name: garage# Default output format: jsonCreate a profile configuration in ~/.aws/config:
[profile garage]endpoint_url = https://your-app-name.klutch.shregion = garageBasic S3 Operations
Perform common S3 operations:
# List bucketsaws s3 ls --profile garage
# Upload a fileaws s3 cp myfile.txt s3://my-bucket/ --profile garage
# Download a fileaws s3 cp s3://my-bucket/myfile.txt . --profile garage
# List objectsaws s3 ls s3://my-bucket/ --profile garage
# Delete an objectaws s3 rm s3://my-bucket/myfile.txt --profile garageUsing S3 SDKs
Use Garage with any S3-compatible SDK:
Python (boto3):
import boto3
s3 = boto3.client( 's3', endpoint_url='https://your-app-name.klutch.sh', aws_access_key_id='YOUR_ACCESS_KEY', aws_secret_access_key='YOUR_SECRET_KEY', region_name='garage')
# Upload files3.upload_file('local-file.txt', 'my-bucket', 'remote-file.txt')
# Download files3.download_file('my-bucket', 'remote-file.txt', 'local-file.txt')JavaScript (AWS SDK):
const { S3Client, PutObjectCommand } = require('@aws-sdk/client-s3');
const s3 = new S3Client({ endpoint: 'https://your-app-name.klutch.sh', region: 'garage', credentials: { accessKeyId: 'YOUR_ACCESS_KEY', secretAccessKey: 'YOUR_SECRET_KEY' }, forcePathStyle: true});
// Upload fileawait s3.send(new PutObjectCommand({ Bucket: 'my-bucket', Key: 'file.txt', Body: 'Hello, Garage!'}));Static Website Hosting
Enabling Web Gateway
Garage can serve static websites from buckets:
- Create a bucket for your website
- Upload your static files
- Configure the bucket for website hosting
# Create website bucketgarage bucket create my-website
# Allow the web gateway to access the bucketgarage bucket website my-website --allow
# Upload filesaws s3 sync ./website s3://my-website/ --profile garageCustom Index and Error Pages
Configure custom pages in garage.toml:
[s3_web]bind_addr = "[::]:3902"root_domain = ".web.example.com"index = "index.html"Multi-Node Clusters
Adding Nodes
For production, run multiple Garage nodes:
- Deploy additional Garage instances
- Configure each with the same
rpc_secret - Add bootstrap peers to connect nodes
- Distribute nodes across zones
Example Multi-Node Configuration
[rpc]rpc_secret = "shared-secret-across-all-nodes"bootstrap_peers = [ "node1.example.com:3901", "node2.example.com:3901"]Zone Configuration
Organize nodes into zones for fault tolerance:
# Assign nodes to different zonesgarage layout assign node1-id --zone zone1 --capacity 100Ggarage layout assign node2-id --zone zone2 --capacity 100Ggarage layout assign node3-id --zone zone3 --capacity 100G
# Apply the layoutgarage layout apply --version 1Monitoring and Administration
Admin API
Use the admin API for monitoring:
# Get cluster statuscurl -H "Authorization: Bearer $ADMIN_TOKEN" \ https://your-app-name.klutch.sh:3903/v0/status
# Get node healthcurl -H "Authorization: Bearer $ADMIN_TOKEN" \ https://your-app-name.klutch.sh:3903/healthMetrics
Garage exposes Prometheus-compatible metrics:
curl -H "Authorization: Bearer $METRICS_TOKEN" \ https://your-app-name.klutch.sh:3903/metricsKey metrics to monitor:
| Metric | Description |
|---|---|
garage_data_bytes | Total stored data |
garage_meta_bytes | Metadata storage |
garage_s3_requests_total | S3 API requests |
garage_rpc_request_duration | RPC latency |
Logs
Access Garage logs through:
- Klutch.sh Dashboard: View runtime logs
- RUST_LOG: Configure log levels
- Container logs: Standard output logging
Production Best Practices
Security Recommendations
- Strong Secrets: Use cryptographically secure random strings for all secrets
- HTTPS Only: Always access Garage via HTTPS
- Access Key Rotation: Regularly rotate access keys
- Minimal Permissions: Grant only required permissions to keys
- Network Security: Restrict RPC port access between trusted nodes
Performance Optimization
- Block Size: Tune block size for your workload (smaller for many small files, larger for big files)
- Compression: Enable compression for compressible data
- Storage Sizing: Allocate sufficient storage for data and metadata
- Memory: Allocate memory based on metadata size
Backup Strategy
Protect your data:
- Replication: Use replication mode 3 for production
- Cross-Zone: Distribute across multiple zones
- Key Backup: Securely store access keys
- Metadata Backup: Regular metadata snapshots
Troubleshooting Common Issues
Node Won’t Join Cluster
Symptoms: Node starts but doesn’t connect to other nodes.
Solutions:
- Verify
rpc_secretmatches across all nodes - Check network connectivity to bootstrap peers
- Ensure RPC port (3901) is accessible
- Review logs for connection errors
S3 Operations Failing
Symptoms: S3 requests return errors.
Solutions:
- Verify access key permissions
- Check bucket exists and is accessible
- Ensure endpoint URL is correct
- Review Garage logs for specific errors
Layout Not Applying
Symptoms: Layout changes don’t take effect.
Solutions:
- Increment layout version number
- Ensure all nodes are reachable
- Check for layout conflicts
- Wait for layout propagation
Storage Full
Symptoms: Uploads fail, storage errors in logs.
Solutions:
- Check available disk space
- Expand persistent volume
- Enable garbage collection
- Review data retention policies
Updating Garage
To update to a newer version:
- Review Release Notes: Check Garage changelog
- Backup Data: Ensure data is replicated or backed up
- Update Dockerfile: Change the image tag
- Push Changes: Commit and push to trigger redeployment
- Verify: Test S3 operations after update
Additional Resources
- GarageHQ Official Website
- Garage Documentation
- Garage Source Code
- Garage Cookbook
- Garage Matrix Chat
- Klutch.sh Persistent Volumes
- Klutch.sh Deployments
Conclusion
Deploying Garage on Klutch.sh gives you a powerful, self-hosted S3-compatible object storage system with automatic builds, persistent storage, and secure HTTPS access. The combination of Garage’s lightweight distributed architecture and Klutch.sh’s deployment simplicity means you can focus on building applications rather than managing storage infrastructure.
With support for S3 API compatibility, geo-distribution, and automatic replication, Garage on Klutch.sh provides enterprise-grade object storage that runs on commodity infrastructure. Whether you’re storing application data, hosting static websites, or building a multi-region storage cluster, Garage delivers the reliability you need with complete control over your data.