Por qué autoalojar Supabase en un VPS
Supabase no es una caja negra: es un conjunto de servicios de código abierto (PostgreSQL, GoTrue para la autenticación, PostgREST para la API, Realtime, Storage, Kong como gateway) orquestados juntos. La versión cloud factura por proyecto y por usuario activo, y pausa los proyectos gratuitos inactivos. Al autoalojarlo en un VPS, obtiene un backend-as-a-service completo sin esos límites, con acceso directo a su PostgreSQL para las migraciones, las extensiones (pgvector, PostGIS) y el tuning. Es ideal para una agencia que aloja varias aplicaciones de clientes, un SaaS que arranca y quiere controlar sus costes, o cualquier proyecto que exija soberanía de los datos. Usted mismo gestiona las actualizaciones y la copia de seguridad, a cambio de una libertad total.
Los beneficios concretos de un Supabase autoalojado
- Backend completo: base de datos Postgres, Auth, Storage, Realtime y API REST/GraphQL en una sola stack.
- Acceso directo al PostgreSQL subyacente: migraciones SQL, extensiones y políticas RLS sin límite.
- Sin pausas ni facturación por usuario activo mensual.
- Studio incluido: interfaz de administración web para gestionar tablas, auth y buckets.
- Extensiones de IA mediante
pgvectorpara el RAG y la búsqueda semántica, activadas libremente. - Multiproyecto en un mismo VPS: práctico para una agencia o un estudio de desarrollo.
Requisitos de hardware y software
Supabase self-hosted levanta una decena de contenedores (Postgres, Kong, GoTrue, PostgREST, Realtime, Storage, Studio, Meta, Imgproxy...), por lo que es una stack más exigente que una simple base de datos. Cuente con un mínimo de 2 vCPU y 4 GB de RAM para un entorno de pruebas, y más bien 4 vCPU con 8 GB de RAM y 80 GB de SSD para producción. En el plano del software: Ubuntu 22.04/24.04 LTS, Docker y Docker Compose v2, un nombre de dominio que apunte al VPS (por ejemplo api.monsaas.com) para exponer la gateway en HTTPS, y un reverse proxy como Caddy, Traefik o Nginx para gestionar el SSL. Prevea también generar secretos robustos (JWT_SECRET, claves anon y service_role).
Desplegar Supabase self-hosted con Docker
Clonar el repositorio oficial y preparar el entorno
Recupere la carpeta
dockerdel repositorio de Supabase, copie.env.examplea.envy genere después secretos únicos:POSTGRES_PASSWORD,JWT_SECRETy las clavesANON_KEY/SERVICE_ROLE_KEYderivadas del JWT. No despliegue nunca con los valores de ejemplo.Configurar las URLs y la contraseña de Studio
En
.env, definaSITE_URL,API_EXTERNAL_URLySUPABASE_PUBLIC_URLcon su dominio, y proteja Supabase Studio conDASHBOARD_USERNAMEyDASHBOARD_PASSWORD: el Studio da un acceso de administrador total a su proyecto.Lanzar la stack
Arranque con
docker compose up -dy siga después el arranque de los servicios mediantedocker compose ps. La primera inicialización de Postgres y la aplicación de las migraciones internas tardan de uno a dos minutos; compruebe que no haya errores endocker compose logs.Colocar un reverse proxy con SSL
Ponga Caddy o Traefik delante de Kong (el puerto 8000 de la gateway) para exponer su API en HTTPS. Caddy obtiene y renueva automáticamente los certificados Let's Encrypt: basta con un simple bloque
monsaas.com { reverse_proxy localhost:8000 }. No exponga nunca Postgres (5432) públicamente.Activar las políticas RLS
Conéctese al Studio, cree sus tablas, active después Row Level Security en cada una y defina sus policies. Sin RLS, su clave
anonexpone todos sus datos: es el ajuste que hay que hacer antes de exponer nada.Hacer copia de seguridad de Postgres y del Storage
Programe un
pg_dumpdiario de la base de datos y archive el volumen de Storage (buckets de archivos) hacia un almacenamiento externo. Pruebe la restauración completa en un VPS de staging antes de contar con ella en producción.
Supabase vs Appwrite: ¿qué BaaS autoalojado elegir?
Desplace la tabla
| Criterio | Supabase | Appwrite |
|---|---|---|
| Base de datos | PostgreSQL nativo, SQL completo | MariaDB internamente, API de documentos/colecciones |
| Modelo de datos | Relacional, RLS de Postgres | Documentos y colecciones, permisos por regla |
| API autogenerada | REST (PostgREST) + GraphQL | REST, GraphQL y múltiples SDK |
| Autenticación | GoTrue, OAuth, magic links | Auth integrada, OAuth, equipos, JWT |
| Huella de recursos | Más pesada (~10 contenedores) | Moderada, stack más compacta |
| Búsqueda vectorial / IA | Nativa mediante pgvector | No nativa, hay que externalizarla |
| Ideal para | Apps relacionales, RAG, SQL avanzado | Apps móviles/web orientadas a documentos |
| Curva de aprendizaje | Cómoda si conoce SQL | Rápida para desarrolladores front/móvil |
Actualice Supabase con prudencia: como las imágenes están versionadas en el docker-compose.yml, haga siempre un pg_dump completo y un snapshot del VPS antes de un docker compose pull && docker compose up -d. Algunas subidas de versión afectan al esquema interno de los servicios. Para producción, aísle Postgres en un volumen dedicado de alto IOPS y active pgvector desde el principio si prevé búsqueda semántica: añadirlo más tarde impone una migración de esquema.
Despliegue a partir de la stack oficial de Supabase, no de un compose casero
Es tentador escribir un docker-compose mínimo con solo los pocos servicios que necesita. En la práctica, eso se rompe: la imagen supabase/postgres ejecuta su propio script de migración (migrate.sh) que aprovisiona los roles de base (supabase_admin, authenticator, supabase_auth_admin...) y la totalidad del esquema de autenticación, y espera la presencia de los archivos SQL de inicialización de Supabase montados como archivos, con expansión de las variables en tiempo de ejecución. Un compose inline autónomo no puede reproducir eso (Docker Compose interpola las variables dentro de las configuraciones inline, dejando el esquema de autenticación migrado a medias y GoTrue fallando con 'must be owner of function auth.uid()'). El enfoque robusto — el que utiliza ServOrbit — consiste en desplegar los archivos Docker oficiales de Supabase, fijados en una versión concreta, y dejar que su migrate.sh haga el arranque exactamente como lo prevé el upstream.
Haz copias de seguridad automáticas de tu instancia
El despliegue Docker de Supabase no hace ninguna copia de seguridad por sí solo: es la carencia que más señalan quienes lo autoalojan. Se complementan dos mecanismos. El primero, pg_dump, produce una copia lógica completa — lánzalo por cron desde el anfitrión, hacia un volumen distinto del de la base, y conserva varias generaciones. El segundo, el archivado WAL, registra cada transacción y permite volver a un instante preciso en lugar de al último volcado. El primero basta para la mayoría de los proyectos; el segundo se vuelve necesario en cuanto perder un día de escrituras no sea aceptable. En ambos casos, la copia solo vale si ya has restaurado una vez: levanta una instancia virgen y reproduce tu volcado dentro antes de necesitarlo.
Aligerar la pila: el servicio analytics
La composición Docker oficial incluye Logflare, el servicio de analítica interna de Supabase, bajo el nombre analytics. No es imprescindible ni para la API, ni para la autenticación, ni para el almacenamiento: es una herramienta de observabilidad. En un VPS con recursos ajustados es frecuente verlo pasar a estado unhealthy sin que el resto de la pila lo sufra, y muchos autoalojadores acaban comentándolo en su docker-compose.yml. Mide primero lo que consume en tu caso con docker stats antes de decidir: si tu supervisión ya pasa por una herramienta externa, no pierdes nada; si contabas con sus registros, córtalo solo después de haber conectado un sustituto.
Migración Kong→Envoy: qué cambia y a quién le rompe
En la semana del 9 de agosto 2026, Supabase convirtió Envoy en la pasarela de API por defecto de las instalaciones autoalojadas; Kong pasa a ser una capa opcional. Envoy ya estaba disponible desde varias versiones mediante docker-compose.envoy.yml — lo que cambia es el valor por defecto.
En docker-compose.yml el servicio se llama ahora api-gw y el contenedor supabase-envoy, pero se conserva el alias de red kong: los servicios que llaman a la pasarela por ese nombre siguen funcionando. El puerto HTTP sigue siendo 8000, ajustable con API_GW_HTTP_PORT, así que tu proxy inverso Caddy o Nginx no necesita ningún cambio.
⚠️ Supabase califica este cambio de rotura para una PARTE de los autoalojadores, y conviene saber si eres uno. Tres casos: dependías del puerto HTTPS 8443 integrado en Kong — ya no se incluye por defecto, la terminación TLS pasa por docker-compose.caddy.yml o docker-compose.nginx.yml; tenías un volumes/api/kong.yml personalizado — hay que portar rutas y plugins a la configuración de Envoy, que vive en volumes/api/envoy/; o tus scripts designan la pasarela por su nombre de servicio. En los tres casos también puedes quedarte en Kong: sh run.sh config add kong.
Pasar a Envoy sin romper tu pasarela
Averigua sobre qué estás corriendo
Ejecuta
docker compose ps. Un contenedorsupabase-kongsignifica que sigues en Kong;supabase-envoy, que el cambio ya está hecho. Comprueba también sivolumes/api/kong.ymldifiere del del repositorio — ese archivo decide si la migración te cuesta trabajo.Haz copia antes de tocar el compose
Haz un
pg_dumpcompleto y, si tu proveedor lo permite, una instantánea del VPS. Cambiar de pasarela no toca el esquema de PostgreSQL, pero cambia la vía de entrada de todas las peticiones: una vuelta atrás rápida vale más que un diagnóstico en caliente.Decide: portar o quedarte
Si tu
kong.ymles el del repositorio, no hay nada que portar. Si contiene rutas o plugins propios, dos caminos: traducirlos a configuración de Envoy envolumes/api/envoy/, o quedarte en Kong consh run.sh config add kongmientras lo haces. Quedarse es una decisión legítima, no un fracaso.Descarga el nuevo compose y reinicia
Descarga la última versión de la carpeta
dockerdel repositorio oficial de Supabase, luegodocker compose down && docker compose up -d. Comprueba queapi-gwllega ahealthyy que la API responde en el puerto 8000.Restaura el TLS si dependías del 8443 de Kong
El puerto HTTPS integrado ya no se incluye. Añade la terminación TLS con
docker-compose.caddy.ymlodocker-compose.nginx.yml, o deja que tu proxy inverso actual se encargue delante del puerto 8000. Es lo que más se rompe, y solo se ve en la primera llamada HTTPS directa.Comprueba el almacenamiento y las URL firmadas
Prueba una descarga desde un bucket privado con una URL prefirmada. Si obtienes un 403 tras el cambio, mira primero la reescritura de la cabecera
Hosty el valor de la URL pública de tu servicio de almacenamiento: ahí es donde difieren las dos pasarelas.
Kong y Envoy, punto por punto
Desplace la tabla
| Aspecto | Kong (antes de agosto 2026) | Envoy (por defecto desde entonces) |
|---|---|---|
| Servicio en `docker-compose.yml` | `kong` | `api-gw` — se conserva `kong` como alias de red |
| Contenedor | `supabase-kong` | `supabase-envoy` |
| Puerto HTTP | 8000 | 8000 — mediante `API_GW_HTTP_PORT` |
| Puerto HTTPS integrado | 8443 | **eliminado** — TLS con `docker-compose.caddy.yml` / `.nginx.yml` |
| Configuración | `volumes/api/kong.yml` | `volumes/api/envoy/` (YAML versionado) |
| Volver atrás | — | `sh run.sh config add kong` |
CVE-2026-31813: fallo OIDC en GoTrue — actualice
En julio de 2026 se divulgó una vulnerabilidad en GoTrue (el servicio de autenticación de Supabase) bajo la referencia CVE-2026-31813. El fallo está en la validación del claim iss durante la autenticación OIDC: un token JWT firmado por un proveedor de identidad externo (Apple o Azure) pero con un iss distinto del configurado en GoTrue se aceptaba en ciertas condiciones de configuración.
En la práctica, un atacante que controle un proveedor OIDC registrado en la aplicación cliente puede emitir tokens válidos para usuarios arbitrarios de su instancia de Supabase. El alcance real depende de la configuración: solo están afectadas las instancias con al menos un proveedor OAuth externo activado (Social Auth). Las instancias que utilizan únicamente la autenticación por correo/contraseña o los magic links no están expuestas.
La corrección está incluida en Supabase Auth (GoTrue) 2.185.0. Para comprobar su versión: docker compose exec auth gotrue version. Si su versión de gotrue es anterior a 2.185.0, actualice de inmediato.
Actualizar GoTrue para corregir CVE-2026-31813
Identificar la versión en curso
Desde el directorio de su stack Supabase:
docker compose exec auth gotrue version. Si la salida indica una versión < 2.185.0, su instancia está expuesta al CVE-2026-31813. Anote también la versión global de la stack:grep 'SUPABASE_VERSION' .env(si la ha fijado) odocker compose images | grep supabase.Hacer copia de seguridad antes de la actualización
Antes de cualquier actualización, haga una copia de seguridad de la base de datos:
docker compose exec db pg_dumpall -U postgres > /tmp/supabase-backup-$(date +%F).sql. La actualización de GoTrue no implica migración del esquema de PostgreSQL, pero una copia de seguridad previa sigue siendo la regla antes de cualquier cambio de versión en producción.Actualizar Supabase Auth a 2.185.0 o posterior
En su
docker-compose.yml, actualice la etiqueta de la imagensupabase/gotrueav2.185.0o más reciente, o si sigue la stack global, descargue la última versión compatible:docker compose pull && docker compose up -d auth. Actualizar solo GoTrue no obliga a reiniciar los demás servicios. Compruebe condocker compose exec auth gotrue versionque la nueva versión está activa.Comprobar la autenticación OIDC
Tras la actualización, pruebe un flujo de autenticación completo con cada proveedor OIDC configurado : inicio de sesión, cierre de sesión, reconexión. Compruebe en los logs de GoTrue (
docker compose logs auth) que no aparece ningún mensaje de error relativo a la validaciónissen condiciones normales de uso.
Si una actualización inmediata no es posible (se requiere una ventana de mantenimiento), puede reducir la superficie de exposición desactivando temporalmente los proveedores OAuth externos en el Studio de Supabase: Authentication → Providers, y desactive después cada proveedor Social. La autenticación por correo/contraseña sigue funcionando. Esta solución alternativa es temporal: no corrige el fallo, solo reduce la superficie de ataque mientras prepara la actualización.