Instalación de Supabase Self-Hosted
Supabase es una alternativa de código abierto a Firebase que combina PostgreSQL, autenticación, almacenamiento de archivos, funciones serverless y suscripciones en tiempo real en una sola plataforma. Desplegar Supabase en tu propio servidor con Docker te da control total sobre los datos, sin límites de uso y con la posibilidad de personalizar cada componente. Esta guía cubre la instalación completa de Supabase self-hosted en Linux.
Requisitos Previos
- Ubuntu 20.04/22.04 o Debian 11/12
- Mínimo 4 GB RAM (recomendado 8 GB para producción)
- 20 GB de espacio en disco
- Docker y Docker Compose instalados
- Dominio con SSL (recomendado para producción)
# Instalar Docker si no está instalado
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
# Verificar versiones
docker --version
docker compose version
Instalación con Docker Compose
# Clonar el repositorio oficial de Supabase
git clone --depth 1 https://github.com/supabase/supabase
cd supabase/docker
# Copiar el archivo de entorno de ejemplo
cp .env.example .env
# Generar secretos seguros (imprescindible en producción)
openssl rand -base64 32 # Para POSTGRES_PASSWORD
openssl rand -base64 32 # Para JWT_SECRET
openssl rand -base64 32 # Para DASHBOARD_PASSWORD
Generar tokens JWT
Supabase requiere tokens JWT firmados. Puedes generarlos con Node.js:
# Instalar node si no está disponible
apt-get install -y nodejs npm
# Generar ANON_KEY y SERVICE_ROLE_KEY
node -e "
const jwt = require('jsonwebtoken');
const secret = 'TU_JWT_SECRET_AQUI'; // Mismo que JWT_SECRET en .env
const anonKey = jwt.sign(
{ role: 'anon', iss: 'supabase', iat: Math.floor(Date.now()/1000), exp: Math.floor(Date.now()/1000) + 10*365*24*60*60 },
secret
);
const serviceKey = jwt.sign(
{ role: 'service_role', iss: 'supabase', iat: Math.floor(Date.now()/1000), exp: Math.floor(Date.now()/1000) + 10*365*24*60*60 },
secret
);
console.log('ANON_KEY:', anonKey);
console.log('SERVICE_ROLE_KEY:', serviceKey);
"
Configuración Inicial
Edita el archivo .env con tus valores:
# Editar la configuración
nano .env
Las variables más importantes a configurar:
# .env - Variables principales de Supabase
# Credenciales de la base de datos PostgreSQL
POSTGRES_PASSWORD=tu-password-seguro-aqui
# Secreto JWT (mínimo 32 caracteres, aleatorio)
JWT_SECRET=tu-jwt-secret-muy-largo-y-aleatorio
# Tokens generados con el script anterior
ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
# Contraseña del panel de administración (Studio)
DASHBOARD_USERNAME=supabase
DASHBOARD_PASSWORD=tu-password-del-panel
# URL pública del servidor (cambiar en producción)
SUPABASE_PUBLIC_URL=https://supabase.tudominio.com
# Puerto del Studio (interfaz web)
STUDIO_PORT=3000
# Puerto de la API
KONG_HTTP_PORT=8000
KONG_HTTPS_PORT=8443
# Configuración de SMTP para emails de autenticación
[email protected]
SMTP_HOST=smtp.tudominio.com
SMTP_PORT=587
[email protected]
SMTP_PASS=tu-password-smtp
SMTP_SENDER_NAME=Mi Aplicación
Iniciar los servicios
# Iniciar todos los servicios de Supabase
docker compose up -d
# Ver el progreso del inicio (tarda 1-2 minutos la primera vez)
docker compose logs -f
# Verificar que todos los servicios están corriendo
docker compose ps
# Los servicios principales son:
# - supabase-db (PostgreSQL)
# - supabase-kong (API Gateway)
# - supabase-auth (GoTrue - autenticación)
# - supabase-rest (PostgREST - API REST automática)
# - supabase-realtime (WebSockets)
# - supabase-storage (almacenamiento de archivos)
# - supabase-studio (interfaz web)
Acceder al panel de administración
# El Studio está disponible en:
# http://IP_SERVIDOR:3000 (con las credenciales del .env)
# La API REST está en:
# http://IP_SERVIDOR:8000
# Verificar que la API responde
curl http://localhost:8000/rest/v1/ \
-H "apikey: TU_ANON_KEY" \
-H "Authorization: Bearer TU_ANON_KEY"
Configuración de Autenticación
Supabase Auth (GoTrue) maneja el registro, login y gestión de sesiones:
# Configurar proveedores OAuth en .env
# Google OAuth
GOTRUE_EXTERNAL_GOOGLE_ENABLED=true
GOTRUE_EXTERNAL_GOOGLE_CLIENT_ID=tu-client-id.apps.googleusercontent.com
GOTRUE_EXTERNAL_GOOGLE_SECRET=tu-client-secret
GOTRUE_EXTERNAL_GOOGLE_REDIRECT_URI=https://supabase.tudominio.com/auth/v1/callback
# GitHub OAuth
GOTRUE_EXTERNAL_GITHUB_ENABLED=true
GOTRUE_EXTERNAL_GITHUB_CLIENT_ID=tu-github-client-id
GOTRUE_EXTERNAL_GITHUB_SECRET=tu-github-secret
GOTRUE_EXTERNAL_GITHUB_REDIRECT_URI=https://supabase.tudominio.com/auth/v1/callback
# Configuración de email
GOTRUE_MAILER_AUTOCONFIRM=false # Requerir verificación de email
GOTRUE_MAILER_URLPATHS_INVITE=/auth/v1/verify
GOTRUE_MAILER_URLPATHS_CONFIRMATION=/auth/v1/verify
GOTRUE_MAILER_URLPATHS_RECOVERY=/auth/v1/verify
# Después de cambiar variables, reiniciar el servicio de auth
docker compose restart supabase-auth
# Probar la API de autenticación
curl -X POST http://localhost:8000/auth/v1/signup \
-H "apikey: TU_ANON_KEY" \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]","password":"password123"}'
API y Base de Datos
Acceder directamente a PostgreSQL
# Conectarse a la base de datos
docker exec -it supabase-db psql -U postgres
# O desde fuera del contenedor
psql postgresql://postgres:TU_POSTGRES_PASSWORD@localhost:5432/postgres
# Listar las tablas del esquema público
\dt public.*
# El esquema 'auth' contiene tablas de usuarios
\dt auth.*
# El esquema 'storage' contiene metadatos de archivos
\dt storage.*
Crear tablas y activar Row Level Security
-- Conectarse al Studio o ejecutar SQL directamente
-- Crear una tabla de ejemplo
CREATE TABLE public.articulos (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
titulo TEXT NOT NULL,
contenido TEXT,
autor_id UUID REFERENCES auth.users(id),
creado_en TIMESTAMPTZ DEFAULT NOW()
);
-- Activar Row Level Security (RLS)
ALTER TABLE public.articulos ENABLE ROW LEVEL SECURITY;
-- Política: los usuarios solo pueden ver sus propios artículos
CREATE POLICY "ver_propios_articulos" ON public.articulos
FOR SELECT USING (auth.uid() = autor_id);
-- Política: los usuarios pueden insertar sus propios artículos
CREATE POLICY "insertar_propios_articulos" ON public.articulos
FOR INSERT WITH CHECK (auth.uid() = autor_id);
# La API REST se genera automáticamente para todas las tablas públicas
curl http://localhost:8000/rest/v1/articulos \
-H "apikey: TU_ANON_KEY" \
-H "Authorization: Bearer TOKEN_DEL_USUARIO"
Storage y Funciones Edge
Configurar almacenamiento de archivos
# El storage de Supabase almacena archivos en el sistema de archivos local
# Configuración en .env:
STORAGE_BACKEND=file
FILE_STORAGE_BACKEND_PATH=/var/lib/storage
# Para usar S3 como backend:
STORAGE_BACKEND=s3
GLOBAL_S3_BUCKET=mi-bucket-supabase
GLOBAL_S3_ENDPOINT=https://s3.amazonaws.com
GLOBAL_S3_REGION=us-east-1
AWS_ACCESS_KEY_ID=tu-access-key
AWS_SECRET_ACCESS_KEY=tu-secret-key
# Crear un bucket de storage desde la API
curl -X POST http://localhost:8000/storage/v1/bucket \
-H "apikey: TU_SERVICE_ROLE_KEY" \
-H "Authorization: Bearer TU_SERVICE_ROLE_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"imagenes","public":true}'
# Subir un archivo al bucket
curl -X POST http://localhost:8000/storage/v1/object/imagenes/foto.jpg \
-H "apikey: TU_ANON_KEY" \
-H "Authorization: Bearer TOKEN_USUARIO" \
-H "Content-Type: image/jpeg" \
--data-binary @foto.jpg
Suscripciones en tiempo real
# Habilitar Realtime para una tabla (en SQL)
# Las tablas deben estar en la publicación de replicación
# Verificar que Realtime está configurado
docker logs supabase-realtime --tail=20
# Probar conexión WebSocket (requiere wscat)
npm install -g wscat
wscat -c "ws://localhost:8000/realtime/v1/websocket?apikey=TU_ANON_KEY&vsn=1.0.0"
Exposición con Proxy Inverso
Para producción, expón Supabase detrás de Nginx con SSL:
# /etc/nginx/sites-available/supabase
server {
listen 80;
server_name supabase.tudominio.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name supabase.tudominio.com;
ssl_certificate /etc/letsencrypt/live/supabase.tudominio.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/supabase.tudominio.com/privkey.pem;
# Panel de administración Studio
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# API Gateway Kong
location /rest/v1/ {
proxy_pass http://localhost:8000/rest/v1/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# Autenticación
location /auth/v1/ {
proxy_pass http://localhost:8000/auth/v1/;
proxy_set_header Host $host;
}
# Storage
location /storage/v1/ {
proxy_pass http://localhost:8000/storage/v1/;
proxy_set_header Host $host;
client_max_body_size 50m;
}
# Realtime WebSocket
location /realtime/v1/ {
proxy_pass http://localhost:8000/realtime/v1/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
# Habilitar el sitio y obtener certificado SSL
ln -s /etc/nginx/sites-available/supabase /etc/nginx/sites-enabled/
nginx -t
systemctl reload nginx
# Obtener certificado Let's Encrypt
certbot --nginx -d supabase.tudominio.com
Solución de Problemas
Los servicios no arrancan
# Ver logs de todos los servicios
cd ~/supabase/docker
docker compose logs --tail=50
# Ver logs de un servicio específico
docker compose logs supabase-db --tail=50
docker compose logs supabase-kong --tail=50
# Verificar el estado
docker compose ps
Error de conexión a la base de datos
# Verificar que PostgreSQL está corriendo
docker compose ps supabase-db
# Verificar la contraseña en .env
grep POSTGRES_PASSWORD .env
# Probar conexión directa
docker exec -it supabase-db psql -U postgres -c "\l"
La autenticación no envía emails
# Verificar configuración SMTP en .env
# En desarrollo, usar GOTRUE_MAILER_AUTOCONFIRM=true para evitar emails
# Ver logs del servicio de auth
docker compose logs supabase-auth | grep -i "mail\|smtp\|error"
Problemas con JWT inválido
# Verificar que ANON_KEY y SERVICE_ROLE_KEY fueron generados con el mismo JWT_SECRET
# Si cambias JWT_SECRET, debes regenerar ambas claves
# Verificar el token en jwt.io (solo en desarrollo)
echo "TU_ANON_KEY" | base64 -d 2>/dev/null
Conclusión
Supabase self-hosted proporciona una plataforma backend completa y lista para producción que combina PostgreSQL, autenticación OAuth, almacenamiento de archivos y suscripciones en tiempo real. Aunque la configuración inicial requiere más trabajo que usar el servicio cloud, el control total sobre los datos, la ausencia de límites de uso y la posibilidad de personalizar cada componente hacen que valga la pena para aplicaciones con requisitos de privacidad o grandes volúmenes de datos.


