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.