Best VPS for PostgreSQL 2026: Self-Host Your Database
Find the best VPS for hosting PostgreSQL. Compare specs, optimize performance, and run your own database server for less than managed services.
Best VPS for PostgreSQL in 2026
PostgreSQL is the world's most advanced open-source database. Self-host it on a VPS and skip the $50-500/month managed database fees.
Why Self-Host PostgreSQL?
| Factor | Managed (AWS RDS) | Self-Hosted VPS |
|---|---|---|
| 2 vCPU, 4GB RAM | $100+/mo | ~$7/mo |
| 4 vCPU, 8GB RAM | $200+/mo | ~$15/mo |
| Control | Limited | Full |
| Extensions | Some | All |
| Maintenance | Automatic | Manual |
Self-hosting costs 90% less for equivalent specs.
VPS Requirements
PostgreSQL performance depends on:
RAM (Most Important)
- More RAM = more data cached
- Rule: Cache your hot data
- 4GB handles most small-medium apps
Storage (Second Most Important)
- NVMe SSD required — HDDs are too slow
- Provision 2-3x your data size for WAL/indexes
- IOPS matter more than raw size
CPU
- More cores = more concurrent queries
- 2 vCPU is fine for most workloads
- Scale up for complex analytical queries
Network
- Low latency to app servers
- Same datacenter as your application
Best VPS for PostgreSQL
1. Hetzner CX21 (Best Value)
€5.39/mo | 2 vCPU, 4GB RAM, 40GB NVMe
AMD EPYC CPUs have excellent per-core performance. NVMe storage handles database I/O well.
Best for: Small to medium applications
2. Hostinger KVM2 (Best RAM/Dollar)
$5.99/mo | 2 vCPU, 8GB RAM, 100GB NVMe
8GB RAM means more data in memory. Great for caching-heavy workloads.
3. Hetzner CX31 (Best for Growth)
€10.49/mo | 2 vCPU, 8GB RAM, 80GB NVMe
8GB RAM with fast NVMe. Hetzner's network handles replication traffic well.
4. Vultr High Frequency (Best Performance)
$48/mo | 4 vCPU (3GHz+), 16GB RAM, 256GB NVMe
High clock speed = faster single-query performance. Worth it for latency-sensitive apps.
PostgreSQL Setup Guide
Step 1: Create VPS
Ubuntu 22.04, 4GB+ RAM. SSH in:
ssh root@your-vps-ip
Step 2: Install PostgreSQL
# Add PostgreSQL repository
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
# Install
sudo apt update
sudo apt install -y postgresql-16
# Start service
sudo systemctl enable postgresql
sudo systemctl start postgresql
Step 3: Create Database and User
sudo -u postgres psql
CREATE USER myapp WITH PASSWORD 'secure-password';
CREATE DATABASE myapp_production OWNER myapp;
GRANT ALL PRIVILEGES ON DATABASE myapp_production TO myapp;
\q
Step 4: Configure for Remote Access
Edit /etc/postgresql/16/main/postgresql.conf:
listen_addresses = '*'
Edit /etc/postgresql/16/main/pg_hba.conf:
# Allow connections from app servers
host myapp_production myapp 10.0.0.0/8 scram-sha-256
# Or specific IP
host myapp_production myapp 1.2.3.4/32 scram-sha-256
Restart:
sudo systemctl restart postgresql
Step 5: Firewall
ufw allow from 10.0.0.0/8 to any port 5432
# Or specific IP
ufw allow from 1.2.3.4 to any port 5432
Performance Tuning
Memory Configuration
Edit /etc/postgresql/16/main/postgresql.conf:
# For 4GB RAM VPS
shared_buffers = 1GB # 25% of RAM
effective_cache_size = 3GB # 75% of RAM
maintenance_work_mem = 256MB
work_mem = 16MB # Per-operation
# For 8GB RAM VPS
shared_buffers = 2GB
effective_cache_size = 6GB
maintenance_work_mem = 512MB
work_mem = 32MB
Write Performance
wal_buffers = 64MB
checkpoint_completion_target = 0.9
checkpoint_timeout = 15min
max_wal_size = 4GB
min_wal_size = 1GB
Query Performance
random_page_cost = 1.1 # For SSD
effective_io_concurrency = 200 # For SSD
default_statistics_target = 100
Connection Pooling
Use PgBouncer for many connections:
apt install pgbouncer
# /etc/pgbouncer/pgbouncer.ini
[databases]
myapp = host=127.0.0.1 dbname=myapp_production
[pgbouncer]
listen_addr = *
listen_port = 6432
auth_type = scram-sha-256
auth_file = /etc/pgbouncer/userlist.txt
pool_mode = transaction
max_client_conn = 1000
default_pool_size = 20
Your app connects to port 6432 instead of 5432.
Backup Strategy
Continuous Archiving (WAL)
Enable in postgresql.conf:
archive_mode = on
archive_command = 'cp %p /var/lib/postgresql/wal_archive/%f'
wal_level = replica
Daily Backups
#!/bin/bash
# /home/postgres/backup.sh
DATE=$(date +%Y%m%d)
BACKUP_DIR=/var/backups/postgresql
pg_dump -Fc myapp_production > $BACKUP_DIR/myapp-$DATE.dump
# Keep 7 days
find $BACKUP_DIR -mtime +7 -delete
# Upload to S3
aws s3 cp $BACKUP_DIR/myapp-$DATE.dump s3://my-backups/postgres/
Cron:
0 3 * * * /home/postgres/backup.sh
Point-in-Time Recovery
With WAL archiving enabled:
# Restore base backup
pg_restore -d myapp_production backup.dump
# Replay WAL to specific time
recovery_target_time = '2026-02-08 14:30:00'
Monitoring
Built-in Stats
-- Active connections
SELECT * FROM pg_stat_activity;
-- Table sizes
SELECT pg_size_pretty(pg_total_relation_size('table_name'));
-- Slow queries
SELECT * FROM pg_stat_statements ORDER BY mean_time DESC LIMIT 10;
pgAdmin
docker run -d \
-p 8080:80 \
-e PGADMIN_DEFAULT_EMAIL=admin@admin.com \
-e PGADMIN_DEFAULT_PASSWORD=admin \
dpage/pgadmin4
Prometheus + Grafana
# postgres_exporter
docker run -d \
-p 9187:9187 \
-e DATA_SOURCE_NAME="postgresql://postgres:password@localhost:5432/postgres?sslmode=disable" \
prometheuscommunity/postgres-exporter
Replication Setup
Streaming Replication
On primary, edit postgresql.conf:
wal_level = replica
max_wal_senders = 3
wal_keep_size = 1GB
On replica:
pg_basebackup -h primary-ip -D /var/lib/postgresql/16/main -U replicator -Fp -Xs -P -R
The replica automatically follows the primary.
Logical Replication
For selective table replication:
-- On primary
CREATE PUBLICATION my_pub FOR TABLE users, orders;
-- On replica
CREATE SUBSCRIPTION my_sub
CONNECTION 'host=primary-ip dbname=myapp user=replicator'
PUBLICATION my_pub;
Common Extensions
-- Full-text search
CREATE EXTENSION pg_trgm;
-- UUID generation
CREATE EXTENSION "uuid-ossp";
-- JSON operations
-- Built-in, no extension needed
-- Geographic data
CREATE EXTENSION postgis;
-- Query statistics
CREATE EXTENSION pg_stat_statements;
-- Cron jobs
CREATE EXTENSION pg_cron;
Security Hardening
SSL Connections
# Generate certificate
openssl req -new -x509 -days 365 -nodes -text \
-out /etc/postgresql/16/main/server.crt \
-keyout /etc/postgresql/16/main/server.key
In postgresql.conf:
ssl = on
ssl_cert_file = '/etc/postgresql/16/main/server.crt'
ssl_key_file = '/etc/postgresql/16/main/server.key'
In pg_hba.conf:
hostssl all all 0.0.0.0/0 scram-sha-256
Strong Passwords
Use scram-sha-256 (default in PostgreSQL 14+):
SET password_encryption = 'scram-sha-256';
ALTER USER myapp PASSWORD 'new-secure-password';
Limit Connections
# Only allow from app servers
host myapp_production myapp 10.0.0.0/8 scram-sha-256
host all all 0.0.0.0/0 reject
Self-Hosted vs Managed
| Factor | Self-Hosted | RDS/Managed |
|---|---|---|
| Cost | $5-20/mo | $100-500/mo |
| Setup | 1-2 hours | 5 minutes |
| Backups | Manual setup | Automatic |
| Updates | Manual | Automatic |
| Extensions | All | Limited |
| Tuning | Full control | Limited |
| Support | Community | Provider |
Choose self-hosted if:
- Cost matters
- You need full control
- You can spend 2-4h/month on maintenance
Choose managed if:
- Zero ops capacity
- Need guaranteed uptime SLA
- Budget isn't a concern
Resource Sizing Guide
| Users | Data Size | VPS Specs | Provider |
|---|---|---|---|
| <1K | <5GB | 2 vCPU, 4GB | Hetzner CX21 |
| 1-10K | 5-50GB | 2 vCPU, 8GB | Hetzner CX31 |
| 10-100K | 50-200GB | 4 vCPU, 16GB | Hetzner CX41 |
| >100K | >200GB | 8+ vCPU, 32GB+ | Dedicated |
FAQ
Is PostgreSQL hard to manage?
Moderately. Initial setup takes 1-2 hours. Ongoing: backups, updates, monitoring. Budget 2-4h/month.
How do I upgrade PostgreSQL?
Use pg_upgrade or pg_dump/restore. Plan for 30-60 min downtime.
Can I run PostgreSQL and my app on the same VPS?
Yes, for small projects. Separate servers for production scale.
What about high availability?
Use streaming replication with automatic failover (Patroni) for HA setups.
Should I use Docker?
For dev: yes. For production: native installation is simpler and performs better.
Recommended Setup
| Use Case | VPS | Monthly Cost |
|---|---|---|
| Development | Hetzner CX11 | €3.79 |
| Small Production | Hetzner CX21 | €5.39 |
| Medium Production | Hetzner CX31 | €10.49 |
| High Performance | Vultr HF | $48 |
Start with Hetzner CX21 at €5.39/month — that's 95% cheaper than equivalent RDS.
Ready to get started?
Get the best VPS hosting deal today. Hostinger offers 4GB RAM VPS starting at just $4.99/mo.
Get Hostinger VPS — $4.99/mo// up to 75% off + free domain included
// related topics
fordnox
Expert VPS reviews and hosting guides. We test every provider we recommend.
// last updated: February 8, 2026. Disclosure: This article may contain affiliate links.