Guide de déploiement

PostgreSQL sur VPS : base fiable et contrôlée

Déployer sur un VPS Cloud →

Tutoriel

Bases de données

PostgreSQL sur VPS : base fiable et contrôlée

PostgreSQL est souvent la base de données de confiance des applications métiers, des APIs et des outils d'analyse. Sur un VPS ServOrbit, vous contrôlez la version, le stockage, les sauvegardes et les accès au lieu de payer une base managée au Go. Ce guide couvre les décisions qui comptent — persistance, utilisateurs, réseau, restauration — ainsi que la configuration fine de `postgresql.conf`, les sauvegardes automatisées avec test de restauration, la haute disponibilité en streaming sur deux VPS, et le dépannage des pannes les plus fréquentes en production.

9 min de lecture11 étapes
Sommaire· Pourquoi auto-héberger PostgreSQL sur un VPS1/10
  1. 01Pourquoi auto-héberger PostgreSQL sur un VPS
  2. 02Les bénéfices concrets d'un PostgreSQL auto-hébergé
  3. 03Prérequis matériels et logiciels
  4. 04Déployer PostgreSQL avec Docker en production
  5. 05Configurer postgresql.conf pour la production
  6. 06Sauvegardes automatiques et stratégie de recovery
  7. 07Haute disponibilité légère sans Kubernetes
  8. 08PostgreSQL self-hosted vs RDS vs Supabase vs Neon
  9. 09Dépannage des problèmes courants en production
  10. 10La documentation officielle

Pourquoi auto-héberger PostgreSQL sur un VPS

Les bases managées (RDS, Cloud SQL) facturent au Go stocké, aux IOPS et aux connexions, et limitent souvent les extensions disponibles. En déployant PostgreSQL sur votre propre VPS, vous activez pg_stat_statements, PostGIS, pgvector ou TimescaleDB sans restriction, vous choisissez votre version exacte (15, 16, 17) et vous gardez vos données dans une juridiction que vous maîtrisez. Un VPS avec disque SSD offre des latences I/O très basses, idéales pour les workloads transactionnels d'une application en production. Vous payez un forfait fixe et prévisible, et vous décidez seul de votre stratégie de réplication, de chiffrement et de rétention des backups.

Les bénéfices concrets d'un PostgreSQL auto-hébergé

  • Coût fixe et prévisible : pas de facturation au Go, aux IOPS ni au nombre de connexions actives.
  • Extensions libres : pgvector pour l'IA, PostGIS pour le géospatial, TimescaleDB pour les séries temporelles.
  • Contrôle total des sauvegardes : pg_dump planifié, pg_basebackup ou réplication physique vers un second VPS.
  • Tuning fin de postgresql.conf (shared_buffers, work_mem, WAL) impossible chez la plupart des offres managées.
  • Souveraineté des données : vos données restent sur une infrastructure que vous choisissez.
  • Accès superutilisateur réel pour auditer, profiler et optimiser sans ticket support.

Prérequis matériels et logiciels

Pour une instance PostgreSQL de développement ou un petit projet en production, prévoyez un VPS avec 2 vCPU, 4 Go de RAM et 40 Go de SSD NVMe : PostgreSQL aime la mémoire pour son cache de pages. Pour une charge plus soutenue (plusieurs centaines de connexions ou jeux de données de plusieurs dizaines de Go), visez 4 vCPU et 8 Go de RAM. Côté logiciel : Ubuntu 22.04 ou 24.04 LTS, Docker Engine et le plugin Docker Compose v2, un nom de domaine pointant vers le VPS (ex : db.mondomaine.com) si vous exposez l'accès distant, et un pare-feu ufw configuré pour ne laisser passer que le strict nécessaire. Réservez aussi un volume Docker dédié pour PGDATA afin de découpler les données du conteneur.

Déployer PostgreSQL avec Docker en production

  1. Préparer le VPS et le pare-feu

    Connectez-vous en SSH, mettez à jour le système avec apt update && apt upgrade -y, installez Docker via curl -fsSL https://get.docker.com | sh. Bloquez le port 5432 depuis l'extérieur avec ufw deny 5432 : la base ne doit jamais être directement exposée à Internet.

  2. Écrire le docker-compose.yml

    Créez un service postgres:17, montez un volume nommé sur /var/lib/postgresql/data, et définissez POSTGRES_PASSWORD, POSTGRES_DB et POSTGRES_USER via un fichier .env jamais commité. Ajoutez shm_size: 256mb pour les tris volumineux et une healthcheck avec pg_isready.

  3. Lancer et initialiser la base

    Démarrez avec docker compose up -d, vérifiez les logs via docker compose logs -f postgres, puis connectez-vous avec docker compose exec postgres psql -U app -d mabase. Créez vos rôles applicatifs avec des privilèges minimaux plutôt que d'utiliser le superutilisateur.

  4. Exposer l'accès via un tunnel ou un proxy TLS

    Pour un accès distant sécurisé, n'ouvrez jamais 5432 en clair : utilisez un tunnel SSH (ssh -L 5432:localhost:5432) ou placez pgbouncer derrière un reverse proxy. Activez le SSL côté PostgreSQL avec un certificat Let's Encrypt monté dans le conteneur (ssl = on dans postgresql.conf).

  5. Tuner la configuration

    Ajustez shared_buffers à environ 25% de la RAM, effective_cache_size à 50-75%, et work_mem selon vos requêtes. Activez pg_stat_statements pour identifier les requêtes lentes. Utilisez l'outil PGTune comme point de départ.

  6. Automatiser les sauvegardes

    Planifiez un pg_dump quotidien via une tâche cron sur l'hôte, compressez en .dump custom format, et copiez les archives vers un stockage externe. Testez régulièrement la restauration avec pg_restore : une sauvegarde non testée n'existe pas.

  7. Se connecter la première fois

    pgAdmin n'est pas publié sur Internet : ouvrez un tunnel depuis votre poste (ssh -L 5050:127.0.0.1:5050 root@<IP>) puis http://127.0.0.1:5050, et connectez-vous avec [email protected] et le mot de passe fourni. Ajoutez ensuite votre serveur (« Add New Server ») avec l'hôte db, le port 5432, l'utilisateur postgres et ce même mot de passe.

Configurer postgresql.conf pour la production

  1. shared_buffers : le cache mémoire de PostgreSQL

    Définissez shared_buffers = 25% de la RAM totale du VPS. Sur 8 Go de RAM, cela donne 2 Go. Ce paramètre contrôle la taille du cache de pages partagé entre tous les processus PostgreSQL — c'est le levier le plus important pour les lectures répétées. Un fichier postgresql.conf personnalisé monté via Docker (-v ./postgresql.conf:/etc/postgresql/postgresql.conf) permet d'appliquer ces réglages au démarrage du conteneur.

  2. work_mem et max_connections

    Réglez work_mem en fonction de vos requêtes de tri et de jointure : 4 à 16 Mo est raisonnable pour une charge mixte. Attention : chaque connexion peut allouer plusieurs fois work_mem simultanément, donc multipliez par max_connections pour estimer la consommation mémoire maximale. Pour 100 connexions applicatives, max_connections = 150 (réserve pour les outils de monitoring et les migrations) suffit largement ; au-delà, utilisez pgbouncer en mode transaction pour multiplexer les connexions.

  3. Logging et détection des requêtes lentes

    Activez logging_collector = on, log_min_duration_statement = <seuil_ms> (ms) et log_line_prefix = '%t [%p]: [%l-1] db=%d,user=%u ' pour tracer toutes les requêtes qui dépassent le seuil configuré. Les logs atterrissent dans pg_log/ à l'intérieur du volume PGDATA. Coupler cette configuration à pg_stat_statements (extension à activer dans shared_preload_libraries) vous donne une vue agrégée des requêtes les plus coûteuses sans scanner chaque fichier de log.

  4. WAL et checkpoints

    Augmentez wal_buffers à 16 Mo et checkpoint_completion_target à 0.9 pour étaler l'écriture des checkpoints dans le temps. Sur un SSD NVMe, random_page_cost = 1.1 (au lieu du défaut 4.0) incite le planificateur à choisir les index scans plutôt que les seq scans — un réglage souvent oublié qui change drastiquement les plans d'exécution sur une base volumineuse.

Sauvegardes automatiques et stratégie de recovery

Une sauvegarde non testée est une sauvegarde qui n'existe pas. Trois approches complémentaires couvrent des besoins différents.

pg_dump + cron est le point de départ : simple à mettre en place, il produit un fichier SQL logique restaurable sur n'importe quelle version compatible. Planifiez-le à 3h du matin, compressez avec --format=custom (format binaire compressé, restauration sélective par table), et copiez l'archive vers un stockage externe (objet S3-compatible, autre VPS) avec rclone ou scp. Conservez 7 jours en local et 30 jours en distant.

pgBackRest va plus loin : il supporte les backups incrémentaux et différentiels, la compression parallèle et la restauration point-in-time (PITR) à partir des archives WAL. C'est la solution recommandée dès que votre base dépasse quelques Go ou que vous avez besoin de revenir à un état précis à la minute près après un DELETE accidentel. Il se configure via un fichier pgbackrest.conf et s'intègre à un cron ou un timer systemd.

Test de restauration mensuel : exécutez régulièrement pg_restore -d test_restore <dump> sur un VPS de test pour vérifier l'intégrité de vos archives. Un script hebdomadaire qui restaure la dernière sauvegarde et vérifie le nombre de tables ou une requête de contrôle suffit à détecter une corruption silencieuse avant qu'elle ne soit critique.

Haute disponibilité légère sans Kubernetes

La haute disponibilité PostgreSQL sur VPS n'implique pas nécessairement Patroni ou un cluster Pacemaker complexe. La réplication streaming native couvre la majorité des besoins avec un minimum de configuration.

Réplication streaming manuelle : sur le VPS primaire, activez wal_level = replica, ajoutez un utilisateur dédié replicator dans pg_hba.conf et définissez max_wal_senders = 3. Sur le VPS secondaire (standby), lancez pg_basebackup pour initialiser une copie physique, créez un fichier standby.signal et configurez primary_conninfo dans postgresql.conf. La réplication démarre automatiquement au redémarrage. Avec hot_standby = on, la standby accepte les requêtes en lecture seule — parfait pour déporter les rapports et le monitoring.

Patroni ajoute la bascule automatique (failover) : il surveille le primaire via une clé dans etcd, Consul ou ZooKeeper, et promeut automatiquement la standby si le primaire devient inaccessible pendant plus de 30 secondes. Sur deux VPS, il suffit d'un etcd tiers (VM légère ou service managé) pour le consensus. Patroni est la voie recommandée dès que vous ne pouvez pas tolérer une intervention manuelle de 5 à 15 minutes lors d'une panne.

Supervision du lag de réplication : SELECT pg_wal_lsn_diff(pg_current_wal_lsn(), sent_lsn) AS lag_bytes FROM pg_stat_replication sur le primaire vous donne le décalage en octets en temps réel. Un lag supérieur à quelques Mo indique une saturation réseau ou une standby surchargée.

PostgreSQL self-hosted vs RDS vs Supabase vs Neon

Faites défiler le tableau

CritèreVPS ServOrbit (self-hosted)AWS RDS PostgreSQLSupabase (cloud)Neon (serverless)
Coût mensuel (small)99 DH/mois (forfait fixe)~35-70 $/mois (db.t3.medium)~25 $/mois (Pro)~19 $/mois (Launch)
Contrôle de postgresql.confTotalPartiel (paramètre groups)LimitéMinimal
Extensions customToutes (pgvector, PostGIS…)Liste restreintepgvector, PostGISLimitées
PITR (Point-in-Time Recovery)Oui avec pgBackRestOui (natif)Oui (Pro+)Oui (natif)
Haute disponibilitéRéplication manuelle ou PatroniMulti-AZ natifNatifMulti-région natif
Charge de maintenanceÉlevée (DBA requis)FaibleTrès faibleTrès faible
Données hors USOui (VPS marocain)Selon régionSelon régionUS/EU uniquement
Superuser / extensionsOuiNonNonNon

Dépannage des problèmes courants en production

OOM killer tue PostgreSQL : le signal OOM dans /var/log/syslog (oom_kill_process) indique que la mémoire est épuisée. Causes principales : shared_buffers trop élevé, work_mem mal calibré face au nombre de connexions, ou processus concurrent (Elasticsearch, Node.js) qui consomme tout le swap. Diagnostic : cat /proc/meminfo | grep -E 'MemFree|Cached|Buffers' et ps aux --sort=-%mem | head -10. Remède : réduire work_mem, activer huge_pages = try dans postgresql.conf, ou upgrader le VPS.

Connexions épuisées (FATAL: sorry, too many clients already) : max_connections est atteint. Court terme : SELECT count(*), state FROM pg_stat_activity GROUP BY state pour identifier les connexions idle. Long terme : déployez pgbouncer en mode transaction (pool_mode = transaction) devant PostgreSQL — il multiplex des centaines de connexions applicatives vers un pool de 20-50 connexions réelles.

Autovacuum saturé : des tables avec beaucoup d'UPDATE ou de DELETE accumulent des tuples morts (dead tuples) qui gonflent les tables et ralentissent les scans. SELECT relname, n_dead_tup, last_autovacuum FROM pg_stat_user_tables ORDER BY n_dead_tup DESC LIMIT 10 révèle les tables problématiques. Accélérez l'autovacuum en réduisant autovacuum_vacuum_scale_factor (ex : 0.01 au lieu de 0.2) pour les tables critiques via ALTER TABLE ... SET (autovacuum_vacuum_scale_factor = 0.01).

Checkpoints trop fréquents (LOG: checkpoint occurring too frequently) : le WAL se remplit plus vite que checkpoint_timeout (défaut 5 min). Augmentez max_wal_size (ex : 2-4 Go) et checkpoint_timeout à 15-30 min pour espacer les checkpoints sans risquer une perte de données excessive en cas de crash.

Pour une haute disponibilité, déployez un second VPS en réplication physique en streaming (primary_conninfo + slot de réplication). Vous obtenez une standby chaude prête à basculer, et vous pouvez y déporter vos requêtes de lecture lourdes (hot_standby = on) pour soulager le primaire. Couplé à pgBackRest pour des backups incrémentaux différentiels, vous atteignez un RPO de quelques minutes sans dépendre d'un service managé.

La documentation officielle

Pour la configuration avancée, les options propres à l'outil et les changements de version, référez-vous à la documentation officielle de PostgreSQL. Ce guide couvre la mise en ligne sur VPS ServOrbit ; la documentation éditeur reste la référence pour les réglages fins.

Déployez votre PostgreSQL en quelques minutes

Lancez un VPS Cloud ServOrbit avec template Docker préconfiguré et SSD : l'environnement idéal pour héberger PostgreSQL sans facturation au Go.