
Portabase est un outil open source (licence Apache 2.0) qui sauvegarde et restaure vos bases de données depuis un dashboard web que vous hébergez vous-même. Au lieu d'écrire un script cron par serveur et par moteur, vous pilotez PostgreSQL, MySQL, MongoDB, Redis ou des volumes Docker depuis une seule interface, avec un historique des sauvegardes et une restauration en quelques clics.
Ce guide déploie Portabase avec Docker Compose, connecte un agent, déclare une base PostgreSQL et une base MySQL, puis prouve le cycle complet : sauvegarde, incident simulé, restauration. Tout a été validé en lab sur la version 1.26.0, y compris le piège réseau qui bloque la plupart des premières installations.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »À la fin de ce guide, vous aurez une instance Portabase fonctionnelle et vous saurez sauvegarder puis restaurer une base en toute confiance :
- L'architecture de Portabase : un dashboard central et des agents au plus près des bases
- Déployer le dashboard avec Docker Compose et éviter le piège de la variable
PROJECT_URL - Créer le compte administrateur et parcourir l'assistant d'installation
- Connecter un agent au dashboard grâce à son Edge Key
- Déclarer une base PostgreSQL et une base MySQL à sauvegarder
- Lancer une sauvegarde, simuler un incident, puis restaurer et vérifier les données
Dans quel contexte ?
Section intitulée « Dans quel contexte ? »La sauvegarde d'une base isolée est un problème résolu : pg_dump pour PostgreSQL, mysqldump pour MySQL, un cron et un stockage. Ces méthodes natives restent la référence et sont détaillées dans les guides Sauvegarder PostgreSQL et Sauvegarder MySQL.
Le problème change d'échelle dès que vous gérez plusieurs bases, sur plusieurs serveurs, avec plusieurs moteurs. Chaque script vit dans son coin, personne ne sait quelle sauvegarde a réussi hier soir, et la première vraie restauration se fait sous stress. Portabase répond à ce besoin d'orchestration : il ne réécrit pas pg_dump, il l'appelle pour vous, centralise l'historique, la planification et la restauration, et vous donne une vue unique sur l'état de toutes vos sauvegardes.
L'architecture : un dashboard et des agents
Section intitulée « L'architecture : un dashboard et des agents »Portabase sépare deux rôles, et comprendre cette séparation évite la moitié des erreurs de configuration :
- Le dashboard est le cerveau. C'est l'interface web, la base de métadonnées (qui sauvegarde quoi, quand, avec quel résultat) et le point de pilotage. Il ne touche jamais directement vos bases de production.
- L'agent est le bras. Vous l'installez au plus près des bases à protéger. C'est lui qui se connecte à PostgreSQL ou MySQL, lance le dump, l'envoie vers le stockage et exécute les restaurations. Il ne fait rien tant que le dashboard ne lui a pas donné d'ordre.
Entre les deux, un jeton d'enregistrement appelé Edge Key authentifie l'agent auprès du dashboard. Cette architecture permet de sauvegarder des bases réparties sur plusieurs machines ou plusieurs réseaux : un seul dashboard, autant d'agents que nécessaire.
Prérequis
Section intitulée « Prérequis »Pour reproduire ce lab, il vous faut :
- Docker et le plugin Docker Compose (v2) installés
- Environ 1 Go de RAM libre pour le dashboard et sa base de métadonnées
- Deux bases à sauvegarder. Le lab en fournit deux jetables, une PostgreSQL et une MySQL, avec un jeu de données minimal
Le lab reste entièrement local. Aucune donnée ne sort de votre poste.
Déployer le dashboard
Section intitulée « Déployer le dashboard »Le dashboard a besoin de sa propre base PostgreSQL pour stocker ses métadonnées. On décrit les deux services dans un compose.yml.
# compose.yml : le dashboard Portabase et sa base de metadonneesname: portabase-dashboard
services: portabase: container_name: portabase-app image: portabase/portabase:1.26.0@sha256:69e97155330991d8c28cb12ea2967d87a202cf838cb77605b33eaea16a61d9ab restart: always env_file: .env ports: - "8887:80" # Point cle du reseau : voir la section suivante extra_hosts: - "portabase.lab:host-gateway" volumes: - portabase-data:/data networks: - portabase depends_on: db: condition: service_healthy
db: container_name: portabase-pg image: postgres:17-alpine@sha256:742f40ea20b9ff2ff31db5458d127452988a2164df9e17441e191f3b72252193 restart: always volumes: - postgres-data:/var/lib/postgresql/data environment: POSTGRES_DB: ${POSTGRES_DB} POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} networks: - portabase healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"] interval: 10s timeout: 5s retries: 5
networks: portabase: name: portabase_network
volumes: postgres-data: portabase-data:La configuration sensible vit dans un fichier .env à côté du compose.yml. Générez les secrets, ne les recopiez pas :
# secrets a generer une seule foisopenssl rand -hex 32 # -> PROJECT_SECRETopenssl rand -hex 12 # -> POSTGRES_PASSWORD (a reporter dans DATABASE_URL)# .env : configuration du dashboardPROJECT_URL=http://portabase.lab:8887PROJECT_SECRET=REMPLACER_PAR_LE_HEX_32POSTGRES_USER=portabasePOSTGRES_PASSWORD=REMPLACER_PAR_LE_HEX_12POSTGRES_HOST=dbPOSTGRES_PORT=5432POSTGRES_DB=portabaseDATABASE_URL=postgresql://portabase:REMPLACER_PAR_LE_HEX_12@db:5432/portabaseLe piège PROJECT_URL, la source de « Failed to fetch »
Section intitulée « Le piège PROJECT_URL, la source de « Failed to fetch » »C'est le point qui bloque la première installation, et il mérite qu'on s'y arrête. La variable PROJECT_URL doit être joignable à l'identique depuis deux endroits différents :
- Le conteneur du dashboard s'appelle lui-même en rendu côté serveur (SSR). Pour lui,
PROJECT_URLdoit pointer vers une adresse qu'il peut atteindre de l'intérieur. - Le navigateur appelle la même URL en JavaScript. Or le dashboard applique une politique de sécurité CSP
connect-src 'self': le navigateur n'autorise les appels que vers exactement l'origine dePROJECT_URL.
Si vous mettez http://localhost:8887, le navigateur est content mais le conteneur ne s'atteint pas lui-même sur le port 8887 (son application écoute sur le port 80 en interne). Si vous mettez une autre adresse, c'est le navigateur qui refuse l'appel avec un laconique « Failed to fetch » au moment de créer le compte.
La solution est un nom d'hôte unique, résolu de la même façon des deux côtés, sur le port publié :
-
Côté navigateur, faites pointer ce nom vers votre machine dans
/etc/hosts:Fenêtre de terminal echo "127.0.0.1 portabase.lab" | sudo tee -a /etc/hosts -
Côté conteneur, la ligne
extra_hosts: ["portabase.lab:host-gateway"]ducompose.ymlrésout ce même nom vers l'hôte Docker. Le conteneur atteint donchttp://portabase.lab:8887exactement comme le navigateur. -
PROJECT_URL=http://portabase.lab:8887est alors valide des deux côtés, et la CSP est satisfaite.
Lancez le dashboard, puis vérifiez qu'il répond :
docker compose up -dcurl -s -o /dev/null -w "%{http_code}\n" http://portabase.lab:8887/api/health# -> 200Créer le compte administrateur
Section intitulée « Créer le compte administrateur »Ouvrez http://portabase.lab:8887 dans votre navigateur. Au premier lancement, Portabase propose de créer le compte administrateur. Renseignez un nom, une adresse et un mot de passe robuste : ce compte est superadmin, il pilote toute l'instance.

L'assistant enchaîne ensuite une série d'étapes rapides : sécurité du compte, préférences, création de l'organisation, notifications et stockage. Vous pouvez passer les étapes optionnelles (notifications, stockage externe) : un stockage local est configuré par défaut, suffisant pour ce lab. Poursuivez jusqu'à l'étape Create an agent.
Connecter un agent
Section intitulée « Connecter un agent »L'assistant propose de créer un agent. Donnez-lui un nom (ici agent-lab) et validez. Portabase affiche alors l'écran Connect your agent avec la commande à exécuter et, surtout, l'Edge Key : le jeton qui autorise l'agent à rejoindre le dashboard.

L'Edge Key est un jeton signé qui encode notamment l'URL du dashboard. Copiez-le : il alimente la variable EDGE_KEY de l'agent. Créez un dossier agent/ avec son propre compose.yml.
# agent/compose.yml : l'agent Portabasename: portabase-agent
services: app: container_name: portabase-agent image: portabase/agent:latest@sha256:9a57cb6470bcf4e7583953d6ab576ab4ba414e57498d38e03c6805e926cc3ab0 restart: always volumes: - ./databases.json:/config/config.json extra_hosts: # l'Edge Key pointe le dashboard sur portabase.lab:8887 ; # l'agent doit resoudre ce nom vers l'hote, comme le navigateur - "localhost:host-gateway" - "portabase.lab:host-gateway" environment: EDGE_KEY: "${EDGE_KEY}" TZ: "Europe/Paris" POLLING: 5 APP_ENV: production LOG: info networks: - portabase
networks: portabase: name: portabase_network external: trueL'agent lit la liste des bases dans un fichier config.json, monté ici depuis databases.json. Créez-le vide au premier démarrage, il sera complété à l'étape suivante :
echo '{"databases": []}' > agent/databases.jsonPlacez l'Edge Key dans agent/.env, puis démarrez l'agent :
cd agentecho "EDGE_KEY=collez_ici_votre_edge_key" > .envdocker compose up -ddocker logs portabase-agentLes journaux confirment la connexion :
INFO EDGE_KEY server_url: http://portabase.lab:8887INFO EDGE_KEY agent_id: 7141e5e0-3e3a-4427-a915-0bf56f55b94eINFO Ping server task startedINFO Databases: 0 instances loadedDéclarer les bases à sauvegarder
Section intitulée « Déclarer les bases à sauvegarder »Dans l'édition Community, les bases se déclarent dans le fichier de configuration de l'agent. Chaque entrée décrit une base : son moteur (type), son hôte, son port et ses identifiants. L'agent lit ce fichier et signale les bases au dashboard.
Voici le databases.json du lab, avec une base PostgreSQL et une base MySQL :
{ "databases": [ { "name": "Boutique PostgreSQL", "database": "boutique", "type": "postgresql", "username": "app", "password": "app-mdp-demo", "port": 5432, "host": "source-postgres", "generated_id": "b8965c07-7e40-49b4-abad-9dad8b90b3da" }, { "name": "Catalogue MySQL", "database": "catalogue", "type": "mysql", "username": "app", "password": "app-mdp-demo", "port": 3306, "host": "source-mysql", "generated_id": "b85ca400-9764-4d05-b608-fd3be14fb92d" } ]}Quelques champs méritent une explication :
typesélectionne le moteur :postgresql,mysql,mariadb,mongodb,redis,sqlite,valkey,mssql,firebirdoudocker-volume.hostest le nom joignable depuis l'agent. Comme l'agent partage le réseauportabase_network, il atteint les bases par leur nom de conteneur.generated_idest un identifiant stable (un UUID) : il relie la configuration à l'historique côté dashboard. Ne le réutilisez pas d'une base à l'autre.
Rechargez l'agent pour qu'il prenne le fichier en compte :
docker compose restartdocker logs portabase-agent | grep "instances loaded"# INFO Databases: 2 instances loadedLes deux bases apparaissent alors dans le dashboard, rattachées à votre projet.
Lancer une sauvegarde
Section intitulée « Lancer une sauvegarde »Ouvrez une base depuis le projet, par exemple Boutique PostgreSQL. La fiche affiche les compteurs (sauvegardes disponibles, taux de réussite) et deux onglets, Backup et Restoration. Cliquez sur le bouton Backup en haut à droite, puis confirmez.

L'agent exécute le dump et l'envoie vers le stockage. Ses journaux tracent chaque étape :
INFO Starting backup for database Boutique PostgreSQLINFO Running FC backup for Boutique PostgreSQLINFO Upload completed successfully. Final size: 1099INFO Database backup job finishedLa sauvegarde apparaît dans l'onglet Backup avec son statut success, sa taille et sa durée. C'est le moment de vérifier ce qu'une sauvegarde ne prouve pas : qu'on sait la restaurer.
Restaurer et vérifier
Section intitulée « Restaurer et vérifier »Une sauvegarde n'a de valeur que si la restauration fonctionne. On le prouve en simulant un incident : on vide la table, on restaure, on vérifie que les données reviennent.
-
État de départ. La base
boutiquecontient trois clients :Fenêtre de terminal docker exec source-postgres psql -U app -d boutique -c "SELECT * FROM clients ORDER BY id;"# id | nom | ville# ----+---------+--------# 1 | Dupont | Lyon# 2 | Martin | Nantes# 3 | Bernard | Lille -
Incident simulé. On vide la table, comme le ferait une fausse manipulation :
Fenêtre de terminal docker exec source-postgres psql -U app -d boutique -c "TRUNCATE clients;"docker exec source-postgres psql -U app -d boutique -c "SELECT count(*) FROM clients;"# 0 -
Restauration. Dans l'onglet Backup de la base, ouvrez le menu de la sauvegarde (les trois points) et choisissez Restore. Portabase demande le stockage d'où lire la sauvegarde : sélectionnez System (le stockage local), puis Confirm.

-
Vérification. Les trois clients sont de retour :
Fenêtre de terminal docker exec source-postgres psql -U app -d boutique -c "SELECT count(*) FROM clients;"# 3
Côté agent, la restauration est tracée et rapide :
INFO Starting restore for database Boutique PostgreSQLINFO Restore completed successfully for database Boutique PostgreSQLINFO [RestoreService] Status: success | Duration: 77ms
Le cycle est bouclé : la donnée perdue est revenue depuis une sauvegarde pilotée par le dashboard. C'est cette boucle, testée à froid, qui distingue une vraie stratégie de sauvegarde d'un simple dump qu'on espère valide.
Aller vers la production
Section intitulée « Aller vers la production »Le lab tourne en local avec des raccourcis à corriger avant tout usage réel :
- Stockage distant obligatoire. Le stockage local vit sur la même machine que l'agent. Une panne disque emporte les bases et leurs sauvegardes. Configurez un canal S3 ou équivalent pour respecter la règle 3-2-1 (au moins une copie hors site).
- Comptes de sauvegarde dédiés. Donnez à l'agent un utilisateur en lecture seule par base, jamais le compte
rootoupostgres. - Planification et rétention. Ce guide déclenche les sauvegardes à la main pour la démonstration. En production, définissez une planification et une politique de rétention par base.
- HTTPS. Exposez le dashboard derrière un reverse proxy avec un certificat, ce qui règle au passage le piège
PROJECT_URL.
À retenir
Section intitulée « À retenir »- Portabase orchestre, il ne remplace pas
pg_dumpnimysqldump: il les appelle et centralise l'historique. - L'architecture sépare le dashboard (cerveau, interface) de l'agent (bras, au plus près des bases).
- Le piège numéro un est
PROJECT_URL: elle doit être joignable à l'identique depuis le navigateur et le conteneur, sinon « Failed to fetch ». - Les bases se déclarent dans le fichier de configuration de l'agent (
type,host,port, identifiants), qui contient des secrets à protéger. - Une sauvegarde ne vaut que si la restauration est testée : rejouez la boucle complète régulièrement.
- En production, stockage distant obligatoire (règle 3-2-1), comptes de sauvegarde dédiés et HTTPS derrière un reverse proxy.
Ces questions condensent les décisions à prendre au démarrage : le positionnement face aux outils natifs, les moteurs pris en charge, le stockage des sauvegardes et le piège réseau de la première installation.
pg_dump ou mysqldump, puis gère la planification, l'envoi vers le stockage, la rétention et la restauration. Portabase ajoute la couche d'orchestration multi-bases et l'interface ; les outils natifs restent le moteur du dump.PROJECT_URL n'est pas joignable à l'identique depuis le navigateur et depuis le conteneur. Le dashboard s'appelle lui-même en SSR et le navigateur applique une politique CSP connect-src 'self' : l'origine du navigateur doit correspondre exactement à PROJECT_URL. La solution est un nom d'hôte résolu de la même façon des deux côtés, sur le port publié.