Développement Web

Litestream sur VPS avec S3 réplication : tutoriel complet 2026

17 دقائق للقراءة

📍 Article principal : Litestream/Turso 2026 : guide pratique.

Trente minutes pour transformer SQLite local en base répliquée continue vers S3. Recovery point < 1 seconde. Méthode validée chez startups francophones.

Prérequis

  • VPS Linux avec app utilisant SQLite.
  • Bucket S3-compatible (Backblaze B2, MinIO, AWS).
  • Niveau : intermédiaire.
  • Temps : 30-45 min.

Litestream réplique en continu une base SQLite vers un stockage S3 sans interrompre les écritures. Vous avez besoin d’un VPS Linux avec SQLite déjà utilisé par votre application. Un compte S3-compatible (Backblaze B2 à 6 USD/To/mois recommandé pour les budgets serrés, AWS S3 ou MinIO self-hosté possibles aussi). Litestream binaire static téléchargeable depuis litestream.io. Comptez 30-45 minutes pour cette installation initiale incluant la configuration du bucket S3.

Étape 1 — Installer Litestream

wget https://github.com/benbjohnson/litestream/releases/latest/download/litestream-linux-amd64.deb
dpkg -i litestream-linux-amd64.deb
litestream version

Téléchargez le binaire pour votre architecture : wget https://github.com/benbjohnson/litestream/releases/download/v0.5.0/litestream-v0.5.0-linux-amd64.tar.gz && tar xzf litestream-*.tar.gz && sudo mv litestream /usr/local/bin/. Vérifiez avec litestream version qui doit afficher v0.5.0 ou plus récent. Le binaire est statique (Go), pas de dépendances système requises.

Étape 2 — Activer WAL mode SQLite

sqlite3 /srv/app/app.db
PRAGMA journal_mode=WAL;
PRAGMA wal_autocheckpoint=1000;
PRAGMA synchronous=NORMAL;
.exit

WAL mode obligatoire pour Litestream.

Litestream exige le mode WAL (Write-Ahead Logging) de SQLite, qui sépare les écritures dans un fichier log avant le commit. Activez en lançant sqlite3 mabase.db 'PRAGMA journal_mode=WAL;'. Le mode WAL est persistant — il survit aux redémarrages. Vérifiez avec sqlite3 mabase.db 'PRAGMA journal_mode;' qui doit retourner ‘wal’. Sans cette étape, Litestream refuse de démarrer.

Étape 3 — Configuration Litestream

nano /etc/litestream.yml
access-key-id: YOUR_B2_KEY_ID
secret-access-key: YOUR_B2_APPLICATION_KEY

dbs:
  - path: /srv/app/app.db
    replicas:
      - type: s3
        bucket: app-litestream-backup
        endpoint: s3.eu-central-003.backblazeb2.com
        path: prod/app
        region: eu-central-003
        retention: 720h  # 30 jours
        snapshot-interval: 1h
        sync-interval: 1s

Créez /etc/litestream.yml avec la liste des bases à répliquer et leurs cibles S3. Exemple : dbs:
- path: /var/data/app.db
replicas:
- type: s3
bucket: mon-bucket-litestream
path: app/db
endpoint: https://s3.us-west-002.backblazeb2.com
access-key-id: ACCESS_KEY
secret-access-key: SECRET_KEY
. Permissions chmod 600 pour cacher le secret. Litestream chiffre la transmission TLS mais pas le stockage — utilisez encryption-key pour chiffrer côté client si nécessaire.

Étape 4 — Activer service systemd

systemctl enable litestream
systemctl start litestream
systemctl status litestream
journalctl -u litestream -f

Créez /etc/systemd/system/litestream.service avec ExecStart=/usr/local/bin/litestream replicate -config /etc/litestream.yml. Type=simple, Restart=always pour redémarrer en cas de crash. Activez avec sudo systemctl enable --now litestream. Litestream tourne en arrière-plan et réplique chaque transaction WAL vers S3 en quelques secondes après commit. Logs accessibles via journalctl -u litestream -f.

Étape 5 — Vérifier réplication

litestream replicas /srv/app/app.db
litestream snapshots /srv/app/app.db

Après quelques minutes, vérifiez que les snapshots et WAL apparaissent dans S3. Avec mc (MinIO client) configuré : mc ls monb2/mon-bucket-litestream/app/db/. Vous devriez voir des dossiers generations/ avec un timestamp et des fichiers wal/ et snapshots/. Litestream crée un snapshot complet par défaut toutes les 24h et envoie les WAL incrémentaux toutes les secondes, garantissant une fenêtre de perte de données inférieure à 1 seconde en cas de panne.

Étape 6 — Test write

sqlite3 /srv/app/app.db "INSERT INTO users (email) VALUES ('test@example.com')"
# Litestream sync vers B2 dans 1 seconde
sleep 2
litestream snapshots /srv/app/app.db
# Voir nouveau snapshot

Insérez une ligne dans la base : sqlite3 /var/data/app.db "INSERT INTO test VALUES ('check');". Litestream détecte le changement WAL en moins d’une seconde et le pousse vers S3. Surveillez les logs Litestream pour confirmer le push. Cette validation simple confirme que le flux est opérationnel avant de mettre en production avec du trafic réel.

Étape 7 — Restore depuis S3

Simulation crash : supprimer DB, restaurer depuis B2 :

rm /srv/app/app.db /srv/app/app.db-shm /srv/app/app.db-wal
litestream restore /srv/app/app.db
# Restauration depuis B2 dernier snapshot + WAL
sqlite3 /srv/app/app.db "SELECT * FROM users"
# Données récupérées

Pour restaurer la base sur un nouveau VPS (panne disque, migration), arrêtez Litestream sur l’ancien serveur. Sur le nouveau : litestream restore -config /etc/litestream.yml /var/data/app.db. Litestream télécharge le dernier snapshot et applique tous les WAL postérieurs pour reconstituer l’état exact au moment de la dernière transaction. Comptez 1-5 minutes selon la taille de la base et la bande passante.

Étape 8 — Recovery to point in time

litestream restore -timestamp 2026-04-27T10:00:00Z /srv/app/app.db
# Restaure état à un instant T précis

Litestream supporte le PITR (Point-In-Time Recovery). Restaurez la base à un instant précis avec litestream restore -timestamp 2026-05-06T14:30:00Z /var/data/app.db. Idéal pour récupérer après un DROP TABLE accidentel ou une corruption logique. La granularité dépend du retention configuré (24-72h par défaut). Pour une période plus longue, augmentez retention dans la config Litestream et acceptez le surcoût stockage S3.

Étape 9 — Monitoring

litestream replicas /srv/app/app.db -json | jq

Endpoint Prometheus pour Grafana : --exec metrics.

Litestream expose des métriques Prometheus sur le port 9090 par défaut (configurable). Métriques clés : litestream_replica_validation_count_total, litestream_replica_total_seconds, litestream_disk_size. Scrapper avec Prometheus puis dashboard Grafana avec alertes si la réplication s’arrête plus de 5 minutes. Pour les setups simples, Uptime Kuma peut juste pinger l’endpoint /healthz et alerter par email/WhatsApp.

Étape 10 — Multi-DB

Configurer plusieurs bases dans litestream.yml :

dbs:
  - path: /srv/app/users.db
    replicas: [...]
  - path: /srv/app/sessions.db
    replicas: [...]

Pour répliquer plusieurs bases SQLite, listez chacune dans le fichier de config sous dbs:. Litestream gère chaque base indépendamment avec son propre flux WAL. Pour une stack avec 5 microservices SQLite (BookStack, Outline, Plausible, etc.), un seul instance Litestream suffit. Surveillez l’usage CPU — au-delà de 20 bases répliquées en haute fréquence, prévoyez 1 vCPU dédié au process Litestream.

Erreurs fréquentes

Erreur Cause Solution
« database is locked » WAL pas activé PRAGMA journal_mode=WAL
S3 401 unauthorized Keys mal configurées Régénérer B2 application key
Snapshot manqué Service down systemctl status + journalctl
Disk plein WAL accumule wal_autocheckpoint=1000
Restore vide DB pas répliquée Vérifier replicas list
Performance dégradée fsync agressif synchronous=NORMAL

Trois erreurs typiques bloquent les démarrages. Premièrement, la base SQLite ouverte en mode rollback journal (sans WAL) — Litestream refuse et affiche ‘database is not in WAL mode’. Solution : activer WAL via PRAGMA. Deuxièmement, les permissions S3 incorrectes — l’access key doit avoir les permissions s3:PutObject, s3:GetObject, s3:ListBucket sur le bucket. Troisièmement, le bucket inexistant — créez-le manuellement avant le premier démarrage Litestream.

Cas pratiques en zone UEMOA

Trois précisions. B2 Eu-Central-003 : 90 ms vers Afrique Ouest acceptable. Coût : 1 GB DB = 0,006 USD/mois B2. Bandwidth : sync continu utilise ~10 KB/s. Négligeable.

Pour une PME basée à Abidjan ou Cotonou qui héberge une app SQLite (gestion clients, facturation), Litestream + Backblaze B2 coûte typiquement 0,50-2 USD/mois pour 100-1000 transactions/jour. Comparé à PostgreSQL managed (Supabase, Neon) à 25-50 USD/mois, l’économie sur 12 mois justifie largement les 30 minutes de setup. Pour les bases plus volumineuses (10+ Go), considérez plutôt Postgres avec backup pgBackRest qui scale mieux.

Tutoriels frères

Litestream se complète bien avec d’autres briques data. Turso libSQL pour les embedded replicas multi-region (alternative plus moderne mais plus complexe). Backblaze B2 ou MinIO self-hosted comme target S3. Drizzle ORM ou Prisma pour la couche d’accès SQL type-safe en TypeScript. Pour les sauvegardes complètes incluant les fichiers applicatifs, Restic ou Borg en plus de Litestream offrent une couverture totale.

FAQ

Multi-writer ? Non. Single-writer. Pour multi-writer, Turso ou Postgres.

Latence sync ? 1 seconde par défaut, configurable.

S3 alternatives ? MinIO, B2, AWS, Wasabi tous compatibles.

RPO/RTO ? RPO 1s, RTO < 60s pour DB < 1 GB.

Conformité ARTCI/CDP ? B2 EU-Central, conforme.

Q : Litestream est-il production-ready ? R : Oui, utilisé par milliers d’apps incluant Fly.io qui sponsorisait le développement. Q : Latence d’écriture impactée ? R : Non, Litestream lit le WAL en background sans toucher au flux d’écriture applicatif. Q : Conflit avec backup pg_dump ? R : Non applicable, Litestream est SQLite-only. Q : Multi-writer supporté ? R : Non, SQLite reste single-writer même avec WAL. Pour multi-writer, passez à libSQL ou Postgres.

Lectures complémentaires

Hébergement recommandé pour les lecteurs

Si vous n’avez pas encore d’hébergeur, Hostinger est celui que nous utilisons et que nous recommandons après plusieurs années d’usage.

Profiter de l’offre →

Lien d affiliation. Si vous achetez via ce lien, le blog reçoit une petite commission sans surcoût pour vous.

Pourquoi Litestream pour repliquer SQLite

SQLite est embarque dans des dizaines de milliers d’applications self-hosted (Pocketbase, Plausible Lite, Umami sur certains setups, FreshRSS, Wallabag) mais sa reputation de « fichier unique fragile » decourage souvent les equipes prudentes. Litestream, ecrit par Ben Johnson (createur de BoltDB et co-auteur d’embedded databases chez Fly.io), resout ce probleme : il streame les pages WAL de SQLite en continu vers un stockage objet (S3, Backblaze B2, Scaleway Object Storage) et permet une restauration point-in-time avec une fenetre de perte de donnees de l’ordre de la seconde.

Sortie attendue de cette procedure : un binaire Litestream installe en sidecar de votre application SQLite, des sauvegardes incrementales chaque 1 a 10 secondes vers Scaleway Object Storage Paris (≈ 0,01 EUR/Go/mois soit 6,56 FCFA), et un script de restauration teste sur VPS de staging.

Etape 1 : Installation du binaire Litestream 0.5

Litestream est distribue en binaire statique (Go) sans dependance. Sur Ubuntu 24.04 :

wget https://github.com/benbjohnson/litestream/releases/download/v0.5.0/litestream-v0.5.0-linux-amd64.deb
sudo dpkg -i litestream-v0.5.0-linux-amd64.deb
litestream version

Vous devriez obtenir : v0.5.0. Si dpkg renvoie « dependency problems », lancez sudo apt-get install -f. Le paquet installe le binaire dans /usr/bin/litestream et le service systemd associe (desactive par defaut).

Etape 2 : Creer le bucket Scaleway et les cles API

Connectez-vous a la console Scaleway, allez dans Object Storage > Create Bucket, choisissez la region fr-par (Paris, ≈ 90 ms depuis Dakar via le cable ACE), nommez le bucket « litestream-prod-app1 » et laissez-le prive. Generez ensuite une paire d’API keys dans Identity > API Keys avec la permission « Object Storage Full Access » limitee a ce bucket.

Notez l’access key (debut SCW) et la secret key affichee une seule fois. Stockez-les dans un gestionnaire de secrets (Vaultwarden, Bitwarden) plutot qu’en clair sur le serveur.

Etape 3 : Configurer litestream.yml

Creez /etc/litestream.yml avec la configuration de replication :

dbs:
  - path: /var/lib/myapp/data.db
    replicas:
      - type: s3
        bucket: litestream-prod-app1
        path: data
        region: fr-par
        endpoint: https://s3.fr-par.scw.cloud
        access-key-id: SCW_VOTRE_ACCESS_KEY
        secret-access-key: VOTRE_SECRET_KEY
        retention: 72h
        snapshot-interval: 24h
        sync-interval: 1s

Le parametre sync-interval: 1s signifie que Litestream pousse les frames WAL toutes les secondes : RPO de 1 seconde maximum. retention: 72h conserve l’historique sur 3 jours, suffisant pour detecter et corriger une corruption applicative. Les snapshots quotidiens compactent les WAL pour eviter une croissance illimitee.

Etape 4 : Lancer Litestream comme service systemd

Le paquet Debian fournit deja l’unite. Activez-la :

sudo systemctl enable --now litestream
sudo systemctl status litestream

Résultat attendu : Active: active (running) et dans les logs journalctl -u litestream -f vous devez voir initialized db: /var/lib/myapp/data.db puis replica connected: s3. Si l’erreur est SignatureDoesNotMatch, votre secret key contient un caractere mal echappe ; regenerez-la sur Scaleway.

Etape 5 : Verifier la replication en cours

Inserez une ligne de test dans votre base SQLite et observez l’arrivee dans S3 :

sqlite3 /var/lib/myapp/data.db "INSERT INTO logs(message) VALUES('test litestream');"
litestream snapshots /var/lib/myapp/data.db

Résultat type : une liste de snapshots avec leurs index, generations et tailles. La premiere generation porte un identifiant aleatoire de 16 caracteres hex. Si la commande renvoie « no replicas configured », verifiez le chemin dans litestream.yml.

Etape 6 : Restauration sur un VPS de staging

La sauvegarde n’est valide que si vous l’avez restauree au moins une fois. Sur un VPS frais avec Litestream installe et le meme litestream.yml :

litestream restore -o /tmp/data-restored.db /var/lib/myapp/data.db
sqlite3 /tmp/data-restored.db "SELECT count(*) FROM logs;"

Le restore telecharge le snapshot le plus recent et rejoue les WAL frames jusqu’au point demande (par defaut, l’instant present). Résultat type : le nombre de lignes identique a la production. Documentez ce test dans votre runbook : date, duree (typiquement 30 secondes a 5 minutes selon la taille), nombre de lignes verifie.

Etape 7 : Restauration point-in-time

Cas reel : un dev a fait DELETE FROM users WHERE id > 100 a 14h32 au lieu de WHERE id < 100. Restaurez l'etat a 14h31 :

litestream restore -timestamp 2026-05-05T14:31:00Z -o /tmp/data-pit.db /var/lib/myapp/data.db

Résultat attendu : « restored to timestamp 2026-05-05T14:31:00Z ». Comparez les comptages avec la base actuelle, copiez la base restauree par-dessus la production apres avoir arrete le service applicatif, puis redemarrez Litestream. Cette operation prend typiquement 2 a 10 minutes.

Etape 8 : Surveillance et alertes

Litestream expose des metriques Prometheus sur le port 9090 si vous ajoutez addr: ":9090" dans la section metrics de litestream.yml. Surveillez litestream_replica_validation_total : si ce compteur n’augmente plus depuis 5 minutes, une alerte critique doit reveiller l’astreinte. Branchez-y Uptime Kuma (self-hosted, gratuit) ou Grafana Cloud free tier.

Au-delà des métriques Prometheus, configurez des alertes spécifiques. Alerte critique si litestream_replica_validation_count_total stagne plus de 5 minutes (réplication arrêtée). Alerte warning si litestream_disk_size grossit plus de 50 % en 24h (anomalie applicative). Routez via Alertmanager → Discord webhook ou WhatsApp Business pour notifier l’équipe d’astreinte. Cette discipline évite de découvrir la panne après une perte de données réelle.

Etape 9 : Couts et limites

Pour une base de 500 Mo avec 1 000 ecritures/jour, le volume mensuel transmis a S3 tourne autour de 5 a 10 Go (frames WAL compresses), soit 0,05 a 0,10 EUR/mois (33 a 66 FCFA) chez Scaleway Object Storage. Litestream ne replique qu’une seule base SQLite par instance ; pour plusieurs bases, declarez-les toutes dans le bloc dbs:. La limitation principale : Litestream ne fait pas de replication active-active, c’est un outil de sauvegarde continue, pas un cluster.

Pour approfondir : SQLite vs Postgres pour self-hosters et Turso libSQL self-hosted.

Etape 10 : Chiffrement cote client avec age

Scaleway chiffre par defaut les objets stockes (SSE-S3), mais si votre threat model inclut une compromission des cles Scaleway (insider, breach), ajoutez un chiffrement cote client avec age (binaire Go signe par Filippo Valsorda). Generez une paire de cles avec age-keygen -o /etc/litestream/age.key, puis enveloppez les snapshots Litestream via un script wrapper qui appelle age -r AGE_RECIPIENT avant l’upload. Stockez la cle privee dans un coffre-fort hors ligne (papier dans un coffre bancaire, YubiKey).

Ce que vous devez voir apres restauration : age -d -i /etc/litestream/age.key snapshot.age > snapshot.db puis sqlite3 doit ouvrir le fichier sans erreur « file is not a database ».

Etape 11 : Multi-region pour disaster recovery

Pour une tolerance a la panne d’une region complete (incident OVH Strasbourg 2021), declarez plusieurs replicas dans litestream.yml : un sur Scaleway fr-par et un sur Backblaze B2 us-west. Litestream pousse en parallele, le cout double mais la resilience aussi. Lors d’une restauration, choisissez la replique la plus recente avec litestream snapshots --replica=b2 ....

Etape 12 : Latence d’ecriture et impact applicatif

Litestream lit le WAL en arriere-plan, il n’ajoute pas de latence aux ecritures SQLite (mode WAL toujours utilise par l’application). Mesure typique sur un VPS Scaleway DEV1-S a Paris : 0,3 ms par ecriture en mode WAL avec ou sans Litestream actif. La replication consomme environ 2 a 5 pour cent de CPU et 50 Mo de RAM, negligeable sur un VPS 2 Go.

Etape 13 : Cas d’usage adapte et inadapte

Litestream brille pour des bases en lecture intensive et ecriture moderee (jusqu’a quelques centaines d’ecritures/seconde) : blogs, dashboards internes, CRM TPE, applications PocketBase. Il devient inadapte au-dela de 1 000 ecritures/seconde soutenues (le WAL grandit plus vite que l’upload) ou si vous avez besoin de replication synchrone avec failover automatique : dans ce cas, migrez vers PostgreSQL avec un primary/standby ou rkSQLite/dqlite.

Etape 14 : Integration avec Pocketbase et Plausible

Pocketbase utilise SQLite avec WAL active par defaut depuis la version 0.22, parfaitement compatible avec Litestream. Pointez simplement path: /pb_data/data.db dans litestream.yml. Idem pour Plausible Analytics Lite ou pour FreshRSS si vous avez choisi le backend SQLite. Verifiez que l’application n’effectue pas de VACUUM brutal (qui reecrit toute la base) en plein milieu de la journee : programmez VACUUM hebdomadairement la nuit pour eviter un pic d’upload S3.

Résultat type apres VACUUM : un snapshot complet est genere par Litestream a la prochaine fenetre snapshot-interval, puis les uploads incrementaux reprennent leur rythme normal.

Etape 15 : Procedure de bascule en cas de perte du VPS

Si le VPS principal devient injoignable (panne hardware, suspension fournisseur), provisionnez un nouveau VPS, installez l’application + Litestream avec le meme litestream.yml, executez litestream restore /var/lib/myapp/data.db, puis demarrez l’application. RTO typique : 15 a 30 minutes pour une base de 1 Go, dont 80 pour cent en provisioning DNS et certificats. Conservez le runbook de bascule dans votre wiki BookStack ou un README versionne dans Gitea, accessible meme quand le service principal est down.

Etape 16 : Migration depuis cron + sqlite3 .backup

Si vous utilisez aujourd’hui un cron qui fait sqlite3 data.db .backup /tmp/backup.db tous les soirs, vous avez un RPO de 24 heures et zero point-in-time. La migration vers Litestream se fait sans downtime : installez le binaire, configurez litestream.yml, lancez le service, conservez l’ancien cron une semaine en parallele pour comparer les restaurations, puis desactivez-le. Aucune modification applicative n’est necessaire.

Etape 17 : Cout total mensuel pour une stack typique

Recapitulatif pour une PME ouest-africaine qui heberge Pocketbase + Litestream sur un VPS Hetzner CX22 a Helsinki avec replication vers Scaleway fr-par : 4,50 EUR/mois VPS (2 952 FCFA), 0,10 EUR/mois Scaleway Object Storage avec 10 Go (66 FCFA), 0,01 EUR/mois bande passante sortante (negligeable). Total environ 4,61 EUR/mois soit 3 020 FCFA, pour un setup avec RPO 1 seconde, retention 72 heures et restauration point-in-time validee.

Compare a une instance RDS PostgreSQL chez AWS (db.t4g.micro multi-AZ, environ 30 EUR/mois soit 19 678 FCFA), l’economie est d’un facteur 6 a 7 pour des charges modestes. Le compromis : pas de replication active-active ni de read replicas, vous restez sur un nœud unique. C’est le bon trade-off pour 90 pour cent des projets self-hosted ouest-africains qui demarrent.

Etape 18 : Erreurs frequentes et leur diagnostic

Erreur 1 : database is locked apparait au demarrage de Litestream. Cause : un autre processus tient un verrou exclusif sur la base (sqlite3 CLI ouvert en mode interactif, par exemple). Solution : fermez le shell sqlite3 ou desactivez les processus concurrents. Litestream lui-meme ne pose pas de verrou bloquant grace au mode WAL.

Erreur 2 : cannot connect to replica: 403 Forbidden. Cause : la cle API Scaleway n’a pas la permission ObjectStorageFullAccess sur le bucket cible. Solution : recreez la cle dans Scaleway Identity en attachant explicitement le bucket dans la policy.

Erreur 3 : WAL file is too large (plus de 1 Go). Cause : un long checkpoint manque, souvent parce que l’application tient une transaction longue. Solution : forcez un checkpoint avec sqlite3 data.db "PRAGMA wal_checkpoint(TRUNCATE);" et investiguez le code applicatif.

مشاركة