VexObj est une plateforme de stockage objet auto-hébergée, compatible avec l'API Amazon S3. Elle fournit le chiffrement au repos (AES-256-GCM), le versioning, l'object lock en mode WORM, et la réplication asynchrone primary-replica. Distribuée sous forme de binaire unique sans dépendances externes.
Débit AES-256-GCM. Le chiffrement au repos n'introduit pas de surcoût perceptible sur les charges courantes.
Vérifications SigV4 par cœur et par seconde. Contrôle complet de signature, pas uniquement validation de la clé d'accès.
Binaire autonome. Aucun runtime, interpréteur, ou orchestrateur de conteneurs requis au déploiement.
Méthodologie et résultats par taille de payload : docs/benchmarks.md. Benchmarks reproductibles localement via cargo bench.
Toutes les fonctionnalités ci-dessous sont incluses dans la version 0.1.0. Couverture de tests, documentation API (OpenAPI) et benchmarks disponibles dans le dépôt.
Le préfixe /s3/* expose une API compatible avec les clients AWS SDK standards. Les en-têtes Authorization sont entièrement vérifiés : la requête canonique est reconstruite à partir des données reçues par le serveur et les HMAC sont comparés en temps constant. Toute requête altérée en transit est rejetée avec un code HTTP 403.
Chiffrement AES-256-GCM au repos. Les clés par blob sont dérivées par HKDF à partir d'une clé maître et du SHA-256 du contenu en clair, ce qui préserve la déduplication content-addressable : deux uploads identiques produisent un ciphertext identique.
Historique de versions par clé via le paramètre ?version_id= sur GET et DELETE, avec endpoint de purge dédié. La rétention par objet (mode WORM) et le legal hold bloquent toute suppression avec un code HTTP 409 jusqu'à l'expiration de la période de rétention.
Chaque écriture ajoute un événement atomique à un log de réplication. Les répliques consomment ce log, récupèrent les blobs content-addressed via HTTP, et les appliquent directement en base. Une commande CLI dédiée permet la promotion d'une réplique en cas de défaillance du nœud primary.
Redimensionnement, recadrage et conversion de format via paramètres d'URL. Négociation automatique entre AVIF, WebP et JPEG selon l'en-tête Accept. Cache à deux niveaux en amont (LRU en mémoire + cache disque borné) pour optimiser la distribution via CDN.
Règles d'expiration par préfixe, exécutables à la demande ou sur planification. Quotas par bucket en volume et en nombre d'objets. Journal d'audit persistant en SQLite pour chaque écriture : acteur, action, cible, adresse IP source.
Métriques exposées au format Prometheus sur /metrics, interface d'administration embarquée sur /dashboard, et dashboard Grafana prêt à importer couvrant les latences p50/p95/p99, le taux d'erreur et le débit.
SDKs TypeScript (fetch natif, aucune dépendance), Python (httpx, dataclasses typées) et Go (net/http standard, aucune dépendance). Couverture complète des opérations CRUD, du versioning, de l'object lock et des politiques de cycle de vie.
# Création d'un bucket, upload d'une image, transformation à la volée. curl -X POST http://localhost:8000/v1/buckets \ -H "Authorization: Bearer $VFS_KEY" \ -d '{"name": "photos"}' curl -X PUT http://localhost:8000/v1/objects/photos/beach.jpg \ -H "Authorization: Bearer $VFS_KEY" \ -H "Content-Type: image/jpeg" \ --data-binary @beach.jpg # Téléchargement au format WebP à 400 pixels de large. curl "http://localhost:8000/v1/objects/photos/beach.jpg?w=400&format=webp" \ -H "Authorization: Bearer $VFS_KEY" -o beach.webp
import { VexObj } from "@vexobj/client"; const vfs = new VexObj({ baseUrl: "http://localhost:8000", apiKey: process.env.VFS_KEY!, }); await vfs.enableVersioning("photos"); await vfs.putObject("photos", "beach.jpg", file, "image/jpeg"); // Application d'une rétention de 30 jours et d'un legal hold. await vfs.setLock("photos", "beach.jpg", { retain_until: new Date(Date.now() + 30 * 86_400_000).toISOString(), legal_hold: true, });
from vexobj import VexObj vfs = VexObj("http://localhost:8000", api_key=os.environ["VFS_KEY"]) vfs.enable_versioning("photos") vfs.put_object("photos", "beach.jpg", open("beach.jpg", "rb"), "image/jpeg") # Chaque PUT crée une nouvelle version sur un bucket versionné. versions = vfs.list_versions("photos", "beach.jpg") for v in versions: print(v.version_id, v.size, v.is_latest)
import "github.com/vortex-soft/vexobj/sdks/go" c := vexobj.New("http://localhost:8000", os.Getenv("VFS_KEY")) // Règle d'expiration à 7 jours sous le préfixe tmp/. rule, _ := c.CreateLifecycleRule("photos", "tmp/", 7) fmt.Println("rule id:", rule.ID) // Exécution immédiate, sans attendre la prochaine planification. expired, freed, _ := c.RunLifecycle() fmt.Printf("expired %d objects, freed %d bytes\n", expired, freed)
# Réplication continue depuis un nœud primary distant. vexobjctl replicate \ --url http://localhost:8000 \ --key $REPLICA_KEY \ --primary https://primary.example.com \ --primary-key $PRIMARY_KEY \ --cursor-file /var/lib/vexobj/replica.cursor \ --interval 5 # Promotion de la réplique en cas de défaillance du primary. vexobjctl promote \ --url http://localhost:8000 \ --key $REPLICA_KEY \ --cursor-file /var/lib/vexobj/replica.cursor
Un processus, un répertoire de données, une base SQLite pour les métadonnées, des blobs content-addressed organisés sous blobs/<aa>/<bb>/<sha>, et un journal de réplication append-only optionnel. Sauvegarde et restauration via rsync standard.
Trois méthodes d'installation sont disponibles. Au premier démarrage, le serveur génère une clé API administrateur qu'il affiche sur la sortie standard — cette clé doit être conservée, elle ne sera plus affichée par la suite.
Configuration minimale. Un volume pour les données persistantes. Image officielle publiée sur GitHub Container Registry.
docker run -d \ --name vexobj \ -p 8000:8000 \ -v vexobj-data:/data \ ghcr.io/vortex-soft/vexobj:latest
Disponible pour Linux amd64 et macOS arm64. Empreintes SHA-256 signées publiées sur la page de release.
# linux-amd64
curl -LO https://github.com/vortex-soft/vexobj/\
releases/download/v0.1.0/\
vexobj-linux-amd64.tar.gz
tar xzf vexobj-linux-amd64.tar.gz
./vexobj
Rust 1.85 minimum (edition 2024). La suite de tests complète s'exécute en environ deux secondes après un build à chaud.
git clone \
https://github.com/vortex-soft/vexobj.git
cd vexobj
cargo build --release
./target/release/vexobj