Ir al contenido

Esta guía te ayudará a migrar variables de entorno entre plataformas de despliegue (Fly.io ↔ Railway) y rotar secrets de producción de forma segura sin tiempo de inactividad.

  1. Ir a fly.io/dashboard
  2. Seleccionar tu app: talentbricksai
  3. Ir a Secrets
  4. Copiar manualmente cada variable (Fly.io no permite exportación masiva)
Ventana de terminal
# Listar todas las secrets
flyctl secrets list -a talentbricksai
# Guardar lista en archivo temporal
flyctl secrets list -a talentbricksai > fly-secrets.txt

Nota: flyctl secrets list solo muestra los nombres, no los valores. Necesitas los valores originales de tu configuración.

Opción C: Desde tu .env Local (si lo tienes)

Sección titulada «Opción C: Desde tu .env Local (si lo tienes)»

Si tienes un .env.production local con todas las variables:

Ventana de terminal
# Asegúrate que tiene todas las variables de producción
cat .env.production
  1. Ir a railway.app
  2. Seleccionar tu proyecto
  3. Ir a Variables
  4. Click + New Variable
  5. Agregar cada variable manualmente
Ventana de terminal
# Instalar Railway CLI
npm i -g @railway/cli
# Login
railway login
# Vincular proyecto
railway link
# Importar variables una por una
railway variables set DATABASE_URL="postgresql://..."
railway variables set JWT_SECRET="tu_secret"
railway variables set STRIPE_API_KEY="sk_live_..."
railway variables set STRIPE_WEBHOOK_SECRET="whsec_..."
# ... etc
Ventana de terminal
# Crear archivo temporal con variables
cat > railway.env << 'EOF'
DATABASE_URL=postgresql://...
JWT_SECRET=...
STRIPE_API_KEY=sk_live_...
STRIPE_WEBHOOK_SECRET=whsec_...
# ... todas las variables
EOF
# Importar todas a la vez (cada línea)
cat railway.env | while IFS='=' read -r key value; do
railway variables set "$key"="$value"
done
# ⚠️ Eliminar archivo temporal
rm railway.env
Ventana de terminal
# Listar variables en Railway
railway variables
# Verificar que todas las requeridas están presentes
railway run env | grep -E "(DATABASE_URL|JWT_SECRET|STRIPE)"

Después de migrar a Railway, actualiza:

  1. Ir a dashboard.stripe.com/webhooks
  2. Editar webhook existente o crear nuevo:
    • URL anterior (Fly.io): https://talentbricksai.fly.dev/stripe-webhook
    • URL nueva (Railway): https://talentbricksai-production.up.railway.app/stripe-webhook
  3. Copiar nuevo Signing secret (whsec_...)
  4. Actualizar en Railway:
    Ventana de terminal
    railway variables set STRIPE_WEBHOOK_SECRET="whsec_nuevo_valor"
  1. Ir a console.cloud.google.com/apis/credentials
  2. Editar OAuth client
  3. Authorized redirect URIs - agregar:
    https://talentbricksai-production.up.railway.app/auth/google/callback
  1. Ir a github.com/settings/developers
  2. Editar OAuth App
  3. Authorization callback URL - cambiar a:
    https://talentbricksai-production.up.railway.app/auth/github/callback
Ventana de terminal
# Railway
railway variables set CLIENT_URL="https://talentbricksai-production.up.railway.app"
Ventana de terminal
# Desplegar en Railway
railway up
# Ver logs
railway logs --tail
# Verificar que la app inicia sin errores
Ventana de terminal
# Listar variables
railway variables
# Guardar en archivo temporal (manual)
railway variables > railway-vars.txt
Ventana de terminal
# Configurar cada secret
flyctl secrets set DATABASE_URL="postgresql://..." -a talentbricksai
flyctl secrets set JWT_SECRET="tu_secret" -a talentbricksai
flyctl secrets set STRIPE_API_KEY="sk_live_..." -a talentbricksai
# ... etc

Nota: Cada vez que configuras un secret en Fly.io, la app se redespliega automáticamente. Para evitar múltiples redespliegues, puedes usar:

Ventana de terminal
# Configurar múltiples secrets a la vez
flyctl secrets set \
DATABASE_URL="postgresql://..." \
JWT_SECRET="tu_secret" \
STRIPE_API_KEY="sk_live_..." \
STRIPE_WEBHOOK_SECRET="whsec_..." \
-a talentbricksai

Mismo proceso que arriba, pero cambiar URLs de Railway a Fly.io:

  • Railway: https://app.up.railway.app
  • Fly.io: https://app.fly.dev

Es buena práctica rotar secrets periódicamente o después de una brecha de seguridad.

⚠️ Importante: Cambiar JWT_SECRET invalidará todas las sesiones activas. Los usuarios tendrán que hacer login de nuevo.

Ventana de terminal
# 1. Generar nuevo secret
openssl rand -base64 32
# 2. Configurar en tu plataforma
# Fly.io:
flyctl secrets set JWT_SECRET="nuevo_valor_aqui" -a talentbricksai
# Railway:
railway variables set JWT_SECRET="nuevo_valor_aqui"
# 3. Reiniciar app (automático en Fly.io, manual en Railway)
railway up
# 4. Notificar a usuarios (opcional)
# Enviar email avisando que necesitan hacer login de nuevo

Alternativa sin downtime (requiere código):

  1. Soportar múltiples secrets simultáneamente:

    app/src/server/auth.ts
    const JWT_SECRETS = [
    process.env.JWT_SECRET, // nuevo
    process.env.JWT_SECRET_OLD, // viejo
    ];
    // Intentar verificar con cada secret
    for (const secret of JWT_SECRETS) {
    try {
    return jwt.verify(token, secret);
    } catch (err) {
    continue;
    }
    }
  2. Configurar ambos secrets:

    Ventana de terminal
    railway variables set JWT_SECRET="nuevo"
    railway variables set JWT_SECRET_OLD="viejo"
  3. Después de ~24 horas, remover el viejo:

    Ventana de terminal
    railway variables set JWT_SECRET_OLD=""

Estrategia sin downtime:

  1. Ir a dashboard.stripe.com/apikeys
  2. Click + Create restricted key
  3. Nombre: TalentBricks Production - 2024
  4. Permisos necesarios:
    • Checkout Sessions: Write
    • Customers: Write
    • Subscriptions: Write
    • Prices: Read
    • Products: Read
    • Invoices: Read
  5. Copiar la nueva API key (sk_live_...)
Ventana de terminal
# Railway
railway variables set STRIPE_API_KEY="sk_live_nuevo_valor"
# Fly.io
flyctl secrets set STRIPE_API_KEY="sk_live_nuevo_valor" -a talentbricksai
# Verificar que funciona
railway logs --tail
# Buscar errores relacionados con Stripe

⚠️ Importante: Crear webhook ANTES de cambiar el secret para evitar downtime.

  1. Ir a dashboard.stripe.com/webhooks
  2. Click Add endpoint
  3. Endpoint URL: https://tu-dominio.com/stripe-webhook
  4. Seleccionar eventos (ver checklist de producción)
  5. Click Add endpoint
  6. Copiar Signing secret (whsec_...)
  7. Actualizar variable:
    Ventana de terminal
    railway variables set STRIPE_WEBHOOK_SECRET="whsec_nuevo"
  8. Opcional: Eliminar webhook viejo después de verificar que el nuevo funciona
Ventana de terminal
# Hacer compra de prueba
# Verificar en Stripe Dashboard → Webhooks → Recent deliveries → 200 OK

Estrategia sin downtime:

  1. Ir a console.aws.amazon.com/iam
  2. UsersCreate user
  3. Nombre: talentbricks-app-v2
  4. Attach policy: AmazonS3FullAccess (o custom policy)
  5. Create user
  6. Security credentialsCreate access key
  7. Copiar Access key ID y Secret access key
Ventana de terminal
# Railway
railway variables set AWS_S3_IAM_ACCESS_KEY="AKIA_nuevo"
railway variables set AWS_S3_IAM_SECRET_KEY="nuevo_secret"
# Fly.io
flyctl secrets set \
AWS_S3_IAM_ACCESS_KEY="AKIA_nuevo" \
AWS_S3_IAM_SECRET_KEY="nuevo_secret" \
-a talentbricksai
Ventana de terminal
# Intentar subir un archivo de prueba
# O hacer upload via dashboard de admin
  1. Ir a IAM → Users → talentbricks-app-v1
  2. Security credentials
  3. Make inactive en las access keys antiguas
  4. Esperar 24-48 horas
  5. Si no hay errores, eliminar user antiguo

⚠️ Complejo: Rotar CloudFront keys requiere actualizar la distribución.

Ventana de terminal
# Generar nuevo par de claves
openssl genrsa -out cloudfront_private_key_new.pem 2048
openssl rsa -pubout -in cloudfront_private_key_new.pem -out cloudfront_public_key_new.pem
  1. Ir a console.aws.amazon.com/cloudfront
  2. Public keysAdd public key
  3. Pegar contenido de cloudfront_public_key_new.pem
  4. Copiar el Key ID generado
Ventana de terminal
# Leer private key en una línea
PRIVATE_KEY=$(awk 'NF {sub(/\r/, ""); printf "%s\\n",$0;}' cloudfront_private_key_new.pem)
# Configurar
railway variables set CLOUDFRONT_KEY_PAIR_ID="K_nuevo_id"
railway variables set CLOUDFRONT_PRIVATE_KEY="$PRIVATE_KEY"
  1. Abrir curso con video en la app
  2. Verificar que el video carga correctamente
  3. Verificar que la URL tiene signature válida
  1. CloudFront → Public keys
  2. Encontrar key antiguo
  3. Disassociate de las distribuciones
  4. Delete

Estrategia sin downtime:

  1. Ir a app.sendgrid.com/settings/api_keys
  2. Click Create API Key
  3. Nombre: TalentBricks Production - 2024
  4. Permisos: Full Access (o Restricted con Mail Send)
  5. Copiar API key (SG....)
Ventana de terminal
railway variables set SENDGRID_API_KEY="SG.nuevo_valor"
Ventana de terminal
# Registrar nuevo usuario para probar email
# O usar "Forgot password" para enviar email de prueba
# Verificar en SendGrid → Activity que el email se envió
  1. SendGrid → Settings → API Keys
  2. Encontrar key antigua
  3. Click •••Delete

Sigue este checklist para migrar sin tiempo de inactividad:

  • Backup completo de base de datos
  • Documentar todas las variables actuales
  • Crear nuevos secrets/keys en servicios externos
  • Configurar nuevo entorno en paralelo (si es posible)
  • Configurar variables en nuevo entorno
  • Probar conexión a base de datos
  • Probar pagos en Stripe test mode primero
  • Configurar webhooks en nuevo dominio (sin eliminar los viejos todavía)
  • Hacer deploy de prueba en nuevo entorno
  • Verificar logs sin errores
  • Reducir TTL de DNS a 300 segundos (5 minutos)
  • Esperar 24 horas para que TTL se propague
  • Cambiar DNS para apuntar a nuevo entorno
  • Monitorear logs en ambos entornos
  • Verificar que webhooks llegan al nuevo endpoint
  • Verificar flujo completo en producción
  • Hacer compra de prueba real
  • Verificar que emails llegan
  • Verificar que videos cargan
  • Monitorear errores por 24-48 horas
  • Incrementar TTL de DNS a valor normal (3600)
  • Eliminar webhooks viejos
  • Desactivar secrets viejos (no eliminar todavía)
  • Esperar 7 días
  • Eliminar secrets viejos permanentemente
  • Apagar entorno viejo
SecretFrecuencia RecomendadaImpactoComplejidad
JWT_SECRETCada 6 meses o después de brechaAlto - usuarios deben re-loginBaja
STRIPE_API_KEYCada 12 mesesMedio - pagos temporalmente afectadosBaja
STRIPE_WEBHOOK_SECRETAl cambiar endpointsBajo - crear nuevo webhookBaja
AWS_S3_IAM_ACCESS_KEYCada 90 días (buena práctica)Medio - uploads fallanMedia
CLOUDFRONT_PRIVATE_KEYCada 12 mesesAlto - videos no carganAlta
SENDGRID_API_KEYCada 12 mesesMedio - emails no lleganBaja
DATABASE_URLSolo al migrar DBCrítico - app no funcionaAlta

Para migrar todas las variables de Fly.io a Railway:

migrate-fly-to-railway.sh
#!/bin/bash
set -e # Exit on error
echo "🚀 Migrando variables de Fly.io a Railway..."
# Variables a migrar (agregar todas las tuyas)
VARS=(
"DATABASE_URL"
"JWT_SECRET"
"STRIPE_API_KEY"
"STRIPE_WEBHOOK_SECRET"
"PAYMENTS_MONTHLY_SUBSCRIPTION_PLAN_ID"
"PAYMENTS_ANNUAL_SUBSCRIPTION_PLAN_ID"
"SENDGRID_API_KEY"
"ADMIN_EMAILS"
"CLIENT_URL"
"AWS_S3_IAM_ACCESS_KEY"
"AWS_S3_IAM_SECRET_KEY"
"AWS_S3_FILES_BUCKET"
"AWS_S3_REGION"
"CLOUDFRONT_DOMAIN"
"CLOUDFRONT_KEY_PAIR_ID"
"CLOUDFRONT_PRIVATE_KEY"
)
# Leer de .env local (asegúrate que tiene valores de producción)
if [ ! -f ".env.production" ]; then
echo "❌ Error: .env.production no encontrado"
exit 1
fi
source .env.production
# Migrar cada variable
for var in "${VARS[@]}"; do
value="${!var}"
if [ -z "$value" ]; then
echo "⚠️ Saltando $var (vacío)"
continue
fi
echo "✅ Migrando $var"
railway variables set "$var"="$value"
done
echo "🎉 Migración completada!"
echo "Verifica: railway variables"

Uso:

Ventana de terminal
chmod +x migrate-fly-to-railway.sh
./migrate-fly-to-railway.sh

Railway:

Ventana de terminal
# Eliminar primero
railway variables set VARIABLE=""
# Luego configurar nuevo valor
railway variables set VARIABLE="nuevo_valor"

Fly.io:

Ventana de terminal
# Fly.io permite sobrescribir directamente
flyctl secrets set VARIABLE="nuevo_valor" -a talentbricksai

Railway:

Ventana de terminal
# Forzar redespliegue
railway up --detach

Fly.io:

Ventana de terminal
# Reiniciar app
flyctl apps restart talentbricksai

Solución:

  1. Verificar que DNS cambió: nslookup tu-dominio.com
  2. Esperar propagación de DNS (hasta 48 horas)
  3. Verificar TTL bajo antes del cambio

Si encuentras problemas durante la migración:

  1. Revisar logs: railway logs o flyctl logs
  2. Verificar que todas las variables están configuradas
  3. Consultar documentación de la plataforma
  4. Pedir ayuda en Wasp Discord