Cada aplicación de Pampling tiene su propio contenedor PostgreSQL en Coolify, usando la imagen postgres:16-alpine.
Coolify (Docker)
├── app-1 → app-1-postgresql (contenedor dedicado)
├── app-2 → app-2-postgresql (contenedor dedicado)
└── app-3 → app-3-postgresql (contenedor dedicado)
Cada contenedor de BD:
Vía Coolify API:
curl -s -X POST \
-H 'Authorization: Bearer <COOLIFY_TOKEN>' \
-H 'Content-Type: application/json' \
-d '{
"project_uuid": "<COOLIFY_PROJECT>",
"environment_name": "production",
"server_uuid": "p9oujt6wvwz90l3zgzd1vexy",
"name": "mi-app-postgresql",
"postgres_user": "miapp_user",
"postgres_password": "PASSWORD_SEGURO",
"postgres_db": "miapp_db",
"image": "postgres:16-alpine",
"is_public": false
}' \
http://192.168.1.10:8000/api/v1/databases/postgresql
Respuesta:
{
"uuid": "abc123...",
"internal_db_url": "postgres://miapp_user:PASSWORD@abc123...:5432/miapp_db"
}
Arrancar:
curl -s -X POST \
-H 'Authorization: Bearer <COOLIFY_TOKEN>' \
http://192.168.1.10:8000/api/v1/databases/abc123.../start
Dentro de la red Docker de Coolify, los contenedores se comunican usando el UUID como hostname:
postgresql://miapp_user:PASSWORD@UUID_CONTENEDOR:5432/miapp_db
Esta URL se configura como variable de entorno DATABASE_URL en la app de Coolify.
Para conectar desde fuera del servidor, hay que exponer un puerto público:
curl -s -X PATCH \
-H 'Authorization: Bearer <COOLIFY_TOKEN>' \
-H 'Content-Type: application/json' \
-d '{"is_public": true, "public_port": 5433}' \
http://192.168.1.10:8000/api/v1/databases/UUID
Entonces la conexión local sería:
postgresql://miapp_user:PASSWORD@192.168.1.10:5433/miapp_db
Importante: Cada BD pública debe usar un puerto diferente. Comprobar puertos ocupados antes de asignar.
| Acción | Método | Endpoint |
|---|---|---|
| Listar todas | GET | /api/v1/databases |
| Crear PostgreSQL | POST | /api/v1/databases/postgresql |
| Ver detalle | GET | /api/v1/databases/ |
| Modificar | PATCH | /api/v1/databases/ |
| Arrancar | POST | /api/v1/databases/{uuid}/start |
| Parar | POST | /api/v1/databases/{uuid}/stop |
| Borrar | DELETE | /api/v1/databases/ |
Base URL: http://192.168.1.10:8000
Header: Authorization: Bearer <COOLIFY_TOKEN>
import os, psycopg2, psycopg2.extras
DATABASE_URL = os.environ.get("DATABASE_URL", "")
def get_conn():
return psycopg2.connect(DATABASE_URL)
def query(sql, params=None):
conn = get_conn()
try:
cur = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
cur.execute(sql, params)
return [dict(r) for r in cur.fetchall()]
finally:
conn.close()
def query_one(sql, params=None):
rows = query(sql, params)
return rows[0] if rows else None
def execute(sql, params=None):
conn = get_conn()
try:
cur = conn.cursor()
cur.execute(sql, params)
conn.commit()
finally:
conn.close()
Usar siempre
%scomo placeholder (psycopg2 nativo). Nunca f-strings ni concatenación para queries.
← Bitbucket · → Credenciales