Qué instalas realmente
Supabase no es un programa: es un conjunto de servicios de código abierto coordinados alrededor de una base PostgreSQL. El despliegue con Docker levanta más de una docena de contenedores:
- PostgreSQL: la base de datos. Todo lo demás gira a su alrededor.
- Kong: la puerta de entrada. Recibe las peticiones en el puerto 8000 y las enruta.
- GoTrue (auth): registro, inicio de sesión, enlaces mágicos y proveedores externos.
- PostgREST: convierte tus tablas en una API REST automática.
- Realtime: envía cambios de la base por WebSocket.
- Storage: archivos, con una API compatible con S3.
- Studio: el panel gráfico donde escribes SQL y gestionas tablas.
- Analytics, Meta, Imgproxy y funciones Edge: servicios de apoyo.
Todos comparten el mismo VPS. Por eso los requisitos no son los de "una base de datos pequeña".
Requisitos y cuándo conviene
La documentación oficial pide un mínimo de 4 GB de RAM, 2 núcleos y 40 GB de disco SSD, y recomienda 8 GB o más, 4 núcleos y 80 GB. No son cifras infladas: con 2 GB los contenedores arrancan y luego el sistema empieza a matar procesos por falta de memoria.
| Escenario | RAM | vCPU | Disco |
|---|---|---|---|
| Desarrollo y pruebas | 4 GB | 2 | 40 GB |
| Aplicación en producción pequeña | 8 GB | 4 | 80 GB |
| Producción con Storage intensivo | 16 GB | 8 | 150 GB o más |
Autoalojar tiene sentido si ya administras servidores, si tu política exige que los datos permanezcan bajo tu control, o si necesitas extensiones de PostgreSQL que la nube no habilita. No tiene sentido si el equipo no tiene a nadie que responda a las tres de la mañana cuando PostgreSQL no arranca: los 25 dólares mensuales del plan Pro de Supabase Cloud compran backups automáticos, monitoreo y soporte que aquí tendrás que construir tú.
Comprueba el servidor antes de empezar y activa swap si vas justo, como explica la guía de configurar swap en Ubuntu:
free -h
nproc
df -h /
docker --version
docker compose version Descargar y preparar el despliegue
El método oficial clona el repositorio en una rama fijada de autoalojamiento y copia solo la carpeta docker. Fijar la versión importa: seguir master significa despertar un día con un cambio incompatible.
git clone --depth 1 --branch self-hosted/v0.8.0 https://github.com/supabase/supabase
mkdir supabase-project
cp -rf supabase/docker/. supabase-project
cd supabase-project
cp .env.example .env
printf 'ref=self-hosted/v0.8.0\n' > .supabase-version Existe también un instalador rápido, curl -fsSL https://supabase.link/setup.sh | sh, que hace lo mismo de forma guiada en Linux. Si lo usas, revisa el script antes: canalizarlo a sh ejecuta código descargado con tus privilegios.
Cambiar todas las credenciales por defecto
El archivo .env.example trae claves públicas y conocidas: un despliegue que arranque con ellas queda comprometido desde el primer minuto. Este es el paso que más se salta y el que más incidentes causa.
Hay que cambiar, como mínimo:
| Variable | Qué es | Riesgo si la dejas por defecto |
|---|---|---|
POSTGRES_PASSWORD | Contraseña de la base | Acceso total a los datos |
JWT_SECRET | Firma todos los tokens | Cualquiera emite tokens válidos |
ANON_KEY | Clave pública del cliente | Acceso con rol anon |
SERVICE_ROLE_KEY | Clave del servidor | Ignora la seguridad por fila |
DASHBOARD_USERNAME | Usuario del panel | Acceso al Studio |
DASHBOARD_PASSWORD | Contraseña del panel | Acceso al Studio |
SECRET_KEY_BASE | Cifrado de Realtime | Sesiones manipulables |
VAULT_ENC_KEY | Cifrado de secretos | Secretos legibles |
Genera valores fuertes:
openssl rand -base64 48 # POSTGRES_PASSWORD
openssl rand -hex 32 # JWT_SECRET (mínimo 32 caracteres)
openssl rand -base64 64 # SECRET_KEY_BASE ANON_KEY y SERVICE_ROLE_KEY no son cadenas aleatorias: son tokens JWT firmados con tu JWT_SECRET, con los roles anon y service_role respectivamente. La documentación de autoalojamiento incluye un generador para producirlos a partir de tu secreto. Si generas el secreto pero conservas las claves de ejemplo, nada funcionará: las firmas no coincidirán.
Define también la URL pública, porque el panel y los enlaces de correo la usan:
SUPABASE_PUBLIC_URL=https://api.ejemplo.com
API_EXTERNAL_URL=https://api.ejemplo.com
SITE_URL=https://app.ejemplo.com Levantar los servicios
docker compose pull
docker compose up -d
docker compose ps La primera arrancada tarda varios minutos porque descarga imágenes y ejecuta migraciones. Verifica que todos los contenedores estén healthy, no solo running:
docker compose ps --format 'table {{.Name}}\t{{.Status}}'
docker compose logs --tail=50 db
docker compose logs --tail=50 auth El Studio queda disponible en el puerto 8000, protegido con autenticación básica usando DASHBOARD_USERNAME y DASHBOARD_PASSWORD. Ese mismo puerto sirve la API a través de Kong.
Un error frecuente: si un contenedor reinicia en bucle, casi siempre es una variable de .env mal formada o una clave JWT que no coincide con el secreto. Léelo en los logs antes de tocar el volumen de datos.
Publicar con dominio propio y HTTPS
Nunca expongas el puerto 8000 directamente a internet: pon Nginx delante con TLS. Ajusta primero el mapeo de puertos para que Kong solo escuche en local, editando docker-compose.yml:
kong:
ports:
- "127.0.0.1:8000:8000/tcp" Y configura el proxy:
server {
listen 443 ssl;
server_name api.ejemplo.com;
client_max_body_size 50M;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
} Las cabeceras Upgrade y Connection no son opcionales: sin ellas, Realtime no establece el WebSocket y las suscripciones en vivo quedan mudas sin dar error claro.
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d api.ejemplo.com client_max_body_size debe cubrir el archivo más grande que subas a Storage; el valor por defecto de Nginx (1 MB) rechaza cualquier imagen decente con un error 413.
Configurar el correo
El servicio de autenticación necesita SMTP propio para enviar confirmaciones, enlaces mágicos y recuperación de contraseña. El despliegue autoalojado no trae un remitente listo para producción; sin SMTP, los registros que requieran confirmación simplemente no llegan.
SMTP_HOST=smtp.tuproveedor.com
SMTP_PORT=587
[email protected]
SMTP_PASS=CLAVE
SMTP_SENDER_NAME=Ejemplo
[email protected] Usa un servicio de envío transaccional real y configura SPF, DKIM y DMARC en el dominio. Mandar correo de autenticación desde la IP de un VPS recién creado termina en la carpeta de spam; la guía sobre por qué el correo cae en spam explica los registros necesarios.
Migrar una aplicación desde Supabase Cloud
La migración tiene tres partes: base de datos, archivos de Storage y claves de la aplicación. El orden importa.
Exporta la base incluyendo roles y el esquema de autenticación, que es donde viven los usuarios:
pg_dump "postgresql://postgres:[email protected]:5432/postgres" \
--schema=public --schema=auth --schema=storage \
--no-owner --no-privileges \
-f volcado.sql Restaura en el nuevo servidor:
docker compose exec -T db psql -U postgres -d postgres < volcado.sql Los archivos de Storage se descargan aparte con la CLI de Supabase o con cualquier cliente S3 apuntando al endpoint del proyecto. No asumas que el volcado SQL los incluye: la base guarda los metadatos, no el contenido de los archivos.
Por último, en tu aplicación cambia la URL del proyecto y la clave anónima:
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(
'https://api.ejemplo.com',
process.env.SUPABASE_ANON_KEY
) Verifica después de migrar: inicia sesión con un usuario existente, sube un archivo, escucha un cambio en tiempo real y comprueba que las políticas de seguridad por fila siguen bloqueando lo que deben. Una migración que "termina sin errores" pero deja la seguridad por fila desactivada expone toda la base a la clave anónima, que está en el navegador de cualquiera.
Backups: aquí no hay red de seguridad
Supabase Cloud hace copias automáticas; tu VPS no hace nada hasta que tú lo programes. Es la diferencia operativa más importante entre los dos modelos.
docker compose exec -T db pg_dumpall -U postgres | gzip > /var/backups/supabase-$(date +%F).sql.gz
tar czf /var/backups/storage-$(date +%F).tar.gz ./volumes/storage Programa ambos con cron, envíalos fuera del servidor y prueba la restauración en otro VPS. La guía de backups en VPS cubre la rotación y el traslado remoto.
Añade monitoreo del espacio en disco. PostgreSQL con el disco lleno deja de aceptar escrituras, y los servicios de análisis de Supabase generan volumen de registros que sorprende:
df -h /
docker system df
docker compose exec db psql -U postgres -c "SELECT pg_size_pretty(pg_database_size('postgres'));" Autoalojado frente a la nube: tabla honesta
| Función | Supabase autoalojado | Supabase Cloud |
|---|---|---|
| Coste mensual | El del VPS | Gratis limitado o desde 25 USD |
| Backups automáticos | Los programas tú | Incluidos, con punto en el tiempo |
| Réplicas de lectura | No, salvo que las montes | Disponibles en planes superiores |
| Ramas de base de datos | No | Sí |
| Actualizaciones | Manuales | Gestionadas |
| Acceso directo a PostgreSQL | Total, con superusuario | Limitado |
| Extensiones de Postgres | Las que instales | Lista aprobada |
| Soporte | Comunidad | Según plan |
| Dónde viven los datos | Tu servidor | Infraestructura de Supabase |
Autoalojar Supabase es viable y no es complicado: clonar la rama fijada, cambiar todas las claves del .env, poner Nginx con TLS delante de Kong y configurar SMTP. Lo que hay que aceptar es la parte que la nube resolvía en silencio: los backups los programas tú, las actualizaciones las decides tú, y si PostgreSQL no arranca un domingo, el soporte eres tú. Con 8 GB de RAM, un volcado diario probado y monitoreo de disco, un Supabase propio sostiene una aplicación en producción sin sobresaltos.
Terranode ofrece VPS KVM con NVMe en Ecuador desde $2,99 al mes; para Supabase el punto de partida realista es el plan de 8 GB de RAM y 80 GB de disco por $18,50, que cubre con holgura los requisitos recomendados para auto-alojar la plataforma completa.
Hosting con LiteSpeed, NVMe y soporte 24/7 desde $3/mes.