Best VPS for PostgreSQL 2026: Self-Host Your Database
REVIEW 10 min read fordnox

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. If MySQL is more your style, check our MySQL VPS guide.

Why Self-Host PostgreSQL?

Why Self-Host PostgreSQL?

Why Self-Host PostgreSQL?

FactorManaged (AWS RDS)Self-Hosted VPS
2 vCPU, 4GB RAM$100+/mo~$7/mo
4 vCPU, 8GB RAM$200+/mo~$15/mo
ControlLimitedFull
ExtensionsSomeAll
MaintenanceAutomaticManual

Self-hosting costs 90% less for equivalent specs.

VPS Requirements

PostgreSQL performance depends on:

RAM (Most Important)

Storage (Second Most Important)

CPU

Network

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 (see also our VPS security guide)

# 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

FactorSelf-HostedRDS/Managed
Cost$5-20/mo$100-500/mo
Setup1-2 hours5 minutes
BackupsManual setupAutomatic
UpdatesManualAutomatic
ExtensionsAllLimited
TuningFull controlLimited
SupportCommunityProvider

Choose self-hosted if:

Choose managed if:

Resource Sizing Guide

UsersData SizeVPS SpecsProvider
<1K<5GB2 vCPU, 4GBHetzner CX21
1-10K5-50GB2 vCPU, 8GBHetzner CX31
10-100K50-200GB4 vCPU, 16GBHetzner CX41
>100K>200GB8+ 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.

Use CaseVPSMonthly Cost
DevelopmentHetzner CX11€3.79
Small ProductionHetzner CX21€5.39
Medium ProductionHetzner CX31€10.49
High PerformanceVultr HF$48

Start with Hetzner CX21 at €5.39/month — that’s 95% cheaper than equivalent RDS.

~/best-vps-for-postgresql/get-started

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

best vps for postgresql postgresql hosting self-hosted postgres postgres vps database server

// related guides

Andrius Putna

Andrius Putna

I am Andrius Putna. Geek. Since early 2000 in love tinkering with web technologies. Now AI. Bridging business and technology to drive meaningful impact. Combining expertise in customer experience, technology, and business strategy to deliver valuable insights. Father, open-source contributor, investor, 2xIronman, MBA graduate.

// last updated: February 8, 2026. Disclosure: This article may contain affiliate links.