Files
devolucion_proveedores/deploy/windows/DEPLOY.md
T

14 KiB

Despliegue en Windows

La aplicación se ejecuta como un solo servicio de Windows: la API (NestJS) sirve también la web compilada (Angular), por HTTPS y en un único puerto. El servicio lo administra NSSM.

Navegador ──HTTPS :443──▶ servicio "DevolucionProveedores" (node dist\main.js)
                              ├─ sirve la web (Angular compilado)
                              ├─ /api  ──▶ Service Layer de SAP B1 (:50000)
                              └─ /api/…/pdf ──▶ web service de BES (HTTPS)

No hay base de datos propia ni otros servicios: todo se guarda en SAP. Como las sesiones viven en la memoria de la API, reiniciar el servicio cierra la sesión de todos los usuarios.

Estado de esta guía. La carpeta publicada, la API con HTTPS, la web servida por la API, la redirección HTTP→HTTPS y los logs sin colores se probaron en un Mac. Los scripts de PowerShell y NSSM no se han ejecutado todavía en Windows (se comprobó su sintaxis y los comandos de NSSM que generan, con -SoloMostrar). Tampoco se ha probado contra HANA. Haga la primera instalación en un servidor de pruebas.

1. Requisitos del servidor

Qué Detalle
Windows Windows Server 2016 o superior.
Node.js 22 LTS o superior, instalado para todos los usuarios (node -v en una consola nueva).
Red Acceso al Service Layer de SAP (puerto 50000) y al web service de BES (HTTPS de salida).
NSSM nssm.exe de 64 bits (carpeta win64 del .zip de https://nssm.cc/download). Ver la nota de abajo sobre la versión.
Certificado Un .pfx (o .key + .crt) para el nombre con que los usuarios abrirán la página.
Permisos Una consola de PowerShell como administrador.

Versión de NSSM. Descargue la compilación 2.24-101 (pre-release, nssm-2.24-101-g897c7ad.zip, carpeta win64), no la estable. La estable (2.24, de 2014) puede fallar al iniciar servicios en Windows 10 y 11 y en Windows Server 2019 o 2022 (mensajes como Unexpected status SERVICE_PAUSED); solo debería servir en Windows Server 2016. Compruebe con nssm version (debe decir 2.24-101-g897c7ad). La página de descargas no publica sumas de verificación: revise el .zip según la política de su empresa.

2. Publicar (en su equipo de desarrollo o en el servidor)

Desde la raíz del proyecto, con Node 22:

npm install
npm run publicar

Genera release\devolucion-proveedores\ con la API y la web compiladas y solo las dependencias de producción (unos 55 MB). Si ya compiló (npm run build), use npm run publicar -- --sin-build.

Las dependencias de la API son JavaScript puro, así que se puede publicar desde un Mac o Linux y ejecutar en Windows.

3. Copiar al servidor

Copie solo la carpeta release\devolucion-proveedores (no el resto del proyecto) a, por ejemplo, C:\apps\devolucion-proveedores. No contiene enlaces simbólicos, así que se puede copiar por red, USB o comprimida en un .zip (más rápido: son miles de archivos pequeños; en el servidor, Expand-Archive). nssm.exe no viene en la carpeta: se descarga aparte y se indica con -Nssm.

C:\apps\devolucion-proveedores\
├── app\                          la aplicación (no se edita, salvo el .env)
│   └── apps\api\.env             ← se crea en el paso 4
├── certificados\                 ← el certificado HTTPS (paso 5)
├── logs\                         ← los logs del servicio
├── servicio\                     ← lo crea el instalador (copia de nssm.exe)
├── instalar-servicio.ps1
├── desinstalar-servicio.ps1
└── DEPLOY.md

4. Configurar el .env

cd C:\apps\devolucion-proveedores\app\apps\api
Copy-Item .env.example .env
notepad .env

Ejemplo para producción (HANA, HTTPS en el puerto 443 y redirección desde el 80):

PORT=443
SL_URL=https://servidor-hana:50000/b1s/v1
SL_COMPANY_DB=NombreDeLaSociedad
SL_REJECT_UNAUTHORIZED=false
DB_TYPE=HANA
COOKIE_SECURE=true

HTTPS_PFX_PATH=C:\apps\devolucion-proveedores\certificados\sitio.pfx
HTTPS_PFX_PASSPHRASE=la-clave-del-pfx
HTTP_REDIRECT_PORT=80
  • El puerto es el que ponga en PORT: 443 es solo el ejemplo (con él la URL no lleva :puerto). Puede usar cualquiera que esté libre, por ejemplo PORT=8443; entonces la URL es https://servidor:8443. NSSM no influye: solo arranca el servicio.
  • HTTP_REDIRECT_PORT es opcional. Solo es útil con el 80 (la gente escribe http://servidor sin puerto); con otro puerto solo redirige a quien escriba http://servidor:<ese puerto>. Déjelo vacío si no lo necesita.
  • No se configura el usuario ni la contraseña de SAP: cada persona los escribe en el login.
  • WEB_ORIGIN no hace falta: la web y la API comparten origen.
  • Con .key/.crt en vez de .pfx: HTTPS_KEY_PATH y HTTPS_CERT_PATH (no mezcle ambas formas).
  • Si deja el .env con la clave del .pfx, restrinja quién puede leerlo:
icacls C:\apps\devolucion-proveedores\app\apps\api\.env /inheritance:r /grant:r "Administrators:F" "SYSTEM:F"

(Si el servicio correrá con una cuenta propia, agréguela con /grant:r "EMPRESA\svc-devolucion:R".)

5. Certificado HTTPS

Lo normal es un certificado de la CA de la empresa, exportado como .pfx a certificados\. Para una prueba puede crear uno autofirmado (los navegadores mostrarán una advertencia):

$c = New-SelfSignedCertificate -DnsName 'devolucion.empresa.local' -CertStoreLocation Cert:\LocalMachine\My -NotAfter (Get-Date).AddYears(2)
Export-PfxCertificate -Cert $c -FilePath C:\apps\devolucion-proveedores\certificados\sitio.pfx -Password (Read-Host -AsSecureString 'Clave del pfx')

HTTPS es obligatorio: el botón Pegar desde el portapapeles solo funciona con localhost o HTTPS, y la cookie de sesión se marca Secure.

6. Abrir el firewall

Abra el puerto que puso en PORT (y el de HTTP_REDIRECT_PORT, si lo usa). Con los valores del ejemplo (443 y 80):

New-NetFirewallRule -DisplayName 'Devolucion Proveedores HTTPS' -Direction Inbound -Protocol TCP -LocalPort 443 -Action Allow
New-NetFirewallRule -DisplayName 'Devolucion Proveedores HTTP (redireccion)' -Direction Inbound -Protocol TCP -LocalPort 80 -Action Allow

Desde el propio servidor (localhost) la aplicación funciona sin reglas; los demás equipos solo llegan si el puerto está abierto.

Ver las reglas que hay y su puerto:

Get-NetFirewallRule -DisplayName 'Devolucion Proveedores*' |
  Select-Object DisplayName, Enabled, @{ n = 'Puerto'; e = { ($_ | Get-NetFirewallPortFilter).LocalPort } }

Si más adelante cambia PORT, cambie el puerto de la regla existente en vez de crear otra, o borre la anterior para no dejar abierto un puerto que ya no se usa (por ejemplo, para pasar al 8443):

Set-NetFirewallRule -DisplayName 'Devolucion Proveedores HTTPS' -LocalPort 8443
# o bien
Remove-NetFirewallRule -DisplayName 'Devolucion Proveedores HTTPS'

Comprobar desde otro equipo que el puerto responde:

Test-NetConnection servidor -Port 443        # TcpTestSucceeded : True

Si da False con el servicio en Running, el bloqueo está en el firewall (de Windows o de la red).

7. Instalar el servicio

cd C:\apps\devolucion-proveedores
.\instalar-servicio.ps1 -Nssm C:\descargas\nssm-2.24-101-g897c7ad\win64\nssm.exe

Opciones:

Parámetro Para qué
-Cuenta 'EMPRESA\svc-devolucion' Ejecutar con una cuenta propia en vez de LocalSystem. Pide la contraseña y no la guarda en ningún archivo. Esa cuenta necesita el derecho Iniciar sesión como servicio y lectura sobre la carpeta.
-UsarCertificadosDelSistema Agrega NODE_OPTIONS=--use-system-ca. Úselo si Fortinet (u otro firewall) inspecciona el HTTPS de salida con un certificado propio y la descarga de PDF falla por certificado.
-NombreServicio Cambia el nombre del servicio (por defecto DevolucionProveedores).
-SoloMostrar Imprime los comandos de NSSM que ejecutaría y termina, sin instalar nada ni exigir administrador. Úselo para revisarlos antes.

El script verifica Node 22, los archivos y el .env; copia nssm.exe a servicio\; instala el servicio (arranque automático, reinicio a los 10 s si Node se cae, logs a logs\) y lo inicia. Si algún ajuste falla, quita el servicio a medio configurar.

8. Verificar

Get-Service DevolucionProveedores
Invoke-WebRequest https://devolucion.empresa.local/api/health -UseBasicParsing
Get-Content C:\apps\devolucion-proveedores\logs\*.out.log -Tail 30

Debe verse {"status":"ok"} y, en el log, la línea Escuchando en https://0.0.0.0:443. Después abra la dirección en un navegador, inicie sesión con un usuario de SAP y revise Configuración → Metadatos. En una base nueva pulse Reconstruir para crear las tablas, campos y el objeto de usuario.

9. Logs

NSSM guarda lo que la API escribe por consola en logs\devolucion-api.out.log y devolucion-api.err.log, y los rota al llegar a 10 MB (los rotados llevan la fecha y la hora en el nombre). La aplicación no escribe logs por su cuenta.

NSSM no limita cuántos archivos rotados conserva: se acumulan. Programe una limpieza periódica, por ejemplo una tarea que borre los de más de 30 días:

Get-ChildItem C:\apps\devolucion-proveedores\logs -Filter 'devolucion-api.*-*.log' |
  Where-Object LastWriteTime -lt (Get-Date).AddDays(-30) | Remove-Item
  • Los errores 4xx/5xx de la API, los fallos y las peticiones lentas al Service Layer, y los eventos de negocio (planificación creada, PDF descargado) quedan registrados. Las peticiones correctas no.
  • Para seguirlo en vivo: Get-Content C:\apps\devolucion-proveedores\logs\*.out.log -Wait -Tail 50.
  • La contraseña del web service DTE (@DTE_CONFC) y las de los usuarios nunca se registran.

10. Administrar el servicio

Con servicio\nssm.exe (la copia que dejó el instalador):

cd C:\apps\devolucion-proveedores\servicio
.\nssm.exe status DevolucionProveedores
.\nssm.exe restart DevolucionProveedores
.\nssm.exe edit DevolucionProveedores        # ventana gráfica con todos los ajustes
.\nssm.exe get DevolucionProveedores AppEnvironmentExtra

Para cambiar una variable de entorno del servicio con nssm set ... AppEnvironmentExtra, indique todas las variables juntas (reemplaza la lista completa): NODE_ENV=production NO_COLOR=1 [NODE_OPTIONS=--use-system-ca]. Los valores de la aplicación (puerto, SAP, HTTPS) no van aquí: se cambian en el .env y se reinicia el servicio:

Stop-Service DevolucionProveedores
notepad C:\apps\devolucion-proveedores\app\apps\api\.env
Start-Service DevolucionProveedores
  • Al cambiar SL_COMPANY_DB, revise que DB_TYPE (HANA/MSSQL) corresponda a esa base y, tras entrar, pase por Configuración → Metadatos. El login muestra la sociedad conectada.
  • Al cambiar PORT, ajuste el firewall (paso 6). La web y la API usan el mismo puerto.
  • La versión instalada se ve en el login, en la barra superior, en VERSION.txt y en el log al arrancar.

11. Actualizar a una versión nueva

  1. Publique la versión nueva (paso 2) y copie la carpeta al servidor, por ejemplo a C:\nueva\.
  2. Elija una hora en que haya pocos usuarios: se perderán las sesiones.
  3. Ejecute:
Stop-Service DevolucionProveedores
# Respaldo opcional de la versión actual
Copy-Item C:\apps\devolucion-proveedores\app C:\apps\respaldo-app -Recurse
# Copia la nueva sin tocar el .env
robocopy C:\nueva\devolucion-proveedores\app C:\apps\devolucion-proveedores\app /MIR /XF .env
Start-Service DevolucionProveedores

/MIR borra de app\ lo que ya no exista en la versión nueva; /XF .env conserva su configuración. Los certificados, los logs y el servicio no cambian.

12. Desinstalar

cd C:\apps\devolucion-proveedores
.\desinstalar-servicio.ps1

Detiene y elimina el servicio. No borra archivos ni logs.

13. Seguridad

  • No publique la aplicación en Internet. El login es el de SAP B1; manténgala en la red interna o detrás de una VPN.
  • Use un certificado válido de la CA de la empresa; el servicio envía Strict-Transport-Security.
  • Dele al servicio la cuenta con menos permisos posible: solo lectura sobre su carpeta y escritura en logs\.
  • Restrinja la lectura del .env si contiene la clave del .pfx (paso 4).

14. Problemas frecuentes

Síntoma Causa probable
El servicio no inicia (SERVICE_PAUSED, Unexpected status) Problema conocido de NSSM 2.24 estable en Windows recientes: use la compilación 2.24-101 (ver el paso 1) y reinstale el servicio.
El servicio se inicia y se detiene Mire logs\*.err.log. Suele ser una ruta mal escrita en el .env (No se pudo leer HTTPS_PFX_PATH (…)) o el puerto ocupado (EADDRINUSE).
WEB_DIST_DIR no contiene un index.html Se copió la carpeta app incompleta: falta app\apps\web\dist\web\browser.
Puerto 443 o 80 ocupado IIS u otro programa lo usa. Cambie PORT / HTTP_REDIRECT_PORT en el .env y las reglas del firewall.
El navegador avisa que el sitio no es seguro Certificado autofirmado, o el nombre de la URL no coincide con el del certificado.
Entra al login pero vuelve a pedirlo Con COOKIE_SECURE=true la cookie solo se guarda por HTTPS: abra la página por https://.
EHOSTUNREACH o no conecta con SAP Red o firewall hacia el Service Layer; reinicie el servicio tras un cambio de red.
La descarga de PDF falla por certificado Fortinet inspecciona el HTTPS de salida: reinstale con -UsarCertificadosDelSistema, o importe el certificado raíz de Fortinet en Windows.
Cada acción tarda decenas de segundos Mire el log: los avisos Petición lenta al Service Layer indican qué llamada y cuánto tardó.
.\instalar-servicio.ps1 dice que no se puede ejecutar scripts Set-ExecutionPolicy -Scope Process Bypass en esa consola y vuelva a intentarlo.

Antes de pasar a producción (HANA)

El sistema se probó contra SQL Server (SBOLibros). Con HANA:

  1. Pruebe primero con una copia de la sociedad: DB_TYPE=HANA, Reconstruir y una ejecución completa.
  2. Compare los resultados del FIFO con los del addon .NET para el mismo listado.
  3. Confirme que el Service Layer de HANA expone /b1s/v1 (el paginado usa $inlinecount).