Con Supabase Docker Compose levantas en tu servidor lo mismo que ofrece el servicio de pago: PostgreSQL, autenticación con OAuth, API REST generada sola, almacenamiento de ficheros, suscripciones en tiempo real y un panel de administración. Todo tuyo, sin límite de filas ni proyectos que se pausan por inactividad.
Aviso desde el principio: esto no es un contenedor, son unos diez servicios coordinados. Pide bastante más máquina que la mayoría de tutoriales de este blog, y la configuración inicial tiene trampas de seguridad muy serias.
Al terminar este artículo tendrás
- La pila completa funcionando con claves generadas de verdad.
- El panel Studio protegido y accesible por HTTPS.
- Row Level Security entendido, que es lo que separa un despliegue seguro de un desastre.
- Una estrategia de copias y de actualización que no te rompa el proyecto.
Qué incluye realmente Supabase Docker Compose
Supabase Docker Compose se despliega como alternativa libre a Firebase, pero la comparación se queda corta en un punto clave: por debajo hay un PostgreSQL normal y corriente. No es una base de datos propietaria con su propio dialecto, es Postgres. Puedes conectarte con psql, migrar a otro sitio cuando quieras y usar todo lo que ya sabes.
Lo que aporta la plataforma es la capa de servicios alrededor.
| Servicio | Qué hace |
|---|---|
| PostgREST | Genera una API REST completa leyendo el esquema de tu base de datos. |
| GoTrue | Registro, inicio de sesión, OAuth con terceros y gestión de JWT. |
| Realtime | Envía cambios de la base de datos a los clientes por WebSocket. |
| Storage | Ficheros con permisos ligados a las mismas reglas de la base. |
| Kong | Pasarela que expone todo en un único puerto. |
| Studio | Panel web para tablas, consultas, usuarios y registros. |
Esa pieza de PostgREST es la que más impresiona la primera vez: creas una tabla y ya tienes endpoints con filtros, paginación y ordenación sin escribir una línea de backend.
Requisitos previos para Supabase Docker Compose
| Recurso | Mínimo | Recomendado |
|---|---|---|
| RAM | 4 GB | 8 GB |
| CPU | 2 núcleos | 4 núcleos |
| Disco | 20 GB | 100 GB SSD |
| Docker Engine | 24.x | Última estable |
Supabase Docker Compose con 2 GB de RAM arranca, pero los servicios empiezan a morir por falta de memoria en cuanto le das uso. Si vienes de tutoriales ligeros como PostgreSQL en solitario con Docker Compose, asume que aquí multiplicas el consumo por cinco: estás levantando una plataforma entera, no una base de datos.
Instalar Supabase Docker Compose paso a paso
Paso 1: descargar la configuración
El proyecto mantiene el despliegue de Supabase Docker Compose en su propio repositorio. Se clona en superficial, fijando la versión autoalojada, y se copia solo el directorio que interesa.
git clone --depth 1 --branch self-hosted/v0.7.2 https://github.com/supabase/supabase
mkdir mi-supabase
cp -rf supabase/docker/. mi-supabase
cd mi-supabase
cp .env.example .env
Fijar la rama es importante: apuntar a la rama principal te expone a cambios sin previo aviso en un despliegue que quieres estable.
Paso 2: generar las claves
Este es el paso crítico de Supabase Docker Compose y el que más gente se salta. El fichero .env.example trae claves de ejemplo que son públicas y están en GitHub: cualquiera que conozca el proyecto puede firmar tokens válidos contra tu instancia.
sh utils/generate-keys.sh
El script genera el JWT_SECRET y, a partir de él, las dos claves de API. Si prefieres hacerlo a mano, estos son los valores que no puedes dejar por defecto bajo ningún concepto.
| Variable | Para qué |
|---|---|
POSTGRES_PASSWORD | Contraseña de la base. Solo letras y números para evitar problemas de escapado. |
JWT_SECRET | Firma todos los tokens. Mínimo 40 caracteres aleatorios. |
ANON_KEY | Clave pública, va en el navegador. Deriva del JWT_SECRET. |
SERVICE_ROLE_KEY | Clave con permisos totales. Jamás en el cliente. |
DASHBOARD_USERNAME | Usuario del panel Studio. |
DASHBOARD_PASSWORD | Contraseña del panel Studio. |
Advertencia: la clave de servicio
SERVICE_ROLE_KEY se salta todas las reglas de seguridad de la base de datos por diseño. Si acaba en el código de una aplicación web o móvil, cualquiera puede leer y borrar cualquier tabla. Úsala solo en servidores que controles, y nunca la publiques en un repositorio.
Paso 3: levantar la pila
Descarga primero las imágenes de Supabase Docker Compose: son bastantes gigas y conviene separarlo del arranque para ver los fallos con claridad.
docker compose pull
docker compose up -d
docker compose ps
Todos los servicios deben aparecer como healthy. El primer arranque tarda un par de minutos porque la base de datos ejecuta las migraciones iniciales. Si alguno se queda reiniciándose, mira sus registros antes de tocar nada.
docker compose logs -f db
docker compose logs -f auth
Con todo arriba, el panel está en http://tu-servidor:8000 y te pedirá el usuario y contraseña del panel. Las APIs cuelgan del mismo puerto en /rest/v1/, /auth/v1/, /storage/v1/ y /realtime/v1/.
Paso 4: ponerlo detrás de HTTPS
El puerto 8000 de Supabase Docker Compose en claro no vale para producción, y menos si vas a usar proveedores OAuth, que exigen URL de retorno con TLS. Con Traefik como proxy inverso basta con enrutar hacia Kong.
labels:
- "traefik.enable=true"
- "traefik.http.routers.supabase.rule=Host(`api.midominio.es`)"
- "traefik.http.routers.supabase.entrypoints=websecure"
- "traefik.http.routers.supabase.tls.certresolver=letsencrypt"
- "traefik.http.services.supabase.loadbalancer.server.port=8000"
Después actualiza API_EXTERNAL_URL y SUPABASE_PUBLIC_URL en el .env con la URL definitiva; si no, los enlaces de confirmación por correo saldrán apuntando a la IP interna. También sirve Nginx Proxy Manager si prefieres interfaz gráfica.
Row Level Security en Supabase Docker Compose
Aquí está el concepto que decide si tu Supabase Docker Compose es seguro. Como PostgREST expone automáticamente todas las tablas, la protección no vive en el backend —no hay backend— sino en la propia base de datos, mediante políticas de fila.
Una tabla sin RLS activado y accesible con la clave pública es una tabla que puede leer, modificar y borrar cualquiera que abra las herramientas de desarrollo del navegador. Actívalo siempre y define las políticas explícitamente.
alter table public.notas enable row level security;
create policy "Cada usuario ve sus notas"
on public.notas for select
using ( auth.uid() = usuario_id );
create policy "Cada usuario crea sus notas"
on public.notas for insert
with check ( auth.uid() = usuario_id );
La función auth.uid() devuelve el identificador del usuario que viene en el token. Sin política que la contemple, el acceso queda denegado por defecto, que es exactamente el comportamiento que quieres. Tienes el detalle en la documentación de Row Level Security.
Conectar tu aplicación a Supabase Docker Compose
La biblioteca cliente es la misma que usarías con el servicio gestionado; lo único que cambia es la URL y la clave. Ese detalle es importante porque significa que puedes empezar en la nube y migrar a tu servidor sin reescribir la aplicación.
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(
'https://api.midominio.es',
'TU_ANON_KEY'
)
// Registro de usuario
const { data, error } = await supabase.auth.signUp({
email: 'usuario@ejemplo.es',
password: 'una-contrasena-larga'
})
// Consulta respetando las politicas de fila
const { data: notas } = await supabase
.from('notas')
.select('id, titulo, creada_en')
.order('creada_en', { ascending: false })
.limit(20)
Fíjate en que la consulta no lleva ningún filtro por usuario: no hace falta, porque la política de fila ya lo aplica en el servidor. Si un atacante manipula esa llamada desde el navegador para pedir las notas de otro, la base de datos simplemente no se las devuelve. Ese es el modelo mental que hay que interiorizar al trabajar con Supabase Docker Compose.
Para las suscripciones en tiempo real, el cliente abre un WebSocket contra el mismo dominio. Si tu proxy inverso no permite la actualización de protocolo, las suscripciones fallarán en silencio mientras el resto de la API funciona con normalidad: es un fallo desconcertante y muy típico de los despliegues detrás de proxy.
Copias y actualizaciones de Supabase Docker Compose
La copia de seguridad de Supabase Docker Compose tiene dos piezas: el volcado de la base y el directorio de ficheros del servicio de almacenamiento.
docker compose exec -T db pg_dumpall -U postgres | gzip > supabase-$(date +%F).sql.gz
tar czf storage-$(date +%F).tar.gz ./volumes/storage
Usa pg_dumpall y no pg_dump: hay varios esquemas y roles propios de la plataforma que un volcado de una sola base se deja fuera. Automatízalo con Duplicati para copias cifradas si quieres enviarlo fuera del servidor.
Sobre las actualizaciones de Supabase Docker Compose, sé conservador. Actualizar la versión autoalojada implica revisar los cambios del .env.example y a veces migraciones manuales. Haz copia, lee las notas de la versión y prueba en otra máquina antes de tocar la buena.
Qué te falta respecto al servicio gestionado
- Copias automáticas y recuperación a un punto en el tiempo. Aquí las montas tú.
- Escalado y réplicas de lectura. No vienen dados.
- Envío de correo. Debes configurar tu propio SMTP o los registros no se confirmarán nunca.
- Algunas funciones nuevas tardan en llegar a la versión autoalojada.
Lo del correo pilla a todo el mundo: sin SMTP configurado, los usuarios se registran pero jamás reciben el enlace de confirmación y parece que la autenticación está rota. Mientras montas el proyecto puedes desactivar la confirmación obligatoria por correo y activarla más tarde, cuando tengas un servidor de envío en condiciones; así avanzas sin quedarte bloqueado por un detalle de infraestructura que no es urgente todavía.
Problemas frecuentes con Supabase Docker Compose
| Síntoma | Causa | Solución |
|---|---|---|
| Servicios reiniciándose | Falta memoria | Subir a 4 GB o más |
Invalid API key | Claves no regeneradas | Ejecutar generate-keys.sh |
| Enlaces de correo con IP | API_EXTERNAL_URL sin cambiar | Poner la URL pública |
| El registro no confirma | Sin SMTP | Configurar servidor de correo |
| Tablas visibles para todos | RLS desactivado | Activar políticas por tabla |
El último no da error: funciona «bien» y por eso es tan peligroso. Antes de exponer nada, entra en Studio y comprueba tabla por tabla que RLS está activo.
Hay una comprobación de treinta segundos que deberías hacer siempre antes de dar por buena la instalación: pedir datos con la clave pública desde fuera, sin haber iniciado sesión. Si te devuelve filas, tienes una tabla abierta al mundo.
curl "https://api.midominio.es/rest/v1/notas?select=*" \
-H "apikey: TU_ANON_KEY"
La respuesta correcta es una lista vacía. Repítelo con cada tabla nueva que crees, porque RLS se activa por tabla y es muy fácil olvidarse justo en la que guarda los datos sensibles.
Conclusión sobre Supabase Docker Compose
Supabase Docker Compose es de los despliegues más ambiciosos que puedes montar con un solo fichero, y también de los que más respeto merecen. La instalación es sencilla; lo que separa un proyecto sólido de un incidente son las claves regeneradas y las políticas de fila bien puestas.
Mi consejo con Supabase Docker Compose es empezar en una máquina de pruebas, crear una tabla, activar RLS y comprobar desde el navegador que sin token no ves nada. Cuando ese circuito te quede claro, ya puedes construir encima con tranquilidad. Tienes la guía oficial en la documentación de autoalojamiento con Docker, el código en el repositorio del proyecto, la referencia de identidad en la guía de autenticación y la base de todo en la documentación de PostgreSQL. Más ideas, en los tutoriales de Docker Compose.
Preguntas frecuentes sobre Supabase Docker Compose
¿Puedo migrar mi proyecto del servicio en la nube?
Sí. Se exporta con pg_dump desde el proyecto gestionado y se restaura en tu instancia. Los ficheros de almacenamiento se copian aparte, y las claves de API cambian, así que tendrás que actualizarlas en tus aplicaciones.
¿Funciona en una Raspberry Pi?
En una Pi 4 de 8 GB arranca y sirve para trastear, pero va justo y no todas las imágenes tienen la misma madurez en arm64. Para algo serio, un mini PC x86 con 8 GB rinde muchísimo mejor por poco más dinero.
¿Puedo usar solo la base de datos y la API?
Puedes comentar servicios que no uses, como Realtime o Storage, y ahorrarás memoria. Ten cuidado con Kong y con el servicio de autenticación: casi todo lo demás depende de ellos para funcionar.
¿Qué pasa si pierdo el JWT_SECRET?
Todos los tokens emitidos dejan de validar y las claves derivadas quedan inservibles. Los datos siguen intactos en Postgres, pero tendrás que generar claves nuevas y actualizarlas en cada aplicación cliente. Guárdalo con el mismo cuidado que una contraseña de base de datos.
¿Es realmente gratis?
El software es libre y no hay cuotas ni límites artificiales. Pagas el servidor, y sobre todo el tiempo de mantenerlo: copias, actualizaciones y vigilancia corren de tu cuenta. Para un proyecto pequeño con tráfico previsible sale muy a cuenta.
