TuBrief
구독 채널
비디오
커뮤니티

Étapes techniques pour quitter Firebase et passer à un hébergement autonome à 5 $ par mois

TuBrief 편집팀
2026년 7월 14일
0
Computing/Software

원본 영상을 바탕으로 AI의 도움을 받아 작성했습니다. 원본 영상이 기준입니다.

Français한국어EnglishEspañol中文العربيةहिन्दीDeutschPortuguêsРусскийBahasa Indonesia日本語

관련 영상

Cette alternative gratuite à Firebase tient en un seul fichier7:49

Cette alternative gratuite à Firebase tient en un seul fichier

Better Stack

커뮤니티의 다른 글

사내 시스템에 llm api 붙일 때 마주하는 현실적인 한계와 대응법

2026년 9월 13일

레거시 백엔드에 GPT-6 Astra 붙일 때 예산 승인과 보안 통과를 먼저 끝내는 법이 있습니다

2026년 9월 13일

에이전트끼리 대화하다 6천만 원 청구서가 나오는 이유

2026년 9월 13일

사내 RAG 벡터 검색에 Okta 권한 필터를 직접 거는 방법

2026년 9월 13일

브라우저 에이전트에게 내 구글 계정을 통째로 넘기면 안 되는 이유

2026년 9월 12일

Apple Won the AI Race

2026년 9월 12일

댓글 (0)

Log in to leave a comment

아직 작성된 글이 없습니다

© 2026 . All rights reserved.

TuBrief
구독 채널
비디오
커뮤니티
로그인

Étapes techniques pour quitter Firebase et passer à un hébergement autonome à 5 $ par mois

Firebase est séduisant au début. On peut se concentrer uniquement sur les fonctionnalités sans se soucier de l'infrastructure. Cependant, dès que le service connaît une petite croissance, les chiffres sur la facture commencent à grimper. Pourtant, l'idée de passer à un hébergement autonome fait peur. Que faire si les données sont perdues ? Que faire si le service s'interrompt à chaque déploiement ?

C'est une inquiétude tout à fait légitime. Mais il existe une solution. J'ai résumé ici les étapes concrètes pour migrer vos données Firestore vers PocketBase, un backend tout-en-un basé sur SQLite, et créer un environnement de déploiement sans interruption (zéro downtime) en utilisant GitHub Actions et Nginx.


Pipeline de migration des données Firestore vers PocketBase

Le premier obstacle lors du transfert de données non structurées de Firestore vers le schéma relationnel de PocketBase est la longueur des identifiants. Firestore utilise des ID de document de 20 caractères, tandis que PocketBase impose par défaut une limite de 15 caractères alphanumériques. Si vous forcez l'insertion sans tenir compte de cette longueur, vous rencontrerez l'erreur validation_length_invalid.

Pour éviter ce problème, il faut réduire la longueur tout en préservant l'unicité. La méthode la plus fiable consiste à hacher l'ID Firestore avec SHA256, puis à ne conserver que les 15 premiers caractères. Vous n'avez pas à vous soucier des collisions. Même sur de grands ensembles de données, la probabilité que des hashs de 15 caractères se chevauchent est négligeable.

Voici la structure du script de migration Node.js pour gérer cela. Il utilise les paquets firebase-admin et axios pour récupérer les données par lots de 100.

`javascript
// migration.js
const admin = require('firebase-admin');
const axios = require('axios');
const crypto = require('crypto');

admin.initializeApp({
credential: admin.credential.applicationDefault()
});

const db = admin.firestore();
const PB_URL = 'http://127.0.0.1:8090/api/collections/posts/records';

async function migrate() {
let lastDoc = null;
let hasMore = true;

while (hasMore) {
let query = db.collection('posts').orderBy('name').limit(100);
if (lastDoc) {
query = query.startAfter(lastDoc);
}

const snapshot = await query.get();
if (snapshot.empty) {
  hasMore = false;
  break;
}

for (const doc of snapshot.docs) {
  const data = doc.data();
  // Conversion de l'ID Firestore de 20 caractères en 15 caractères alphanumériques
  const newId = crypto.createHash('sha256').update(doc.id).digest('hex').substring(0, 15);
  
  try {
    await axios.post(PB_URL, {
      id: newId,
      firestore_id: doc.id, // Enregistrement de l'ID d'origine pour vérification éventuelle
      title: data.title,
      content: data.content
    });
  } catch (err) {
    console.error(`Échec de transfert : ${doc.id}`, err.response?.data);
  }
}
lastDoc = snapshot.docs[snapshot.docs.length - 1];

}
}

migrate();
`

Pour effectuer cette opération sans interruption, il faut prévoir une période de transition. Commencez par migrer plus de 90 % des données existantes en arrière-plan avec ce script. Ensuite, déployez un code de « double écriture » (Dual-Write) qui enregistre les données simultanément sur Firebase et PocketBase lors des opérations d'écriture dans votre application cliente. Après avoir vérifié que les données correspondent des deux côtés, passez les endpoints de lecture sur PocketBase et supprimez le code lié à Firebase. Pour l'utilisateur, le serveur ne sera jamais indisponible, pas même une seconde.


Configuration d'un serveur PocketBase disponible 24h/24

PocketBase est un backend léger qui s'exécute sous forme d'un binaire unique. Cependant, si vous vous contentez de le lancer sur un serveur Linux, vous n'aurez aucun moyen de récupérer le service s'il s'arrête à cause d'une erreur de mémoire insuffisante (OOM) imprévue.

Vous devez configurer systemd pour que le processus redémarre automatiquement s'il tombe. Créez un fichier /etc/systemd/system/pocketbase.service et enregistrez le contenu suivant :

`ini
[Unit]
Description=PocketBase Service
After=network.target

[Service]
Type=simple
User=pocketbase
Group=pocketbase
LimitNOFILE=65535
ExecStart=/opt/pocketbase/pocketbase serve --http="127.0.0.1:8090"
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target
`

Ici, le réglage LimitNOFILE=65535 est crucial. Lors de l'utilisation de la fonctionnalité d'abonnement en temps réel (WebSockets) qui fait la force de PocketBase, cela empêche les déconnexions dues à la limite de descripteurs de fichiers par défaut de Linux lorsque de nombreux utilisateurs se connectent simultanément.

En amont, placez Nginx pour gérer les certificats SSL et le proxy. Vous devez ajouter des options dans la configuration /etc/nginx/sites-available/pocketbase pour éviter que les connexions de streaming en temps réel ne soient retardées.

`nginx
upstream pocketbase {
server 127.0.0.1:8090;
}

server {
server_name api.yourdomain.com;

location / {
    proxy_pass http://pocketbase;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;

    # Support du streaming en temps réel via WebSockets et SSE
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_buffering off;
}

}
`

Il ne reste plus qu'à appliquer le certificat HTTPS avec la commande certbot --nginx, et l'infrastructure de base est prête.

Selon mon expérience, même sur les VPS les plus économiques avec 512 Mo de RAM, en ajustant légèrement les réglages SQLite, vous pouvez facilement gérer plus de 1 000 requêtes légères par seconde. Pour maximiser les performances de SQLite lors de l'exécution de PocketBase, vous devez activer le mode WAL (Write-Ahead Log). PocketBase active le mode WAL par défaut, mais si vous devez manipuler SQLite directement, vérifiez les paramètres PRAGMA journal_mode=WAL; et PRAGMA synchronous=NORMAL;. Le goulot d'étranglement dû à l'attente d'écriture sur le disque disparaît presque totalement.


Sauvegarde en temps réel avec Cloudflare R2 et Litestream

L'erreur la plus fréquente des développeurs indépendants est de copier directement le fichier de base de données SQLite (data.db) pendant que le serveur est actif. Cette méthode présente un risque élevé de corruption des données pendant la sauvegarde.

Nous utilisons Litestream. C'est un outil qui intercepte les frames WAL de SQLite en temps réel et envoie uniquement les parties modifiées vers un stockage cloud. Je recommande Cloudflare R2 comme dépôt de sauvegarde. Comme les frais de transfert sortant sont gratuits, cela ne coûte pratiquement rien, quelle que soit la quantité de sauvegardes effectuées.

Créez le fichier de configuration /etc/litestream.yml comme suit :

`yaml
dbs:

  • path: /opt/pocketbase/pb_data/data.db
    replicas:
    • type: s3
      bucket: your-r2-bucket-name
      endpoint: https://.r2.cloudflarestorage.com
      access-key-id:
      secret-access-key:

`

Avec cette configuration, même si le fichier db original est perdu, vous pouvez le restaurer jusqu'à l'état de la dernière seconde avec une seule commande :

bash litestream restore -if-replica-exists /opt/pocketbase/pb_data/data.db

Si vous avez accidentellement supprimé des données pendant le développement et que vous souhaitez restaurer à un moment précis, il est également possible de spécifier une valeur temporelle.

`bash

1. Arrêt temporaire de PocketBase

sudo systemctl stop pocketbase.service

2. Création d'un fichier de restauration à un moment donné

litestream restore -timestamp "2026-07-14T15:00:00Z" -o /tmp/recovered.db /opt/pocketbase/pb_data/data.db

3. Vérification de l'intégrité des données puis remplacement du fichier

sqlite3 /tmp/recovered.db "PRAGMA integrity_check;"
mv /tmp/recovered.db /opt/pocketbase/pb_data/data.db
chown -R pocketbase:pocketbase /opt/pocketbase/pb_data/

4. Reprise du service

sudo systemctl start pocketbase.service
`

Cloudflare R2 offre 10 Go de stockage gratuit par mois. Comme ils offrent également 1 million de requêtes d'écriture et 10 millions de requêtes de lecture gratuitement, les coûts de sauvegarde pour un service individuel tendent vers zéro.


Déploiement sans interruption avec GitHub Actions et Nginx

Déployer avec Docker est pratique, mais sur un petit VPS avec 512 Mo ou 1 Go de RAM, la mémoire consommée par le démon Docker lui-même est précieuse. Implémentons un déploiement sans interruption (blue-green) en alternant les ports via systemd Linux, sans utiliser Docker.

Nous profitons de la caractéristique de SQLite qui permet à plusieurs processus de lire et d'écrire dans un même fichier. Il suffit d'enregistrer des modèles de service systemd pour pouvoir lancer le binaire PocketBase sur les ports 9011 (bleu) et 9012 (vert) respectivement.

Voici d'abord un exemple de workflow GitHub Actions pour transférer le binaire léger construit vers le serveur.

`yaml

.github/workflows/deploy.yml

name: Deploy
on:
push:
branches: [ main ]

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.22'
- name: Build
run: |
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o pocketbase main.go
- name: Transfer Binary to VPS
uses: appleboy/scp-action@master
with:
host: ${{ secrets.VPS_HOST }}
username: ${{ secrets.VPS_USER }}
key: ${{ secrets.VPS_KEY }}
source: "pocketbase"
target: "/srv/pocketbase/next_release"
`

Une fois que le binaire arrive sur le serveur, le script de déploiement s'exécute. Il vérifie quel port est actuellement actif (9011 ou 9012) et lance la nouvelle version du binaire sur le port inutilisé.

`bash
#!/bin/bash

deploy_swap.sh

CURRENT_PORT=$(curl -s http://127.0.0.1:8090/api/health | jq -r '.port' 2>/dev/null || echo "9011")

if [ "$CURRENT_PORT" = "9011" ]; then
TARGET_PORT="9012"
else
TARGET_PORT="9011"
fi

Lancement du binaire de la nouvelle version en arrière-plan sur le port cible

sudo systemctl start pocketbase@$TARGET_PORT.service

Attente de 3 secondes pour la vérification de santé (health check)

sleep 3
HEALTH_CHECK=(curl−shttp://127.0.0.1:(curl -s http://127.0.0.1:(curl−shttp://127.0.0.1:TARGET_PORT/api/health | jq -r '.status')

if [ "HEALTH_CHECK" = "OK" ]; then # Modification de la configuration upstream Nginx vers le nouveau port puis rechargement echo "upstream pocketbase { server 127.0.0.1:TARGET_PORT; }" | sudo tee /etc/nginx/conf.d/upstream.conf
sudo systemctl reload nginx

# Arrêt du processus de l'ancienne version

sudo systemctl stop pocketbase@$CURRENT_PORT.service
echo "Déploiement terminé. Basculement vers le port TARGETPORTreˊussi."elseecho"Eˊchecdudeˊploiement.Lehealthcheckdelanouvelleversionaeˊchoueˊ."sudosystemctlstoppocketbase@TARGET_PORT réussi." else echo "Échec du déploiement. Le health check de la nouvelle version a échoué." sudo systemctl stop pocketbase@TARGETP​ORTreˊussi."elseecho"Eˊchecdudeˊploiement.Lehealthcheckdelanouvelleversionaeˊchoueˊ."sudosystemctlstoppocketbase@TARGET_PORT.service
exit 1
fi
`

Grâce à cette méthode, un déploiement sans interruption fonctionne parfaitement sans outils d'orchestration de conteneurs coûteux. Même si un utilisateur envoie une requête pendant le déploiement, Nginx met en attente les requêtes durant l'instant du rechargement (en millisecondes) et les redirige ensuite en toute sécurité vers le nouveau port.

L'hébergement autonome demande un peu d'efforts lors de la première configuration, mais une fois en place, il devient une excellente base pour se concentrer entièrement sur le produit, sans se soucier des frais d'infrastructure facturés chaque mois.