[{"data":1,"prerenderedAt":220},["ShallowReactive",2],{"seo-verification":3,"blog-postgresql-on-a-vps-a-reliable-and-controlled-database-ma-en":6,"promo-bar-likely":219},{"google":4,"bing":5},"EycwPY2XMyTkVzas3n1ygeNJFGAH513qrMjfDljzsMQ","",{"key":7,"data":8},"blog-postgresql-on-a-vps-a-reliable-and-controlled-database-ma-en",{"id":9,"slug":10,"slugs":11,"title":15,"excerpt":16,"readTime":17,"views":18,"isPinned":19,"noindex":19,"publishedAt":20,"updatedAt":21,"category":22,"categories":28,"featuredImage":30,"bgImage":31,"posterImage":32,"relatedSolution":33,"intro":36,"sections":37,"ctaTitle":162,"ctaBody":163,"ctaButton":164,"ctaUrl":165,"relatedPosts":166},56,"postgresql-on-a-vps-a-reliable-and-controlled-database",{"fr":12,"en":10,"ar":13,"es":14},"heberger-postgresql-vps","postgresql-على-خادم-vps-قاعدة-بيانات-موثوقة-ومتحكم-بها","alojar-postgresql-en-un-vps","PostgreSQL on a VPS: reliable, controlled database","Host PostgreSQL on a VPS: production config, pgBackRest backups, streaming HA, RDS\u002FSupabase\u002FNeon comparison and OOM troubleshooting.",9,1,false,"2026-04-25T00:00:00+00:00","2026-10-21T15:21:37+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":27},6,"Databases","bases-de-donnees","bg-teal-500\u002F10 text-teal-400","database",[29],{"id":23,"name":24,"slug":25,"color":26,"icon":27},null,"\u002Fblog\u002Fcovers\u002Fbg.svg","\u002Fblog\u002Fcovers\u002Fheberger-postgresql-vps-poster.svg",{"categorySlug":34,"appSlug":35},"databases","postgresql-stack","PostgreSQL is often the trusted database of business applications, APIs and analytics tools. On a ServOrbit VPS, you control the version, storage, backups and access instead of paying for a managed database by the GB. This guide covers the decisions that matter — persistence, users, network and restoration — as well as fine-tuning `postgresql.conf`, automated backups with restore testing, streaming high availability across two VPS, and troubleshooting the most common production failures.",[38,42,52,55,80,95,98,101,153,156,159],{"type":39,"title":40,"body":41},"h2","Why self-host PostgreSQL on a VPS","Managed databases (RDS, Cloud SQL) bill per GB stored, per IOPS and per connection, and often limit available extensions. By deploying PostgreSQL on your own VPS, you enable `pg_stat_statements`, `PostGIS`, `pgvector` or `TimescaleDB` without restriction, choose your exact version (15, 16, 17) and keep your data in a jurisdiction you control. A VPS with an SSD disk offers very low I\u002FO latencies, ideal for the transactional workloads of a production application. You pay a fixed and predictable flat rate, and you alone decide on your strategy for replication, encryption and backup retention.",{"type":43,"title":44,"items":45},"ul","The concrete benefits of a self-hosted PostgreSQL",[46,47,48,49,50,51],"Fixed and predictable cost: no billing per GB, per IOPS or per number of active connections.","Free extensions: `pgvector` for AI, `PostGIS` for geospatial, `TimescaleDB` for time series.","Full control of backups: scheduled `pg_dump`, `pg_basebackup` or physical replication to a second VPS.","Fine tuning of `postgresql.conf` (shared_buffers, work_mem, WAL) impossible with most managed offerings.","Data sovereignty: your data stays on an infrastructure you choose.","Real superuser access to audit, profile and optimize without a support ticket.",{"type":39,"title":53,"body":54},"Hardware and software prerequisites","For a development PostgreSQL instance or a small production project, plan for a VPS with 2 vCPU, 4 GB of RAM and 40 GB of NVMe SSD: PostgreSQL likes memory for its page cache. For a heavier load (several hundred connections or datasets of several tens of GB), aim for 4 vCPU and 8 GB of RAM. On the software side: Ubuntu 22.04 or 24.04 LTS, Docker Engine and the Docker Compose v2 plugin, a domain name pointing to the VPS (e.g. `db.mydomain.com`) if you expose remote access, and a `ufw` firewall configured to let through only the strict minimum. Also reserve a dedicated Docker volume for `PGDATA` to decouple the data from the container.",{"type":56,"title":57,"steps":58},"steps","Deploy PostgreSQL with Docker in production",[59,62,65,68,71,74,77],{"title":60,"body":61},"Prepare the VPS and the firewall","Connect via SSH, update the system with `apt update && apt upgrade -y`, install Docker via `curl -fsSL https:\u002F\u002Fget.docker.com | sh`. Block port 5432 from the outside with `ufw deny 5432`: the database must never be directly exposed to the Internet.",{"title":63,"body":64},"Write the docker-compose.yml","Create a `postgres:17` service, mount a named volume on `\u002Fvar\u002Flib\u002Fpostgresql\u002Fdata`, and define `POSTGRES_PASSWORD`, `POSTGRES_DB` and `POSTGRES_USER` via a `.env` file that is never committed. Add `shm_size: 256mb` for large sorts and a `healthcheck` with `pg_isready`.",{"title":66,"body":67},"Launch and initialize the database","Start with `docker compose up -d`, check the logs via `docker compose logs -f postgres`, then connect with `docker compose exec postgres psql -U app -d mabase`. Create your application roles with minimal privileges rather than using the superuser.",{"title":69,"body":70},"Expose access via a tunnel or a TLS proxy","For secure remote access, never open 5432 in the clear: use an SSH tunnel (`ssh -L 5432:localhost:5432`) or place `pgbouncer` behind a reverse proxy. Enable SSL on the PostgreSQL side with a Let's Encrypt certificate mounted in the container (`ssl = on` in `postgresql.conf`).",{"title":72,"body":73},"Tune the configuration","Adjust `shared_buffers` to about 25% of the RAM, `effective_cache_size` to 50-75%, and `work_mem` according to your queries. Enable `pg_stat_statements` to identify slow queries. Use the PGTune tool as a starting point.",{"title":75,"body":76},"Automate the backups","Schedule a daily `pg_dump` via a cron task on the host, compress into custom `.dump` format, and copy the archives to external storage. Regularly test restoration with `pg_restore`: an untested backup does not exist.",{"title":78,"body":79},"Logging in for the first time","pgAdmin is not published on the internet: open a tunnel from your own machine (ssh -L 5050:127.0.0.1:5050 root@\u003CIP>), then go to http:\u002F\u002F127.0.0.1:5050 and sign in with admin@local.host and the password provided. Then add your server (\"Add New Server\") with host db, port 5432, user postgres and that same password.",{"type":56,"title":81,"steps":82},"Configure postgresql.conf for production",[83,86,89,92],{"title":84,"body":85},"shared_buffers: PostgreSQL's memory cache","Set `shared_buffers = 25%` of the VPS's total RAM. On 8 GB of RAM, that gives 2 GB. This parameter controls the size of the page cache shared between all PostgreSQL processes — it is the most important lever for repeated reads. A custom `postgresql.conf` file mounted via Docker (`-v .\u002Fpostgresql.conf:\u002Fetc\u002Fpostgresql\u002Fpostgresql.conf`) lets you apply these settings at container startup.",{"title":87,"body":88},"work_mem and max_connections","Set `work_mem` based on your sort and join queries: 4 to 16 MB is reasonable for mixed workloads. Note: each connection can allocate `work_mem` multiple times simultaneously, so multiply by `max_connections` to estimate peak memory usage. For 100 application connections, `max_connections = 150` (reserve for monitoring tools and migrations) is plenty; beyond that, use `pgbouncer` in transaction mode to multiplex connections.",{"title":90,"body":91},"Logging and slow query detection","Enable `logging_collector = on`, `log_min_duration_statement = \u003Cseuil_ms>` (ms) and `log_line_prefix = '%t [%p]: [%l-1] db=%d,user=%u '` to log all queries exceeding the configured threshold. Logs land in `pg_log\u002F` inside the PGDATA volume. Pairing this with `pg_stat_statements` (extension to enable in `shared_preload_libraries`) gives you an aggregated view of the most expensive queries without scanning each log file.",{"title":93,"body":94},"WAL and checkpoints","Increase `wal_buffers` to 16 MB and set `checkpoint_completion_target` to 0.9 to spread checkpoint writes over time. On NVMe SSD, `random_page_cost = 1.1` (instead of the default 4.0) encourages the planner to choose index scans over seq scans — a frequently overlooked setting that dramatically changes execution plans on large datasets.",{"type":39,"title":96,"body":97},"Automated backups and recovery strategy","An untested backup is a backup that does not exist. Three complementary approaches cover different needs.\n\n**`pg_dump` + cron** is the starting point: simple to set up, it produces a logical SQL file restorable on any compatible version. Schedule it at 3 AM, compress with `--format=custom` (compressed binary format, selective restore by table), and copy the archive to external storage (S3-compatible object, another VPS) with `rclone` or `scp`. Keep 7 days locally and 30 days remotely.\n\n**`pgBackRest`** goes further: it supports incremental and differential backups, parallel compression and point-in-time restore (PITR) from WAL archives. It is the recommended solution once your database exceeds a few GB or you need to rewind to a precise minute after an accidental `DELETE`. It is configured via a `pgbackrest.conf` file and integrates with a cron job or systemd timer.\n\n**Monthly restore test**: regularly run `pg_restore -d test_restore \u003Cdump>` on a test VPS to verify archive integrity. A weekly script that restores the latest backup and checks a table count or a control query is enough to catch silent corruption before it becomes critical.",{"type":39,"title":99,"body":100},"Lightweight high availability without Kubernetes","PostgreSQL high availability on a VPS does not necessarily require Patroni or a complex Pacemaker cluster. Native streaming replication covers most needs with minimal configuration.\n\n**Manual streaming replication**: on the primary VPS, enable `wal_level = replica`, add a dedicated `replicator` user in `pg_hba.conf` and set `max_wal_senders = 3`. On the secondary (standby) VPS, run `pg_basebackup` to initialize a physical copy, create a `standby.signal` file and configure `primary_conninfo` in `postgresql.conf`. Replication starts automatically on restart. With `hot_standby = on`, the standby accepts read-only queries — perfect for offloading reports and monitoring.\n\n**Patroni** adds automatic failover: it monitors the primary via a key in `etcd`, `Consul` or `ZooKeeper`, and automatically promotes the standby if the primary becomes unreachable for more than 30 seconds. On two VPS, a third-party `etcd` (lightweight VM or managed service) for consensus is sufficient. Patroni is the recommended path when you cannot tolerate a 5-to-15-minute manual intervention during a failure.\n\n**Replication lag monitoring**: `SELECT pg_wal_lsn_diff(pg_current_wal_lsn(), sent_lsn) AS lag_bytes FROM pg_stat_replication` on the primary gives you the real-time lag in bytes. A lag above a few MB indicates network saturation or an overloaded standby.",{"type":102,"title":103,"columns":104,"rows":110},"comparison","PostgreSQL self-hosted vs RDS vs Supabase vs Neon",[105,106,107,108,109],"Criterion","ServOrbit VPS (self-hosted)","AWS RDS PostgreSQL","Supabase (cloud)","Neon (serverless)",[111,117,123,128,133,139,144,149],[112,113,114,115,116],"Monthly cost (small)","99 DH\u002Fmonth (flat rate)","~$35-70\u002Fmonth (db.t3.medium)","~$25\u002Fmonth (Pro)","~$19\u002Fmonth (Launch)",[118,119,120,121,122],"postgresql.conf control","Full","Partial (parameter groups)","Limited","Minimal",[124,125,126,127,121],"Custom extensions","All (pgvector, PostGIS…)","Restricted list","pgvector, PostGIS",[129,130,131,132,131],"PITR (Point-in-Time Recovery)","Yes with pgBackRest","Yes (native)","Yes (Pro+)",[134,135,136,137,138],"High availability","Manual replication or Patroni","Multi-AZ native","Native","Multi-region native",[140,141,142,143,143],"Maintenance burden","High (DBA required)","Low","Very low",[145,146,147,147,148],"Data outside US","Yes (Moroccan VPS)","By region","US\u002FEU only",[150,151,152,152,152],"Superuser \u002F extensions","Yes","No",{"type":39,"title":154,"body":155},"Troubleshooting common production issues","**OOM killer kills PostgreSQL**: the `OOM` signal in `\u002Fvar\u002Flog\u002Fsyslog` (`oom_kill_process`) means memory is exhausted. Main causes: `shared_buffers` set too high, `work_mem` miscalibrated against connection count, or a concurrent process (Elasticsearch, Node.js) consuming all swap. Diagnosis: `cat \u002Fproc\u002Fmeminfo | grep -E 'MemFree|Cached|Buffers'` and `ps aux --sort=-%mem | head -10`. Fix: reduce `work_mem`, enable `huge_pages = try` in `postgresql.conf`, or upgrade the VPS.\n\n**Connections exhausted** (`FATAL: sorry, too many clients already`): `max_connections` is reached. Short term: `SELECT count(*), state FROM pg_stat_activity GROUP BY state` to identify idle connections. Long term: deploy `pgbouncer` in transaction mode (`pool_mode = transaction`) in front of PostgreSQL — it multiplexes hundreds of application connections onto a pool of 20-50 real connections.\n\n**Autovacuum saturated**: tables with many `UPDATE` or `DELETE` operations accumulate dead tuples that bloat tables and slow down scans. `SELECT relname, n_dead_tup, last_autovacuum FROM pg_stat_user_tables ORDER BY n_dead_tup DESC LIMIT 10` reveals the problematic tables. Speed up autovacuum by reducing `autovacuum_vacuum_scale_factor` (e.g. 0.01 instead of 0.2) for critical tables via `ALTER TABLE ... SET (autovacuum_vacuum_scale_factor = 0.01)`.\n\n**Checkpoints too frequent** (`LOG: checkpoint occurring too frequently`): WAL fills faster than `checkpoint_timeout` (default 5 min). Increase `max_wal_size` (e.g. 2-4 GB) and `checkpoint_timeout` to 15-30 min to space out checkpoints without risking excessive data loss on a crash.",{"type":157,"body":158},"tip","For high availability, deploy a second VPS in physical streaming replication (`primary_conninfo` + replication slot). You get a warm standby ready to fail over, and you can offload your heavy read queries to it (`hot_standby = on`) to relieve the primary. Combined with `pgBackRest` for differential incremental backups, you reach an RPO of a few minutes without depending on a managed service.",{"type":157,"title":160,"body":161},"The official documentation","For advanced configuration, tool-specific options and version changes, refer to the \u003Ca href=\"https:\u002F\u002Fwww.postgresql.org\u002Fdocs\u002F\" target=\"_blank\" rel=\"noopener noreferrer\">official PostgreSQL documentation\u003C\u002Fa>. This guide covers going live on a ServOrbit VPS; the vendor documentation remains the reference for fine tuning.","Deploy your PostgreSQL in minutes","Launch a ServOrbit Cloud VPS with a preconfigured Docker template and SSD storage: the ideal environment to host PostgreSQL without per-GB billing.","Configure my Cloud VPS","\u002Fvps-cloud",[167,185,203],{"id":168,"slug":169,"slugs":170,"title":174,"excerpt":175,"readTime":17,"views":176,"isPinned":19,"noindex":19,"publishedAt":177,"updatedAt":178,"category":179,"categories":180,"featuredImage":30,"bgImage":31,"posterImage":182,"relatedSolution":183},57,"hosting-mysql-on-a-vps",{"fr":171,"en":169,"ar":172,"es":173},"heberger-mysql-vps","استضافة-mysql-على-خادم-vps","alojar-mysql-en-un-vps","Hosting MySQL on a VPS: complete guide","Install MySQL 8.4 LTS on a VPS: prerequisites, security hardening, InnoDB performance, secure remote access, automated backups, and troubleshooting.",0,"2026-04-24T00:00:00+00:00","2026-11-09T20:55:18+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":27},[181],{"id":23,"name":24,"slug":25,"color":26,"icon":27},"\u002Fblog\u002Fcovers\u002Fheberger-mysql-vps-poster.svg",{"categorySlug":34,"appSlug":184},"mysql-stack",{"id":186,"slug":187,"slugs":188,"title":192,"excerpt":193,"readTime":194,"views":176,"isPinned":19,"noindex":19,"publishedAt":195,"updatedAt":196,"category":197,"categories":198,"featuredImage":30,"bgImage":31,"posterImage":200,"relatedSolution":201},58,"hosting-redis-on-a-vps",{"fr":189,"en":187,"ar":190,"es":191},"heberger-redis-vps","استضافة-redis-على-خادم-vps","alojar-redis-en-un-vps","Hosting Redis on a VPS: the complete guide","Deploy Redis on your Cloud VPS: RAM\u002FCPU requirements, security (ACL, TLS), RDB\u002FAOF persistence, troubleshooting, and high availability.",10,"2026-04-23T00:00:00+00:00","2026-09-08T21:59:59+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":27},[199],{"id":23,"name":24,"slug":25,"color":26,"icon":27},"\u002Fblog\u002Fcovers\u002Fheberger-redis-vps-poster.svg",{"categorySlug":34,"appSlug":202},"redis-stack",{"id":204,"slug":205,"slugs":206,"title":210,"excerpt":211,"readTime":212,"views":176,"isPinned":19,"noindex":19,"publishedAt":213,"updatedAt":214,"category":215,"categories":216,"featuredImage":30,"bgImage":31,"posterImage":218,"relatedSolution":30},59,"hosting-mongodb-on-a-vps",{"fr":207,"en":205,"ar":208,"es":209},"heberger-mongodb-vps","استضافة-mongodb-على-خادم-vps","alojar-mongodb-en-un-vps","Hosting MongoDB on a VPS","Host MongoDB on your Cloud VPS: Docker deployment, replica set, authentication, indexing, and controlled backups.",3,"2026-04-22T00:00:00+00:00","2026-09-08T22:00:02+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":27},[217],{"id":23,"name":24,"slug":25,"color":26,"icon":27},"\u002Fblog\u002Fcovers\u002Fheberger-mongodb-vps-poster.svg",true,1794270472861]