Documentation Index Fetch the complete documentation index at: https://mintlify.com/deuxfleurs-org/garage/llms.txt
Use this file to discover all available pages before exploring further.
Garage can serve as the storage backend for many popular web applications. This guide covers tested integrations with various platforms including file sharing, social media, and chat applications.
Supported Applications
Application Status Notes Nextcloud ✅ Both Primary Storage and External Storage Mastodon ✅ Natively supported Peertube ✅ Requires website endpoint Matrix ✅ Via synapse-s3-storage-provider Gitea ✅ LFS, avatars, and attachments Pleroma ✅ Natively supported Lemmy ✅ Via pict-rs ejabberd ✅ Via mod_s3_upload Ente ✅ Photo storage alternative Pixelfed ❓ Natively supported, not yet tested Funkwhale ❓ Not yet tested Misskey ❓ Not yet tested
Nextcloud
Nextcloud is a popular file synchronization and sharing platform. Garage can be configured as either Primary Storage (all data on S3) or External Storage (selective data on S3).
Prerequisites
First, create a key and bucket:
garage key create nextcloud-key
garage bucket create nextcloud
garage bucket allow nextcloud --read --write --key nextcloud-key
Note the Key ID and Secret Key for later use.
Primary Storage
Primary storage stores all Nextcloud data on S3 in an opaque manner, providing the best performance.
Edit your Nextcloud configuration file (typically /var/www/nextcloud/config/config.php):
<? php
$CONFIG = array (
/* your existing configuration */
'objectstore' => [
'class' => ' \\ OC \\ Files \\ ObjectStore \\ S3' ,
'arguments' => [
'bucket' => 'nextcloud' ,
'autocreate' => false , // Garage does not support autocreate
'key' => 'GKxxxx' , // Your Key ID
'secret' => 'xxxx' , // Your Secret Key
'hostname' => '127.0.0.1' ,
'port' => 3900 ,
'use_ssl' => false ,
'region' => 'garage' ,
'use_path_style' => true // Required for Garage
],
],
);
SSE-C Encryption (Garage v1.0+)
For enhanced security, enable server-side encryption with customer keys:
Configure SSL
Ensure Garage is accessible via SSL with a valid public certificate.
Update Configuration
Add the encryption key to your config.php: 'objectstore' => [
'class' => ' \\ OC \\ Files \\ ObjectStore \\ S3' ,
'arguments' => [
// ... other settings ...
'sse_c_key' => 'your-generated-key-here' ,
],
],
External Storage
GUI Configuration
CLI Configuration
Activate “External storage support” from Applications page
Go to Settings → External Storage
Add new storage with these settings:
Folder name : Choose a name (e.g., “shared”)
Storage type : Amazon S3
Authentication : Access Key
Bucket : Your bucket name
Host : Your Garage endpoint
Port : Your Garage port (e.g., 3900)
Region : garage (or your configured region)
Enable SSL if using HTTPS
Enable Path access
Leave Legacy authentication (v2) unchecked
Enter your Key ID and Secret Key
Click the checkmark to save
# Install external storage app
php occ app:install files_external
# Create mount point
php occ files_external:create \
-c bucket=nextcloud \
-c hostname= 127.0.0.1 \
-c port= 3900 \
-c region=garage \
-c use_ssl= false \
-c use_path_style= true \
-c legacy_auth= false \
-c key=GKxxxx \
-c secret=xxxx \
shared amazons3 amazons3::accesskey
Mastodon
Mastodon natively supports S3 for media storage with direct serving from Garage.
Mastodon stores many small objects (average 50-150 KB). For optimal performance:
Use Garage v0.8.0+ with LMDB database engine
Store the Garage database on SSD storage
Setup
Create Bucket
garage key create mastodon-key
garage bucket create mastodon-data
garage bucket allow mastodon-data --read --write --key mastodon-key
Configure Website Access
garage bucket alias mastodon-data my-social-media.mydomain.tld
garage bucket website --allow mastodon-data
Setup Reverse Proxy
Configure a reverse proxy to serve media files over HTTPS.
Clean Up Before Migration
Reduce migration time by removing old media:
RAILS_ENV = production bin/tootctl media remove --days 3
RAILS_ENV = production bin/tootctl media remove --days 15 --prune-profiles
RAILS_ENV = production bin/tootctl media remove-orphans
RAILS_ENV = production bin/tootctl preview_cards remove --days 15
Migrate Data
Use the Minio client for efficient migration:
mc mirror ./public/system/ garage/mastodon-data
Add to your .env.production:
S3_ENABLED = true
S3_ENDPOINT = http://my-garage-instance.mydomain.tld:3900
S3_REGION = garage
S3_BUCKET = mastodon-data
AWS_ACCESS_KEY_ID = GKxxxx
AWS_SECRET_ACCESS_KEY = xxxx
S3_ALIAS_HOST = my-social-media.mydomain.tld
Final Sync
After Mastodon is using Garage, run a final sync:
mc mirror --newer-than "3h" ./public/system/ garage/mastodon-data
Peertube
Peertube offloads video serving directly to Garage endpoints.
Create Resources
garage key create peertube-key
garage bucket create peertube-videos
garage bucket create peertube-playlists
garage bucket allow peertube-videos --read --write --owner --key peertube-key
garage bucket allow peertube-playlists --read --write --owner --key peertube-key
garage bucket website --allow peertube-videos
garage bucket website --allow peertube-playlists
export CORS = '{"CORSRules":[{"AllowedHeaders":["*"],"AllowedMethods":["GET"],"AllowedOrigins":["*"]}]}'
aws --endpoint http://s3.garage.localhost s3api put-bucket-cors --bucket peertube-videos --cors-configuration $CORS
aws --endpoint http://s3.garage.localhost s3api put-bucket-cors --bucket peertube-playlists --cors-configuration $CORS
Edit config/production.yaml:
object_storage :
enabled : true
endpoint : 'http://localhost:3900'
region : 'garage'
credentials :
access_key_id : 'GKxxxx'
secret_access_key : 'xxxx'
max_upload_part : 2GB
proxy :
proxify_private_files : false
streaming_playlists :
bucket_name : 'peertube-playlists'
prefix : ''
base_url : 'http://peertube-playlists.web.garage.localhost'
videos :
bucket_name : 'peertube-videos'
prefix : ''
base_url : 'http://peertube-videos.web.garage.localhost'
Starting from Peertube v5.0, per-object ACL features are not supported by Garage, which may impact private video security.
Matrix
Matrix servers can use Garage for media storage.
Synapse with s3-storage-provider
Install the module:
pip3 install --user git+https://github.com/matrix-org/synapse-s3-storage-provider.git
Create bucket and key:
garage key create matrix-key
garage bucket create matrix
garage bucket allow matrix --read --write --key matrix-key
Edit /etc/matrix-synapse/homeserver.yaml:
media_storage_providers :
- module : s3_storage_provider.S3StorageProviderBackend
store_local : True
store_remote : True
store_synchronous : True
config :
bucket : matrix
region_name : garage
endpoint_url : http://localhost:3900
access_key_id : "GKxxxx"
secret_access_key : "xxxx"
Cache Garbage Collection
Create a script to clean up local cache (~/.local/bin/matrix-cache-gc):
#!/bin/bash
## CONFIGURATION ##
AWS_ACCESS_KEY_ID = GKxxxx
AWS_SECRET_ACCESS_KEY = xxxx
AWS_ENDPOINT_URL = http://localhost:3900
S3_BUCKET = matrix
MEDIA_STORE = /var/lib/matrix-synapse/media
PG_USER = matrix
PG_PASS = xxxx
PG_DB = synapse
PG_HOST = localhost
PG_PORT = 5432
## CODE ##
PATH = $HOME /.local/bin/: $PATH
cat > database.yaml << EOF
user: $PG_USER
password: $PG_PASS
database: $PG_DB
host: $PG_HOST
port: $PG_PORT
EOF
s3_media_upload update-db 1d
s3_media_upload --no-progress check-deleted $MEDIA_STORE
s3_media_upload --no-progress upload $MEDIA_STORE $S3_BUCKET --delete --endpoint-url $AWS_ENDPOINT_URL
Make executable and add to crontab:
chmod +x ~/.local/bin/matrix-cache-gc
crontab -e
# Add: */10 * * * * $HOME/.local/bin/matrix-cache-gc
Gitea
Gitea can store Git LFS data, avatars, and attachments in Garage.
Setup
garage key create gitea-key
garage bucket create gitea
garage bucket allow gitea --read --write --key gitea-key
Configuration
Config File
Environment Variables
Edit /etc/gitea/conf/app.ini: [storage]
STORAGE_TYPE =minio
MINIO_ENDPOINT =localhost:3900
MINIO_ACCESS_KEY_ID =GKxxxx
MINIO_SECRET_ACCESS_KEY =xxxx
MINIO_BUCKET =gitea
MINIO_LOCATION =garage
MINIO_USE_SSL =false
GITEA__storage__STORAGE_TYPE = minio
GITEA__storage__MINIO_ENDPOINT = localhost:3900
GITEA__storage__MINIO_ACCESS_KEY_ID = GKxxxx
GITEA__storage__MINIO_SECRET_ACCESS_KEY = xxxx
GITEA__storage__MINIO_BUCKET = gitea
GITEA__storage__MINIO_LOCATION = garage
GITEA__storage__MINIO_USE_SSL = false
Restart Gitea and test by uploading a custom avatar.
Pleroma
Pleroma natively supports S3 storage for media files.
Setup
garage key new --name pleroma-key
garage bucket create pleroma
garage bucket allow pleroma --read --write --owner --key pleroma-key
garage bucket website --allow pleroma
Configuration
Edit /etc/pleroma/config.exs:
config :pleroma , Pleroma . Upload ,
uploader: Pleroma . Uploaders . S3 ,
base_url: "https://pleroma.garage.example.tld"
config :ex_aws , :s3 ,
access_key_id: "GKxxxx" ,
secret_access_key: "xxxx" ,
region: "garage" ,
host: "api.garage.example.tld"
Data Migration
Sync existing uploads:
mc mirror /var/lib/pleroma/uploads/ garage/pleroma
Lemmy
Lemmy uses pict-rs for media handling, which supports S3 backends (requires pict-rs >= 4.0.0).
Setup
garage key new --name pictrs-key
garage bucket create pictrs-data
garage bucket allow pictrs-data --read --write --key pictrs-key
Configuration
Config File
Environment Variables
Add to pict-rs.toml: [ store ]
type = 'object_storage'
endpoint = 'http://my-garage-instance.mydomain.tld:3900'
bucket_name = 'pictrs-data'
region = 'garage'
access_key = 'GKxxxx'
secret_key = 'xxxx'
PICTRS__STORE__TYPE = object_storage
PICTRS__STORE__ENDPOINT = http://my-garage-instance.mydomain.tld:3900
PICTRS__STORE__BUCKET_NAME = pictrs-data
PICTRS__STORE__REGION = garage
PICTRS__STORE__ACCESS_KEY = GKxxxx
PICTRS__STORE__SECRET_KEY = xxxx
ejabberd
ejabberd XMPP server can use Garage for media uploads via mod_s3_upload.
Setup
ejabberdctl module_install mod_s3_upload
garage key new --name ejabberd
garage bucket create objects.xmpp-server.fr
garage bucket allow objects.xmpp-server.fr --read --write --key ejabberd
garage bucket website --allow objects.xmpp-server.fr
Configuration
mod_s3_upload :
bucket_url : https://my-garage-instance.mydomain.tld/objects.xmpp-server.fr
access_key_id : GKxxxx
access_key_secret : xxxx
region : garage
download_url : https://objects.xmpp-server.fr
Users should enable E2EE to protect data-at-rest since media is publicly accessible via URLs.
Ente
Ente is a self-hostable alternative to Google Photos and Apple Photos.
Setup
garage bucket create ente
garage key create ente-key
garage bucket allow ente --read --write --owner --key ente-key
export CORS = '{"CORSRules":[{"AllowedHeaders":["*"],"AllowedMethods":["GET","PUT","POST","DELETE"],"AllowedOrigins":["*"],"ExposeHeaders":["ETag"]}]}'
aws s3api put-bucket-cors --bucket ente --cors-configuration $CORS
Create credentials.yaml:
db :
host : postgres
port : 5432
name : ente_db
user : ente_user
password : ente_password
s3 :
hot_storage :
primary : b2-eu-cen
are_local_buckets : true
b2-eu-cen :
key : GKxxxx
secret : xxxx
endpoint : garage:3900
region : garage
bucket : ente
use_path_style : true
Run with Docker:
docker run -d --name ente-server \
--restart unless-stopped \
-v /path/to/museum.yaml:/museum.yaml \
-v /path/to/credentials.yaml:/credentials.yaml \
-p 8080:8080 \
ghcr.io/ente-io/ente-server
Additional Resources
CLI Tools Configure AWS CLI, rclone, and other S3 tools
Static Websites Host static websites with Hugo, Jekyll, and more
Backup Tools Use Restic, Duplicity, and other backup solutions
Docker Registry Configure Docker registry with Garage backend