Por qué autoalojar PostgreSQL en un VPS
Las bases de datos gestionadas (RDS, Cloud SQL) facturan por GB almacenado, por IOPS y por conexiones, y a menudo limitan las extensiones disponibles. Al desplegar PostgreSQL en su propio VPS, activa pg_stat_statements, PostGIS, pgvector o TimescaleDB sin restricción, elige su versión exacta (15, 16, 17) y mantiene sus datos en una jurisdicción que usted controla. Un VPS con disco SSD ofrece latencias de I/O muy bajas, ideales para las cargas transaccionales de una aplicación en producción. Paga una tarifa fija y previsible, y decide usted solo su estrategia de replicación, de cifrado y de retención de las copias de seguridad.
Los beneficios concretos de un PostgreSQL autoalojado
- Coste fijo y previsible: sin facturación por GB, por IOPS ni por número de conexiones activas.
- Extensiones libres:
pgvectorpara la IA,PostGISpara lo geoespacial,TimescaleDBpara las series temporales. - Control total de las copias de seguridad:
pg_dumpplanificado,pg_basebackupo replicación física hacia un segundo VPS. - Ajuste fino de
postgresql.conf(shared_buffers, work_mem, WAL), imposible en la mayoría de las ofertas gestionadas. - Soberanía de los datos: sus datos permanecen en una infraestructura que usted elige.
- Acceso de superusuario real para auditar, perfilar y optimizar sin abrir un ticket de soporte.
Requisitos de hardware y software
Para una instancia PostgreSQL de desarrollo o un proyecto pequeño en producción, prevea un VPS con 2 vCPU, 4 GB de RAM y 40 GB de SSD NVMe: PostgreSQL aprovecha la memoria para su caché de páginas. Para una carga más sostenida (varios cientos de conexiones o conjuntos de datos de varias decenas de GB), apunte a 4 vCPU y 8 GB de RAM. En cuanto al software: Ubuntu 22.04 o 24.04 LTS, Docker Engine y el plugin Docker Compose v2, un nombre de dominio que apunte al VPS si expone el acceso remoto, y un cortafuegos ufw configurado para dejar pasar solo lo estrictamente necesario. Reserve también un volumen Docker dedicado para PGDATA con el fin de desacoplar los datos del contenedor.
Desplegar PostgreSQL con Docker en producción
Preparar el VPS y el cortafuegos
Conéctese por SSH, actualice el sistema con
apt update && apt upgrade -ye instale Docker mediantecurl -fsSL https://get.docker.com | sh. Bloquee el puerto 5432 desde el exterior conufw deny 5432: la base de datos nunca debe estar expuesta directamente a Internet.Escribir el docker-compose.yml
Cree un servicio
postgres:17, monte un volumen con nombre en/var/lib/postgresql/datay definaPOSTGRES_PASSWORD,POSTGRES_DByPOSTGRES_USERmediante un archivo.envque nunca se suba al repositorio. Añadashm_size: 256mbpara las ordenaciones voluminosas y unhealthcheckconpg_isready.Lanzar e inicializar la base de datos
Arranque con
docker compose up -d, compruebe los logs condocker compose logs -f postgresy después conéctese condocker compose exec postgres psql -U app -d mabase. Cree sus roles de aplicación con privilegios mínimos en lugar de utilizar el superusuario.Exponer el acceso mediante un túnel o un proxy TLS
Para un acceso remoto seguro, nunca abra 5432 en claro: utilice un túnel SSH (
ssh -L 5432:localhost:5432) o coloquepgbouncerdetrás de un reverse proxy. Active el SSL del lado de PostgreSQL con un certificado Let's Encrypt montado en el contenedor (ssl = onenpostgresql.conf).Ajustar la configuración
Ajuste
shared_buffersa alrededor del 25% de la RAM,effective_cache_sizeal 50-75% ywork_memsegún sus consultas. Activepg_stat_statementspara identificar las consultas lentas. Utilice la herramienta PGTune como punto de partida.Automatizar las copias de seguridad
Programe un
pg_dumpdiario mediante una tarea cron en el host, comprima en formato custom.dumpy copie los archivos hacia un almacenamiento externo. Pruebe regularmente la restauración conpg_restore: una copia de seguridad no probada no existe.Conectarse por primera vez
pgAdmin no está publicado en Internet: abra un túnel desde su equipo (ssh -L 5050:127.0.0.1:5050 root@<IP>) y después http://127.0.0.1:5050, e inicie sesión con [email protected] y la contraseña facilitada. A continuación añada su servidor («Add New Server») con el host db, el puerto 5432, el usuario postgres y esa misma contraseña.
Configurar postgresql.conf para producción
work_mem y max_connections
Establezca
work_memen función de sus consultas de ordenación y unión: de 4 a 16 MB es razonable para cargas mixtas. Atención: cada conexión puede asignarwork_memvarias veces simultáneamente, así que multiplique pormax_connectionspara estimar el pico de consumo de memoria. Para 100 conexiones de aplicación,max_connections = 150es suficiente; más allá, usepgbounceren modo transacción para multiplexar conexiones.Logging y detección de consultas lentas
Active
logging_collector = onylog_min_duration_statement = <seuil_ms>(ms) para registrar todas las consultas que superen el umbral configurado. Combinar esto conpg_stat_statements(extensión a activar enshared_preload_libraries) ofrece una vista agregada de las consultas más costosas sin escanear cada archivo de log.WAL y checkpoints
Aumente
wal_buffersa 16 MB y establezcacheckpoint_completion_targeten 0.9 para distribuir las escrituras de checkpoints en el tiempo. En SSD NVMe,random_page_cost = 1.1(en lugar del valor por defecto 4.0) anima al planificador a elegir index scans en lugar de seq scans — un ajuste frecuentemente ignorado que cambia drásticamente los planes de ejecución en bases de datos grandes.
Copias de seguridad automáticas y estrategia de recuperación
Una copia de seguridad no probada es una copia que no existe. Tres enfoques complementarios cubren necesidades distintas.
pg_dump + cron es el punto de partida: sencillo de configurar, produce un archivo SQL lógico restaurable en cualquier versión compatible. Prográmelo a las 3 AM, comprima con --format=custom, y copie el archivo hacia almacenamiento externo con rclone o scp. Conserve 7 días en local y 30 días en remoto.
pgBackRest va más lejos: admite copias incrementales y diferenciales, compresión paralela y restauración a punto en el tiempo (PITR) a partir de archivos WAL. Es la solución recomendada cuando su base supera unos pocos GB o necesita volver a un minuto preciso tras un DELETE accidental.
Prueba de restauración mensual: ejecute pg_restore -d test_restore <dump> regularmente en un VPS de prueba para verificar la integridad de sus archivos.
Alta disponibilidad ligera sin Kubernetes
La alta disponibilidad de PostgreSQL en un VPS no implica necesariamente Patroni o un clúster Pacemaker complejo. La replicación streaming nativa cubre la mayoría de las necesidades con una configuración mínima.
Replicación streaming manual: en el VPS primario, active wal_level = replica, añada un usuario replicator en pg_hba.conf y establezca max_wal_senders = 3. En el VPS secundario (standby), ejecute pg_basebackup para inicializar una copia física, cree un archivo standby.signal y configure primary_conninfo en postgresql.conf. La replicación arranca automáticamente al reiniciar. Con hot_standby = on, el standby acepta consultas de solo lectura.
Patroni añade la conmutación por error automática: monitoriza el primario mediante una clave en etcd o Consul, y promueve automáticamente el standby si el primario deja de responder durante más de 30 segundos.
Monitorización del lag de replicación: SELECT pg_wal_lsn_diff(pg_current_wal_lsn(), sent_lsn) AS lag_bytes FROM pg_stat_replication en el primario le da el desfase en bytes en tiempo real.
PostgreSQL self-hosted vs RDS vs Supabase vs Neon
Desplace la tabla
| Criterio | VPS ServOrbit (self-hosted) | AWS RDS PostgreSQL | Supabase (cloud) | Neon (serverless) |
|---|---|---|---|---|
| Coste mensual (small) | 99 DH/mes (tarifa plana) | ~35-70 $/mes (db.t3.medium) | ~25 $/mes (Pro) | ~19 $/mes (Launch) |
| Control de postgresql.conf | Total | Parcial (grupos de parámetros) | Limitado | Mínimo |
| Extensiones personalizadas | Todas (pgvector, PostGIS…) | Lista restringida | pgvector, PostGIS | Limitadas |
| PITR | Sí con pgBackRest | Sí (nativo) | Sí (Pro+) | Sí (nativo) |
| Alta disponibilidad | Replicación manual o Patroni | Multi-AZ nativo | Nativo | Multi-región nativo |
| Carga de mantenimiento | Alta (requiere DBA) | Baja | Muy baja | Muy baja |
| Datos fuera de EE.UU. | Sí (VPS marroquí) | Por región | Por región | Solo EE.UU./UE |
| Superusuario / extensiones | Sí | No | No | No |
Resolución de problemas frecuentes en producción
El OOM killer mata PostgreSQL: la señal OOM en /var/log/syslog indica que la memoria se ha agotado. Causas principales: shared_buffers demasiado alto, work_mem mal calibrado frente al número de conexiones. Diagnóstico: cat /proc/meminfo | grep -E 'MemFree|Cached|Buffers'. Solución: reducir work_mem, activar huge_pages = try en postgresql.conf, o actualizar el VPS.
Conexiones agotadas (FATAL: sorry, too many clients already): se ha alcanzado max_connections. Corto plazo: SELECT count(*), state FROM pg_stat_activity GROUP BY state para identificar conexiones inactivas. Largo plazo: despliegue pgbouncer en modo transacción delante de PostgreSQL.
Autovacuum saturado: las tablas con muchas operaciones UPDATE o DELETE acumulan tuplas muertas. SELECT relname, n_dead_tup, last_autovacuum FROM pg_stat_user_tables ORDER BY n_dead_tup DESC LIMIT 10 revela las tablas problemáticas. Acelere el autovacuum reduciendo autovacuum_vacuum_scale_factor a 0.01 para las tablas críticas.
Checkpoints demasiado frecuentes (LOG: checkpoint occurring too frequently): aumente max_wal_size a 2-4 GB y checkpoint_timeout a 15-30 min para espaciar los checkpoints.
Para alta disponibilidad, despliegue un segundo VPS en replicación física por streaming (primary_conninfo + slot de replicación). Obtiene un standby caliente listo para tomar el relevo, y puede derivar hacia él sus consultas de lectura pesadas (hot_standby = on) para aliviar el primario. Combinado con pgBackRest para copias de seguridad incrementales diferenciales, alcanza un RPO de unos minutos sin depender de un servicio gestionado.
La documentación oficial
Para la configuración avanzada, las opciones propias de la herramienta y los cambios de versión, consulte la documentación oficial de PostgreSQL. Esta guía cubre la puesta en línea en un VPS ServOrbit; la documentación del editor sigue siendo la referencia para los ajustes finos.