
Garage est un stockage objet S3 auto-hébergé conçu pour être simple, léger et géo-distribué. Un seul binaire Rust de ~25 Mo, ~50 Mo de RAM par nœud, aucune dépendance externe : c’est l’alternative idéale à MinIO ou Ceph RGW quand vous avez besoin de S3 sans la complexité. Ce guide déploie un cluster 3 nœuds avec réplication en 3 zones, teste l’API S3 et l’hébergement web statique, avec toutes les commandes vérifiées sur Ubuntu 24.04.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Architecture Garage : hash ring, zones, CRDT, quorum
- Lab complet : cluster 3 nœuds avec KVM et systemd
- API S3 : buckets, clés, upload/download avec AWS CLI
- Site web statique : héberger un site directement depuis un bucket
- Administration : layout, clés, monitoring, dépannage
Qu’est-ce que Garage ?
Section intitulée « Qu’est-ce que Garage ? »Garage est un système de stockage objet distribué open source créé par l’association française Deuxfleurs. Il fournit une API compatible S3 et un module d’hébergement web statique, le tout dans un unique binaire Rust sans dépendance.
Analogie : imaginez un réseau de casiers postaux répartis dans 3 villes différentes (les zones). Quand vous déposez un colis (un objet S3) dans n’importe quel bureau, il est automatiquement copié dans les 2 autres villes. Si un bureau ferme, les 2 autres continuent à servir vos colis. Garage fonctionne exactement comme ça : sans chef central, chaque nœud est autonome.
Ce qui distingue Garage
Section intitulée « Ce qui distingue Garage »| Caractéristique | Description |
|---|---|
| Ultra-léger | Un seul binaire (~25 Mo), ~50 Mo de RAM par nœud. Tourne sur un Raspberry Pi |
| Géo-distribué | Conçu nativement pour répartir les données sur plusieurs sites (zones) |
| S3 compatible | API S3 standard, fonctionne avec AWS CLI, MinIO Client, Rclone, Restic |
| Web statique | Héberge des sites directement depuis les buckets (port dédié) |
| Sans dépendance | Pas de Docker, pas de base de données externe, pas de JVM |
| CRDT | Résolution de conflits sans coordination centrale |
| Open source | Licence AGPLv3, développé par Deuxfleurs |
Garage vs alternatives
Section intitulée « Garage vs alternatives »| Critère | Garage | MinIO | Ceph RGW | SeaweedFS |
|---|---|---|---|---|
| Type de stockage | Objet (S3) | Objet (S3) | Objet + Bloc + Fichier | Objet + Fichier |
| Ressources | ~50 Mo RAM/nœud | ~1 Go RAM/nœud | ~4 Go RAM minimum | ~200 Mo RAM/nœud |
| Complexité | Très faible | Faible | Élevée | Modérée |
| Géo-distribution | Native (zones) | Site replication | RADOS multi-site | Multi-datacenter |
| Licence | AGPLv3 | AGPLv3 | LGPL | Apache 2.0 |
| Cas d’usage | Self-hosted S3 petit/moyen | S3 haute perf | Cloud privé complet | S3 + fichiers |
| K8s natif | Non (mais utilisable) | Opérateur officiel | Rook | Opérateur CSI |
Architecture et concepts clés
Section intitulée « Architecture et concepts clés »Fonctionnement interne
Section intitulée « Fonctionnement interne »Garage utilise un hash ring (anneau de hachage) pour distribuer les données
entre les nœuds. Chaque objet est découpé en blocs de 1 Mo (par défaut),
chaque bloc est répliqué selon le replication_factor (typiquement 3).
Les composants clés :
-
Nœud : une instance Garage (un binaire, un fichier de config). Tous les nœuds sont égaux, il n’y a pas de maître.
-
Zone : un regroupement logique de nœuds (datacenter, rack, site géographique). Garage garantit que chaque copie d’un objet est stockée dans une zone différente.
-
Layout : la carte du cluster qui définit la capacité et la zone de chaque nœud. Doit être appliqué explicitement après modification.
-
Partition : subdivision du hash ring. Les données sont assignées aux partitions, elles-mêmes assignées aux nœuds selon le layout.
Modèle de cohérence
Section intitulée « Modèle de cohérence »Garage utilise des CRDT (Conflict-free Replicated Data Types) pour les métadonnées et un quorum pour les opérations de données :
- Écriture : réussit quand une majorité de nœuds (2/3 en replication_factor=3) confirment
- Lecture : renvoie la donnée dès qu’un nœud répond (mode
consistent: vérifie le quorum) - Cohérence : read-after-write garantie en mode
consistent
Ports réseau
Section intitulée « Ports réseau »| Port | Protocole | Usage |
|---|---|---|
| 3900 | HTTP | API S3 (accès client) |
| 3901 | TCP | RPC inter-nœuds (protocole interne) |
| 3902 | HTTP | Hébergement web statique |
| 3903 | HTTP | API d’administration + métriques Prometheus |
Lab : déployer un cluster Garage 3 nœuds
Section intitulée « Lab : déployer un cluster Garage 3 nœuds »Prérequis
Section intitulée « Prérequis »- 3 machines (VMs, serveurs physiques ou même Raspberry Pi)
- Ubuntu 24.04 (ou toute distro Linux)
- 512 Mo de RAM et 1 vCPU minimum par nœud
- Connectivité réseau entre les 3 nœuds (port 3901)
Créer les VMs avec KVM
Section intitulée « Créer les VMs avec KVM »Le script suivant crée 3 VMs légères avec cloud-init :
#!/bin/bash# Créer 3 VMs pour le lab Garage (1 Go RAM, 1 vCPU, 10 Go disque)for i in 1 2 3; do sudo qemu-img create -f qcow2 \ -b /var/lib/libvirt/images/ubuntu-24.04-cloud.img -F qcow2 \ /var/lib/libvirt/images/garage${i}.qcow2 10G
sudo virt-install --name garage${i} \ --ram 1024 --vcpus 1 \ --disk /var/lib/libvirt/images/garage${i}.qcow2 \ --os-variant ubuntu24.04 \ --cloud-init user-data=cloud-init-garage${i}.yaml \ --network network=default \ --graphics none --noautoconsole --importdoneChaque VM utilise un fichier cloud-init (adapter le hostname) :
#cloud-confighostname: garage1users: - name: bob groups: sudo shell: /bin/bash sudo: ALL=(ALL) NOPASSWD:ALL ssh_authorized_keys: - ssh-ed25519 AAAA... votre-clé-publiquepackages: - chronyInstaller et configurer Garage
Section intitulée « Installer et configurer Garage »-
Télécharger le binaire sur chaque nœud
Garage est un binaire statique unique. Le chemin de téléchargement utilise un répertoire
x86_64-unknown-linux-musl: c’est un binaire compilé avec musl, compatible avec toutes les distributions Linux sans dépendance :Fenêtre de terminal curl -fsSL -o /usr/local/bin/garage \https://garagehq.deuxfleurs.fr/_releases/v2.2.0/x86_64-unknown-linux-musl/garagechmod +x /usr/local/bin/garageVérification :
Fenêtre de terminal garage --version# garage v2.2.0 [features: bundled-libs, consul-discovery, lmdb, ...] -
Générer le secret RPC partagé
Tous les nœuds du cluster doivent partager le même secret RPC pour s’authentifier mutuellement :
Fenêtre de terminal openssl rand -hex 32# 22c9b4a6b8225ee259298ee643512676e956a2e50702a18bc9a68141c3625e28Conservez cette valeur : elle sera identique dans la configuration de chaque nœud.
-
Créer le fichier de configuration
Sur chaque nœud, créez
/etc/garage.toml(adapterrpc_public_addrà l’IP du nœud) :metadata_dir = "/var/lib/garage/meta"data_dir = "/var/lib/garage/data"db_engine = "lmdb"metadata_auto_snapshot_interval = "6h"replication_factor = 3consistency_mode = "consistent"compression_level = 1rpc_secret = "22c9b4a6b8225ee259298ee643512676e956a2e50702a18bc9a68141c3625e28"rpc_bind_addr = "[::]:3901"rpc_public_addr = "192.168.122.236:3901"[s3_api]api_bind_addr = "[::]:3900"s3_region = "garage"root_domain = ".s3.garage"[s3_web]bind_addr = "[::]:3902"root_domain = ".web.garage"[admin]api_bind_addr = "0.0.0.0:3903"Les paramètres essentiels :
Paramètre Rôle replication_factorNombre de copies de chaque objet (3 = tolérance 1 panne) consistency_modeconsistentgarantit read-after-write,degradedprivilégie la disponibilitédb_enginelmdbest le plus rapide et le plus testécompression_level1= compression zstd légère,0= désactivéerpc_secretClé partagée entre tous les nœuds (identique partout) rpc_public_addrAdresse IP accessible par les autres nœuds -
Créer le service systemd
Fenêtre de terminal sudo mkdir -p /var/lib/garage/meta /var/lib/garage/datasudo tee /etc/systemd/system/garage.service << 'EOF'[Unit]Description=Garage S3-compatible object storeAfter=network-online.targetWants=network-online.target[Service]Type=simpleExecStart=/usr/local/bin/garage serverRestart=alwaysRestartSec=5StateDirectory=garageProtectSystem=full[Install]WantedBy=multi-user.targetEOFsudo systemctl daemon-reloadsudo systemctl enable --now garageVérification :
Fenêtre de terminal sudo systemctl status garage# ● garage.service - Garage S3-compatible object store# Active: active (running) since ... -
Connecter les nœuds entre eux
Chaque nœud possède un identifiant unique généré automatiquement au premier démarrage. Récupérez-le :
Fenêtre de terminal garage node id# 794367e3ef23feb8...@192.168.122.236:3901Depuis n’importe quel nœud, connectez les autres :
Fenêtre de terminal garage node connect <ID_NOEUD2>@192.168.122.115:3901# Success.garage node connect <ID_NOEUD3>@192.168.122.5:3901# Success.Vérification :
Fenêtre de terminal garage status==== HEALTHY NODES ====ID Hostname Address Tags Zone Capacity DataAvail Version794367e3ef23feb8 garage1 192.168.122.236:3901 NO ROLE ASSIGNED v2.2.0d0fb5d2f74e66c45 garage2 192.168.122.115:3901 NO ROLE ASSIGNED v2.2.079ab760dda72a403 garage3 192.168.122.5:3901 NO ROLE ASSIGNED v2.2.0 -
Assigner les rôles (layout)
Informez Garage de la capacité et de la zone de chaque nœud. Les zones garantissent que les 3 copies d’un objet sont stockées sur 3 sites différents :
Fenêtre de terminal garage layout assign 794367e3 -z dc1 -c 5G -t garage1garage layout assign d0fb5d2f -z dc2 -c 5G -t garage2garage layout assign 79ab760d -z dc3 -c 5G -t garage3Prévisualisez puis appliquez :
Fenêtre de terminal garage layout showgarage layout apply --version 1Partitions are replicated 3 times on at least 3 distinct zones.Optimal partition size: 19.5 MBUsable capacity / total cluster capacity: 15.0 GB / 15.0 GB (100.0 %)Effective capacity (replication factor 3): 5.0 GBVérification finale :
Fenêtre de terminal garage status==== HEALTHY NODES ====ID Hostname Address Tags Zone Capacity DataAvail Version794367e3ef23feb8 garage1 192.168.122.236:3901 [garage1] dc1 5.0 GB 7.2 GB (77.6%) v2.2.0d0fb5d2f74e66c45 garage2 192.168.122.115:3901 [garage2] dc2 5.0 GB 7.2 GB (77.6%) v2.2.079ab760dda72a403 garage3 192.168.122.5:3901 [garage3] dc3 5.0 GB 7.2 GB (77.6%) v2.2.0
Utiliser l’API S3
Section intitulée « Utiliser l’API S3 »Créer un bucket et une clé API
Section intitulée « Créer un bucket et une clé API »Garage sépare les concepts de bucket (espace de stockage) et de clé API (identifiant d’accès). Une clé peut avoir accès à plusieurs buckets avec des permissions différentes.
# Créer une clé APIgarage key create demo-app-key==== ACCESS KEY INFORMATION ====Key ID: GK54fbf9edf0f36dda7eeb5162Key name: demo-app-keySecret key: 0b2d21f3b2911a8b084a81a65ed9cf1e6ef52bf5ead54cba8a5a0c76d869113a# Créer un bucketgarage bucket create demo-bucket
# Autoriser la clé sur le bucket (read + write + owner)garage bucket allow --read --write --owner demo-bucket --key demo-app-keyVérification :
garage bucket info demo-bucket==== BUCKET INFORMATION ====Bucket: 37c984b2c7c9944fa9218b0d3b413d7c671b1a81eab8c9e0389bf4a5e9a29aa3Global alias: demo-bucketObjects: 0
==== KEYS FOR THIS BUCKET ====Permissions Access key Local aliasesRWO GK54fbf9edf0f36dda7eeb5162 demo-app-keyOpérations S3 avec AWS CLI
Section intitulée « Opérations S3 avec AWS CLI »Configurez AWS CLI pour pointer vers votre cluster Garage :
export AWS_ACCESS_KEY_ID="GK54fbf9edf0f36dda7eeb5162"export AWS_SECRET_ACCESS_KEY="0b2d21f3b2911a8b084a81a65ed9cf1e6ef52bf5ead54cba8a5a0c76d869113a"export AWS_DEFAULT_REGION="garage"# Lister les bucketsaws --endpoint-url http://192.168.122.236:3900 s3 ls# 2026-03-01 10:35:11 demo-bucket
# Uploader un fichierecho 'Bonjour depuis le cluster Garage !' > test.txtaws --endpoint-url http://192.168.122.236:3900 s3 cp test.txt s3://demo-bucket/test.txt# upload: ./test.txt to s3://demo-bucket/test.txt
# Lister les objets d'un bucketaws --endpoint-url http://192.168.122.236:3900 s3 ls s3://demo-bucket/# 2026-03-01 10:36:16 35 test.txt
# Télécharger un objetaws --endpoint-url http://192.168.122.236:3900 s3 cp s3://demo-bucket/test.txt -# Bonjour depuis le cluster Garage !
# Supprimer un objetaws --endpoint-url http://192.168.122.236:3900 s3 rm s3://demo-bucket/test.txt# delete: s3://demo-bucket/test.txtGénérer une URL de téléchargement temporaire
Section intitulée « Générer une URL de téléchargement temporaire »Les presigned URLs permettent de partager un objet sans exposer les identifiants S3 :
aws --endpoint-url http://192.168.122.236:3900 \ s3 presign s3://demo-bucket/test.txt --expires-in 3600# http://192.168.122.236:3900/demo-bucket/test.txt?X-Amz-Algorithm=...Le lien est valide 1 heure (3600 secondes). N’importe qui peut le télécharger sans clé API.
Vérifier la réplication
Section intitulée « Vérifier la réplication »L’un des atouts de Garage : les données sont accessibles depuis n’importe quel nœud du cluster, quelle que soit la zone d’upload :
# Upload via garage1aws --endpoint-url http://192.168.122.236:3900 \ s3 cp test.txt s3://demo-bucket/test.txt
# Lecture via garage2 (autre zone)aws --endpoint-url http://192.168.122.115:3900 \ s3 cp s3://demo-bucket/test.txt -# Bonjour depuis le cluster Garage !
# Lecture via garage3 (encore une autre zone)aws --endpoint-url http://192.168.122.5:3900 \ s3 cp s3://demo-bucket/test.txt -# Bonjour depuis le cluster Garage !Héberger un site web statique
Section intitulée « Héberger un site web statique »Garage peut servir un site directement depuis un bucket, sans reverse proxy
supplémentaire. Le module web écoute sur le port 3902 et route les
requêtes via l’en-tête Host.
-
Créer le bucket et activer le mode web
Fenêtre de terminal garage bucket create mon-sitegarage bucket allow --read --write --owner mon-site --key demo-app-keygarage bucket website --allow mon-siteVérification :
Fenêtre de terminal garage bucket info mon-siteWebsite access: trueindex document: index.htmlerror document: (not defined) -
Uploader le contenu
Fenêtre de terminal cat > index.html << 'HTML'<!DOCTYPE html><html><head><title>Mon site sur Garage</title></head><body><h1>Site hébergé sur Garage</h1><p>Stockage S3 distribué, servi directement.</p></body></html>HTMLaws --endpoint-url http://192.168.122.236:3900 \s3 cp index.html s3://mon-site/index.html --content-type text/html -
Tester l’accès
Le module web utilise l’en-tête
Hostpour identifier le bucket :Fenêtre de terminal curl -H 'Host: mon-site.web.garage' http://192.168.122.236:3902/<!DOCTYPE html><html><head><title>Mon site sur Garage</title></head><body><h1>Site hébergé sur Garage</h1><p>Stockage S3 distribué, servi directement.</p></body></html>
Commandes essentielles
Section intitulée « Commandes essentielles »Cluster et nœuds
Section intitulée « Cluster et nœuds »# Statut du cluster (commande la plus utilisée)garage status
# Identifiant du nœud localgarage node id
# Connecter un nœudgarage node connect <ID>@<IP>:3901
# Afficher le layout actuelgarage layout show
# Modifier la capacité d'un nœudgarage layout assign <ID> -z <zone> -c <capacité> -t <tag>
# Appliquer les changements de layoutgarage layout apply --version <N>
# Annuler les changements en attentegarage layout revert# Lister les bucketsgarage bucket list
# Créer un bucketgarage bucket create mon-bucket
# Infos détailléesgarage bucket info mon-bucket
# Activer l'hébergement webgarage bucket website --allow mon-bucket
# Supprimer un bucket (doit être vide)garage bucket delete --yes mon-bucketClés API
Section intitulée « Clés API »# Lister les clésgarage key list
# Créer une clégarage key create ma-cle
# Afficher les infos (avec secret)garage key info --show-secret ma-cle
# Autoriser une clé sur un bucketgarage bucket allow --read --write mon-bucket --key ma-cle
# Révoquer l'accèsgarage bucket deny --read --write mon-bucket --key ma-cle
# Supprimer une clégarage key delete --yes ma-cleMaintenance
Section intitulée « Maintenance »# Lancer un scrub de vérification des donnéesgarage repair scrub start
# Vérifier le statut du scrubgarage repair scrub status
# Snapshot des métadonnéesgarage meta snapshotSécurité
Section intitulée « Sécurité »Clé RPC partagée
Section intitulée « Clé RPC partagée »Le rpc_secret dans garage.toml est la seule barrière d’authentification
entre les nœuds du cluster. Si cette clé est compromise, un attaquant peut
rejoindre le cluster.
| Pratique | Description |
|---|---|
| Secret RPC fort | Générer avec openssl rand -hex 32 (256 bits) |
| Fichier protégé | chmod 600 /etc/garage.toml — seul root doit le lire |
| Réseau dédié | Isoler le port RPC (3901) sur un VLAN interne |
| Pare-feu | Exposer uniquement 3900 (S3) aux clients, bloquer 3901/3903 de l’extérieur |
| TLS | Placer un reverse proxy TLS devant le port 3900 pour les clients |
| Clés API | Créer une clé par application avec les droits minimaux |
Dépannage
Section intitulée « Dépannage »Problèmes courants et solutions
Section intitulée « Problèmes courants et solutions »| Symptôme | Cause probable | Solution |
|---|---|---|
garage status affiche 0 nœuds | Le service ne tourne pas | sudo systemctl status garage puis vérifier les logs : journalctl -u garage |
Nœud visible mais NO ROLE ASSIGNED | Layout non appliqué | garage layout assign + garage layout apply --version N |
Connection refused sur le port 3901 | Pare-feu ou mauvaise IP | Vérifier rpc_public_addr et ufw allow 3901/tcp |
Unauthorized sur l’API S3 | Clé API incorrecte ou pas de permission | Vérifier garage key info et garage bucket allow |
| Upload OK mais lecture échoue | replication_factor=3 avec moins de 3 nœuds up | Vérifier garage status, attendre la re-synchronisation |
rpc_secret mismatch dans les logs | Secrets RPC différents entre nœuds | Vérifier que /etc/garage.toml a le même rpc_secret partout |
Layout version mismatch | Layout non propagé | Relancer garage layout apply --version N |
| Site web renvoie 404 | Pas de fichier index.html ou web non activé | garage bucket website --allow et vérifier le upload |
Commandes de diagnostic
Section intitulée « Commandes de diagnostic »# Logs du servicesudo journalctl -u garage -f --no-pager
# Statut détaillé du clustergarage status
# Vérifier l'intégrité des donnéesgarage repair scrub startgarage repair scrub status
# Vérifier les métriques (si admin API activée)curl http://localhost:3903/metricsBonnes pratiques
Section intitulée « Bonnes pratiques »Dimensionnement
Section intitulée « Dimensionnement »| Composant | Minimum (test) | Recommandé (production) |
|---|---|---|
| Nœuds | 3 | 3+ (au moins 3 zones) |
| RAM par nœud | 512 Mo | 1-2 Go |
| CPU | 1 vCPU | 2+ vCPU |
| Réseau | 100 Mbps | 1 Gbps+ entre zones |
| Disque | HDD | SSD pour les métadonnées, HDD pour les données |
Organisation
Section intitulée « Organisation »- Séparer métadonnées et données sur des disques différents en production :
SSD pour
metadata_dir(accès aléatoire intense), HDD pourdata_dir(accès séquentiel). - Une clé API par application : ne pas partager les clés entre services.
- Nommer les tags pour identifier les nœuds :
garage layout assign <ID> -t "paris-srv01". - 3 zones minimum avec
replication_factor = 3pour une vraie tolérance aux pannes de site. - Snapshots automatiques des métadonnées :
metadata_auto_snapshot_interval(6h par défaut) crée des sauvegardes du fichier LMDB.
Performance
Section intitulée « Performance »compression_level = 1(zstd rapide) est un bon compromis. Passez à0pour du contenu déjà compressé (images, vidéos, archives).block_size = "1M"(défaut) convient à la plupart des workloads. Augmentez à4Mou64Mpour des fichiers volumineux.consistency_mode = "degraded"si la disponibilité prime sur la cohérence stricte (lectures servies même si un nœud est down, sans vérifier le quorum).
À retenir
Section intitulée « À retenir »- Garage = stockage S3 ultra-léger : un seul binaire Rust, ~50 Mo de RAM, aucune dépendance.
- Géo-distribution native : les zones garantissent que chaque copie est stockée sur un site différent.
- Pas de maître : tous les nœuds sont égaux, le hash ring distribue les données.
- 3 commandes suffisent pour un cluster :
node connect,layout assign,layout apply. - API S3 standard : fonctionne avec AWS CLI, MinIO Client, Rclone, Restic.
- Hébergement web intégré : servez un site statique directement depuis un bucket.
- Idéal pour : sauvegardes, stockage Nextcloud, artefacts CI/CD, sites statiques, partage de fichiers.
- Pas adapté pour : stockage bloc (VM), systèmes de fichiers POSIX, workloads haute performance à faible latence.
Prochaines étapes
Section intitulée « Prochaines étapes »Ressources
Section intitulée « Ressources »- Site officiel : garagehq.deuxfleurs.fr
- Documentation : garagehq.deuxfleurs.fr/documentation
- Releases : git.deuxfleurs.fr/Deuxfleurs/garage/releases
- Code source : git.deuxfleurs.fr/Deuxfleurs/garage
- Matrix :
#garage:deuxfleurs.fr