10 KiB
Ruleta - Aplicación Next.js
Aplicación web personalizada construida con Next.js.
📋 Descripción
Este stack despliega una aplicación Next.js con:
- Dos rutas de acceso: subdominio y path
- Integración con Traefik para HTTPS
- Soporte para múltiples dominios
- Configuración opcional de Authentik (SSO)
🚀 Despliegue
Prerequisitos
- Red Docker: Asegúrate de que la red
proxyexiste - Registros DNS: Configura los registros A para tus dominios
- Imagen Docker: La aplicación debe estar construida como imagen Docker
Desde Portainer
- Ve a Stacks → Add stack
- Nombre:
ruleta - Selecciona Repository o Git repository
- Configura:
- Repository URL:
<tu-repositorio> - Repository reference:
main - Compose path:
ruleta/docker-compose.yml
- Repository URL:
- Carga el archivo de variables de entorno:
ruleta/stack.env - Haz clic en Deploy the stack
Variables de Entorno
Edita el archivo stack.env:
# Imagen de la aplicación (construida previamente)
RULETA_IMAGE=tu-usuario/ruleta:latest
# Entorno de Node.js
RULETA_NODE_ENV=production
RULETA_NEXT_TELEMETRY_DISABLED=1
# Puerto interno de Next.js
RULETA_APP_PORT=3000
# Dominios
# Opción 1: Subdominio dedicado
RULETA_SUBDOMAIN=ruleta.tudominio.com
# Opción 2: Path en dominio principal
RULETA_MAIN_DOMAIN=tudominio.com
# Traefik
TRAEFIK_DOCKER_NETWORK=proxy
TRAEFIK_ENTRYPOINT_SECURE=websecure
TRAEFIK_CERTRESOLVER=letsencrypt
# Si usas Supabase, descomenta y configura:
# NEXT_PUBLIC_SUPABASE_URL=https://tu-proyecto.supabase.co
# NEXT_PUBLIC_SUPABASE_ANON_KEY=tu-clave-publica
# SUPABASE_SERVICE_ROLE_KEY=tu-clave-privada
⚙️ Rutas de Acceso
Esta aplicación tiene dos formas de acceso configuradas:
1. Subdominio Dedicado
Accede mediante: https://ruleta.tudominio.com
- URL completa del subdominio
- Next.js recibe las peticiones en el path raíz
/ - No requiere configuración especial en Next.js
2. Path en Dominio Principal
Accede mediante: https://tudominio.com/ruleta
- Path dentro del dominio principal
- Traefik elimina el prefijo
/ruletaantes de enviar a Next.js - Next.js recibe las peticiones como si estuvieran en
/
Nota: Puedes usar ambas rutas simultáneamente o deshabilitar una editando el
docker-compose.yml.
🔧 Configuración de Next.js
Configurar basePath (si usas path)
Si quieres que Next.js sea consciente del path /ruleta, edita next.config.js:
/** @type {import('next').NextConfig} */
const nextConfig = {
basePath: '/ruleta',
assetPrefix: '/ruleta',
// ... otras opciones
}
module.exports = nextConfig
Nota: Con la configuración actual (middleware de stripprefix en Traefik), esto NO es necesario. Traefik se encarga de eliminar el prefijo.
Variables de Entorno en Next.js
Para exponer variables al cliente (navegador):
// next.config.js
module.exports = {
env: {
CUSTOM_VAR: process.env.CUSTOM_VAR,
},
// o usa NEXT_PUBLIC_ prefix
}
En stack.env:
NEXT_PUBLIC_API_URL=https://api.tudominio.com
CUSTOM_VAR=valor-personalizado
🔒 Proteger con Authentik (Opcional)
Por defecto, la aplicación NO está protegida con SSO. Para protegerla:
Opción 1: Proteger Todo
Edita el docker-compose.yml y descomenta:
labels:
# Para subdominio
traefik.http.routers.ruleta-sub.middlewares: "ths-authentik@docker"
# Para path (requiere cadena de middlewares)
traefik.http.routers.ruleta-path.middlewares: "ths-authentik@docker,ruleta-strip@docker"
Opción 2: Proteger Solo Ciertas Rutas
Crea routers adicionales en Traefik:
# Router para rutas públicas
traefik.http.routers.ruleta-public.rule: "Host(`ruleta.tudominio.com`) && PathPrefix(`/api`, `/public`)"
traefik.http.routers.ruleta-public.priority: "20"
# Router para rutas protegidas
traefik.http.routers.ruleta-private.rule: "Host(`ruleta.tudominio.com`) && PathPrefix(`/admin`)"
traefik.http.routers.ruleta-private.middlewares: "ths-authentik@docker"
traefik.http.routers.ruleta-private.priority: "30"
🏗️ Construir la Imagen Docker
Dockerfile de Ejemplo
# Build stage
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Production stage
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
# Copiar archivos necesarios
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
EXPOSE 3000
CMD ["node", "server.js"]
next.config.js para Standalone
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'standalone',
// ... otras opciones
}
module.exports = nextConfig
Construir y Publicar
# Construir
docker build -t tu-usuario/ruleta:latest .
# Probar localmente
docker run -p 3000:3000 tu-usuario/ruleta:latest
# Publicar en Docker Hub
docker push tu-usuario/ruleta:latest
# O publicar en GitHub Container Registry
docker tag tu-usuario/ruleta:latest ghcr.io/tu-usuario/ruleta:latest
docker push ghcr.io/tu-usuario/ruleta:latest
🔧 Configuración Avanzada
Integración con Supabase
Si tu aplicación usa Supabase:
-
Crea un proyecto en supabase.com
-
Obtén las credenciales:
- URL del proyecto: Settings → API → Project URL
- Anon key: Settings → API → anon public
- Service role key: Settings → API → service_role (secreto)
-
Añade a
stack.env:NEXT_PUBLIC_SUPABASE_URL=https://tu-proyecto.supabase.co NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbG... SUPABASE_SERVICE_ROLE_KEY=eyJhbG... -
En tu código Next.js:
import { createClient } from '@supabase/supabase-js' const supabase = createClient( process.env.NEXT_PUBLIC_SUPABASE_URL, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY )
Variables de Entorno Sensibles
Para secrets (API keys, tokens):
-
No las incluyas en
stack.envsi el repositorio es público -
Configúralas manualmente en Portainer:
- Edita el stack
- Ve a la pestaña Environment variables
- Añade variables adicionales
-
O usa Docker secrets:
services: app: secrets: - api_key secrets: api_key: external: true
Volúmenes para Datos Persistentes
Si necesitas persistir datos (uploads, cache):
services:
app:
volumes:
- ${RULETA_DATA_PATH}:/app/data:Z
- ${RULETA_UPLOADS_PATH}:/app/public/uploads:Z
Añade a stack.env:
RULETA_DATA_PATH=/opt/ruleta/data
RULETA_UPLOADS_PATH=/opt/ruleta/uploads
🛠️ Troubleshooting
La aplicación no inicia
-
Verifica los logs:
docker logs ruleta-app -
Verifica que la imagen existe:
docker images | grep ruleta -
Verifica variables de entorno:
docker inspect ruleta-app | grep -A 20 Env
No puedo acceder por dominio
-
Verifica DNS:
nslookup ruleta.tudominio.com -
Verifica Traefik:
docker logs traefik | grep ruleta -
Verifica labels de Traefik:
docker inspect ruleta-app | grep -A 30 Labels
Error 502 Bad Gateway
-
Verifica que el puerto interno es correcto:
- Next.js por defecto usa puerto 3000
- Verifica
RULETA_APP_PORT=3000
-
Verifica que la aplicación está escuchando:
docker exec ruleta-app netstat -tulpn -
Verifica conectividad desde Traefik:
docker exec traefik ping ruleta-app
Las rutas no funcionan con basePath
Si configuraste basePath en Next.js:
- Opción A: Elimina el middleware
stripprefixde Traefik - Opción B: Elimina
basePathde Next.js (Traefik se encarga)
Recursos estáticos (CSS/JS) no cargan
Verifica:
- El
assetPrefixennext.config.js(debe coincidir con basePath) - Los logs del navegador (F12 → Console)
- Las rutas en el inspector de red (F12 → Network)
Variables de entorno no disponibles
Recuerda:
- Solo variables con prefijo
NEXT_PUBLIC_están disponibles en el navegador - Variables sin prefijo solo están disponibles en el servidor (API routes, getServerSideProps)
📚 Recursos Adicionales
🔄 Actualizaciones
Actualizar la Aplicación
-
Construye una nueva versión de la imagen:
docker build -t tu-usuario/ruleta:v2.0 . docker push tu-usuario/ruleta:v2.0 -
Actualiza en
stack.env:RULETA_IMAGE=tu-usuario/ruleta:v2.0 -
Actualiza el stack en Portainer
Rolling Updates
Para actualizaciones sin downtime, usa múltiples réplicas (requiere Docker Swarm o Kubernetes).
Rollback
Si algo sale mal:
- Vuelve a la versión anterior en
stack.env - Actualiza el stack en Portainer
📊 Monitoreo
Logs de la Aplicación
# Logs en tiempo real
docker logs -f ruleta-app
# Últimas 100 líneas
docker logs --tail 100 ruleta-app
# Logs con timestamps
docker logs -t ruleta-app
Logs de Next.js
Next.js registra en stdout/stderr, accesibles con docker logs.
Para logs estructurados, considera usar:
Métricas
Para monitorear la aplicación:
- Implementa un endpoint
/api/health - Usa herramientas como Prometheus + Grafana
- O servicios de APM como New Relic, Datadog
🎯 Casos de Uso
Este stack es ideal para:
- Aplicaciones Next.js personalizadas
- Landing pages
- Dashboards administrativos
- Aplicaciones full-stack con API routes
- JAMstack con SSR/SSG
💡 Tips
- Usa
output: 'standalone'en Next.js para imágenes Docker más pequeñas - Implementa caching con Redis para mejor rendimiento
- Usa ISR (Incremental Static Regeneration) para contenido dinámico
- Implementa rate limiting en API routes
- Usa CDN para assets estáticos (imágenes, CSS, JS)