Railway PaaS NutriTrack SaaS

Guía de Despliegue Railway CLI

Ciclo completo: setup · variables · entornos · deploy · health-check · rollback automático

Node.js 20 + Express
PostgreSQL + Redis
Staging + Production
GitHub Actions CI/CD
Prisma Migrations
🔗
Setup
🗄️
DB + Redis
🔐
Variables
🌿
Entornos
🚀
Deploy
🏥
Health-check
Rollback
1

Setup inicial del proyecto

Task A
terminal bash
# Instalar CLI (una sola vez)
$ npm i -g @railway/cli

# Autenticarse
$ railway login
  Opening browser for authentication...
  Logged in as dev@nutritrack.app ✓

# Inicializar proyecto desde el repo
$ railway init
  ✔ Created project "nutritrack-api" in workspace "NutriTrack"
  ✔ Linked to environment: production

# Verificar contexto siempre antes de ejecutar comandos
$ railway status
  Project:     nutritrack-api
  Service:     web
  Environment: production
  URL:         https://nutritrack-api.up.railway.app
ℹ️

En CI/CD (GitHub Actions) usar token headless: RAILWAY_TOKEN=xxx railway up --detach. El token de proyecto (RAILWAY_TOKEN) tiene scope limitado; para operaciones de cuenta usar RAILWAY_API_TOKEN.

2

Añadir PostgreSQL y Redis

Task C
PostgreSQL bash
$ railway add --database postgres
  ✔ Added PostgreSQL service
  ✔ DATABASE_URL auto-injected
  ✔ PGHOST, PGPORT, PGUSER set

# Verificar conexión
$ railway connect
  psql (PostgreSQL 16)
  nutritrack=# \dt
Redis bash
$ railway add --database redis
  ✔ Added Redis service
  ✔ REDIS_URL auto-injected
  ✔ REDISHOST, REDISPORT set

# Conectar a Redis shell
$ railway connect redis
  127.0.0.1:6379> PING
  PONG
3

Variables de entorno

Task D
terminal bash
# Inyectar variables sensibles (nunca en .env del repo)
$ railway variable set \
    JWT_SECRET=nt_jwt_prod_s3cr3t_2025 \
    SENDGRID_KEY=SG.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx \
    STRIPE_KEY=sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx \
    NODE_ENV=production \
    PORT=3000
  ✔ 5 variables set in production

# Listar todas (los valores secretos se enmascaran en la UI)
$ railway variable list
  DATABASE_URL   = postgres://railway:abc123@db.railway.app:5432/railway  [auto]
  REDIS_URL      = redis://default:xyz789@redis.railway.app:6379           [auto]
  JWT_SECRET     = nt_jwt_prod_s3cr3t_2025                                 [set]
  SENDGRID_KEY   = SG.xxxxx...                                             [set]
  STRIPE_KEY     = sk_live_xxxxx...                                        [set]
  NODE_ENV       = production                                              [set]
  PORT           = 3000                                                    [set]
Variable Descripción Tipo
DATABASE_URL Cadena de conexión PostgreSQL auto
REDIS_URL Cadena de conexión Redis auto
JWT_SECRET Secreto para firma de tokens JWT secret
SENDGRID_KEY API key para envío de emails transaccionales secret
STRIPE_KEY Clave secreta Stripe para pagos secret
NODE_ENV Entorno de ejecución config
PORT Puerto de escucha del servidor config
4

Gestión de entornos (staging / production)

Task E
terminal bash
# Crear entorno de staging que clona la config de production
$ railway environment new staging
  ✔ Created environment "staging" (cloned from production)

# Desplegar en staging (sin afectar production)
$ railway up -e staging -s web
  Uploading 1.8 MB...
  Build started (staging)
  ✔ Deployment live at nutritrack-api-staging.up.railway.app

# Sobrescribir variables sólo en staging
$ railway variable set -e staging \
    STRIPE_KEY=sk_test_xxxxxxxxxxxxxxxxxxxxxx \
    NODE_ENV=staging

# Cambiar contexto al entorno de production
$ railway environment
  ? Select environment:
  ❯ production
    staging
5

Deploy con migraciones Prisma

Task B + G
terminal — flujo de deploy manual bash
# 1. Ejecutar migraciones usando env vars de Railway (sin desplegar)
$ railway run npx prisma migrate deploy
  Prisma Migrate
  ✔ 4 migrations applied successfully
    - 20250102_init
    - 20250210_add_meals_table
    - 20250315_add_clinic_plans
    - 20250401_add_audit_log

# 2. Desplegar la API (detach = no bloquear terminal en logs)
$ railway up --detach
  Uploading 2.1 MB...
  Build started (detached)
  Deployment ID: dep_K9mXv7pQr2nLw

# 3. Asignar dominio personalizado
$ railway domain api.nutritrack.app
  ✔ Custom domain added
  ✔ SSL certificate issued (Let's Encrypt)
  Add CNAME api.nutritrack.app → nutritrack-api.up.railway.app
6

Health-check con auto-rollback

Task H · CI/CD
🚀

Script listo para GitHub Actions. Despliega, espera hasta 60 s a que GET /api/health responda 200 y hace rollback automático si falla.

deploy_railway.py python
#!/usr/bin/env python3
# deploy_railway.py — NutriTrack API · Deploy con health-check y auto-rollback
# Uso: python deploy_railway.py --env production --health https://api.nutritrack.app/api/health

import subprocess, time, httpx, argparse, sys

def run(cmd: list[str], **kw) -> subprocess.CompletedProcess:
    """Ejecuta un comando railway y lanza excepción en error."""
    return subprocess.run(cmd, check=True, **kw)

def deploy_with_health_check(
    env: str,
    health_url: str,
    service: str = "web",
    timeout: int = 60,
) -> bool:
    # 1. Verificar contexto
    run(["railway", "status"])

    # 2. Correr migraciones antes del deploy
    print("[1/3] Migraciones Prisma...")
    run(["railway", "run", "-e", env,
         "npx", "prisma", "migrate", "deploy"])

    # 3. Desplegar en modo detach
    print("[2/3] Desplegando en Railway...")
    run(["railway", "up", "--detach", "-e", env, "-s", service])

    # 4. Health-check loop
    print(f"[3/3] Health-check → {health_url} (timeout: {timeout}s)")
    deadline = time.time() + timeout
    while time.time() < deadline:
        try:
            r = httpx.get(health_url, timeout=5)
            if r.status_code == 200:
                print("✅  Deploy saludable — NutriTrack API activa")
                return True
        except httpx.RequestError:
            pass
        elapsed = int(timeout - (deadline - time.time()))
        print(f"  Esperando... ({elapsed}s)")
        time.sleep(3)

    # 5. Rollback automático
    print("❌  Health-check falló. Iniciando rollback...")
    run(["railway", "rollback", "-e", env])
    print("⏪  Rollback completado. Versión anterior restaurada.")
    return False

if __name__ == "__main__":
    ap = argparse.ArgumentParser()
    ap.add_argument("--env",     default="production")
    ap.add_argument("--health",  default="https://api.nutritrack.app/api/health")
    ap.add_argument("--service", default="web")
    ap.add_argument("--timeout", type=int, default=60)
    args = ap.parse_args()
    ok = deploy_with_health_check(args.env, args.health, args.service, args.timeout)
    sys.exit(0 if ok else 1)
7

Logs y depuración

Task F
terminal — escenario real: crashloop en production bash
# Ver logs de build (errores de dependencias, npm ci, etc.)
$ railway logs --build
  Step 3/7: RUN npm ci
  npm WARN deprecated bcrypt@5.1.0: use bcryptjs instead
  ✔ Build completed in 41s

# Ver últimas 50 líneas de logs de runtime
$ railway logs -n 50
  [2025-06-14 09:12:33] INFO  Server listening on port 3000
  [2025-06-14 09:12:33] ERROR connect ECONNREFUSED 127.0.0.1:5432
  [2025-06-14 09:12:33] FATAL Database connection failed — process exiting

# CAUSA: DATABASE_URL apunta a localhost. Corregir:
$ railway variable set \
    DATABASE_URL=postgres://railway:abc123@db.railway.app:5432/railway
  ✔ Variable updated

$ railway redeploy
  ✔ Redeploying web...
  [2025-06-14 09:15:01] INFO  Database connected ✓
  [2025-06-14 09:15:02] INFO  Server listening on port 3000 ✓
8

Cheatsheet de comandos esenciales

Referencia rápida

🚀 Deploy

  • railway up — deploy + stream logs
  • railway up --detach — deploy sin bloquear
  • railway up -e staging -s web — target específico
  • railway redeploy — rebuild mismo código
  • railway restart — reiniciar sin rebuild
  • railway rollback — restaurar versión anterior

🔐 Variables

  • railway variable list — listar variables
  • railway variable set K=V — crear/actualizar
  • railway variable delete K — eliminar
  • railway run cmd — comando con env vars
  • railway shell — shell interactivo

🏗️ Infraestructura

  • railway add --database postgres — añadir DB
  • railway add --database redis — añadir Redis
  • railway domain api.ejemplo.com — dominio custom
  • railway scale — escalar servicio
  • railway volume add — volumen persistente
  • railway connect — shell de base de datos

🔎 Diagnóstico

  • railway status — contexto actual
  • railway logs — logs en tiempo real
  • railway logs --build — logs de build
  • railway logs -n 100 — últimas N líneas
  • railway ssh — SSH al contenedor
  • railway environment new staging — nuevo entorno
9

Integración GitHub Actions

CI/CD
⚠️

Añadir RAILWAY_TOKEN como secret en GitHub: Settings → Secrets → Actions → New repository secret.

.github/workflows/deploy.yml yaml
name: Deploy NutriTrack API

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node 20
        uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Install Railway CLI
        run: npm i -g @railway/cli

      - name: Deploy with health-check
        env:
          RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}
        run: |
          pip install httpx
          python deploy_railway.py \
            --env production \
            --health https://api.nutritrack.app/api/health \
            --timeout 60