Cómo iniciar una aplicación automáticamente en Windows Server con NSSM

Configura tu aplicación Node, Python o Java para arrancar sola tras reiniciar Windows Server usando NSSM como servicio — paso a paso ejecutable.

Toda aplicación en producción debe sobrevivir a reinicios. Actualizaciones de seguridad de Windows, cortes de energía, mantenimiento del hipervisor — cualquiera de estos eventos derriba el servidor, y si tu aplicación Node, Python o Java está corriendo dentro de una sesión interactiva (node server.js en una terminal abierta), muere con ella y no vuelve sola.

La solución correcta en Windows es registrar la aplicación como servicio del sistema. Los servicios corren en la sesión 0 — aislada de cualquier inicio de sesión interactivo —, arrancan automáticamente en el boot, se reinician ante fallos y exponen controles estandarizados (sc start, sc stop, Get-Service). Este tutorial cubre la ruta más usada para aplicaciones que no nacieron como servicio nativo de Windows: NSSM (Non-Sucking Service Manager).

Tiempo estimado: 15 a 20 minutos, incluyendo verificación. Persona objetivo: desarrollador que ya tiene la aplicación ejecutándose manualmente en el servidor y quiere hacerla persistente.

Prerrequisitos

Lo que necesitas antes de empezar

Windows Server 2019, 2022 o 2025 con acceso RDP de administrador. Tu aplicación ya probada y ejecutándose manualmente (node app.js, python app.py, java -jar app.jar). Ruta absoluta del ejecutable (Node, Python, JRE) y del script de entrada anotadas. PowerShell abierto como administrador.

SO probado Windows Server 2019/2022/2025
Versión NSSM 2.24 (estable)
Privilegio necesario Administrator local
Puerto de la app Tu elección (ej: 3000)

Confirma antes de seguir que la aplicación corre cuando ejecutas el comando manualmente en PowerShell y responde en el puerto esperado — convertirla en servicio no arregla un bug de configuración de la aplicación en sí.

Descarga e instala NSSM

NSSM es un binario standalone (nssm.exe) — no tiene instalador MSI ni dependencias. La forma más limpia es colocarlo en C:\Tools\nssm\ y añadirlo al PATH del sistema.

01

Crea el directorio de herramientas y descarga NSSM desde PowerShell:

New-Item -ItemType Directory -Force -Path C:\Tools\nssm
Invoke-WebRequest -Uri "https://nssm.cc/release/nssm-2.24.zip" -OutFile C:\Tools\nssm.zip
Expand-Archive -Path C:\Tools\nssm.zip -DestinationPath C:\Tools\nssm-temp
Copy-Item C:\Tools\nssm-temp\nssm-2.24\win64\nssm.exe C:\Tools\nssm\
Remove-Item C:\Tools\nssm.zip, C:\Tools\nssm-temp -Recurse -Force

El archivo nssm.exe ahora vive en C:\Tools\nssm\nssm.exe. Usa siempre la build win64 en servidores modernos.

02

Añade NSSM al PATH del sistema para invocar nssm desde cualquier directorio:

$old = [Environment]::GetEnvironmentVariable("Path", "Machine")
[Environment]::SetEnvironmentVariable("Path", "$old;C:\Tools\nssm", "Machine")

Cierra PowerShell y ábrelo de nuevo para recargar el PATH. Confirma con nssm version — debe responder NSSM version 2.24.

Verifica la integridad de la descarga

Si el servidor está expuesto a internet, conviene comprobar el hash SHA256 del archivo descargado contra el publicado en nssm.cc. Los binarios ejecutables descargados sin verificación son un vector clásico de compromiso — vale el minuto extra.

Registra tu aplicación como servicio

Con NSSM disponible, cada servicio se configura con nssm install <Nombre> (modo GUI) o nssm install <Nombre> <ejecutable> <argumentos> (modo headless). Vamos a usar el modo headless porque es reproducible, versionable y funciona en Server Core.

01

Instala el servicio apuntando al intérprete y al script. Sustituye las rutas por las de tu aplicación:

nssm install MiApp "C:\Program Files\nodejs\node.exe" "C:\apps\miapp\server.js"

Para aplicaciones Python:

nssm install MiApp "C:\Python312\python.exe" "C:\apps\miapp\app.py"

Para aplicaciones Java:

nssm install MiApp "C:\Program Files\Java\jdk-21\bin\java.exe" "-jar C:\apps\miapp\app.jar"

El nombre del servicio (MiApp) es el que aparece en services.msc y en sc query. Usa nombres descriptivos sin espacios.

02

Configura el directorio de trabajo de la aplicación. Sin esto, las rutas relativas en el código (logs, archivos de configuración, módulos) se rompen porque el servicio arranca en C:\Windows\System32 por defecto:

nssm set MiApp AppDirectory "C:\apps\miapp"

Este es el error de configuración más común en una primera instalación. Anótalo: AppDirectory siempre apunta al directorio que contiene el script de entrada.

03

Define las variables de entorno que la aplicación espera. NSSM acepta múltiples variables separadas por \0 (escape literal), o las defines una a una:

nssm set MiApp AppEnvironmentExtra "NODE_ENV=production" "PORT=3000" "DATABASE_URL=postgres://..."

Las variables sensibles (tokens, contraseñas) pueden ir aquí, pero ten en cuenta que el registro de Windows es legible por cualquier admin. Para secretos de verdad, prefiere leerlos desde un archivo .env protegido por ACL o desde un vault.

04

Configura logs de stdout y stderr — sin esto, cualquier mensaje que la aplicación imprima simplemente desaparece:

New-Item -ItemType Directory -Force -Path C:\apps\miapp\logs
nssm set MiApp AppStdout "C:\apps\miapp\logs\stdout.log"
nssm set MiApp AppStderr "C:\apps\miapp\logs\stderr.log"
nssm set MiApp AppRotateFiles 1
nssm set MiApp AppRotateOnline 1
nssm set MiApp AppRotateBytes 10485760

AppRotateBytes 10485760 rota cuando el archivo alcanza 10 MB. Sin rotación, un log olvidado crece hasta llenar el disco.

05

Configura la política de restart en caso de crash. NSSM ofrece tres modos: Restart (predeterminado — siempre reinicia), Ignore (no hace nada) y Exit (no reinicia). Para producción, mantén el valor por defecto pero ajusta el delay:

nssm set MiApp AppExit Default Restart
nssm set MiApp AppRestartDelay 5000

Un delay de 5 segundos evita un bucle de crash apretado consumiendo CPU si la aplicación se rompe nada más arrancar.

Inicia y configura el auto-arranque

Con todo configurado, falta marcar el servicio para que arranque en el boot e iniciarlo ahora por primera vez como servicio.

01

Marca el servicio como Automatic (arranca en el boot) y configura las dependencias de red:

sc config MiApp start= auto
sc config MiApp depend= Tcpip/Dnscache

El espacio después del = es obligatorio — sintaxis peculiar de sc.exe. La dependencia garantiza que la pila TCP/IP y el cliente DNS estén listos antes de que el servicio arranque — sin esto, las aplicaciones que hacen lookup DNS en el startup fallan aleatoriamente en el boot.

02

Arranca el servicio ahora:

nssm start MiApp

Deberías ver MiApp: START: The operation completed successfully.. Si recibes un error, salta a la sección de verificación más abajo antes de seguir.

Cuenta de ejecución dedicada

En entornos más maduros, evita ejecutar como LocalSystem (predeterminado). Crea una cuenta local de servicio (net user svc_miapp <password> /add), concede solo los permisos NTFS necesarios en el directorio de la app y usa nssm set MiApp ObjectName .\svc_miapp <password>. Un compromiso de la aplicación queda contenido — no escala a SYSTEM.

Verificación

Antes de dar la tarea por terminada, valida tres cosas: el servicio respondió al start, la aplicación está respondiendo en el puerto esperado, y un boot real reinicia todo solo.

01

Confirma que el servicio está corriendo:

Get-Service MiApp

La columna Status debe mostrar Running y StartType debe ser Automatic. Si aparece Stopped, abre C:\apps\miapp\logs\stderr.log — el error real de la aplicación está ahí.

02

Prueba el endpoint de la aplicación:

Invoke-WebRequest http://localhost:3000 -UseBasicParsing | Select-Object StatusCode, Content

Sustituye el puerto por el que hayas configurado. Una respuesta 200 OK confirma que está atendiendo dentro de la sesión 0 correctamente.

03

Reinicia el servidor para validar el auto-arranque de verdad. Esta es la única forma fiable de garantizar que va a funcionar mañana cuando no estés mirando:

Restart-Computer -Force

Reconecta por RDP tras unos 60 segundos y ejecuta Get-Service MiApp de nuevo. Estado Running sin que hayas hecho nada = configuración correcta.

Resolución de problemas

El servicio arranca pero se detiene inmediatamente

La causa casi siempre es un AppDirectory incorrecto o una variable de entorno faltante. Abre stderr.log — el stack trace de la aplicación está ahí. Para depuración interactiva, ejecuta el comando exacto que NSSM ejecutaría desde un PowerShell admin: cd C:\apps\miapp; & "C:\Program Files\nodejs\node.exe" server.js. Si se rompe, el problema es de la app, no de NSSM.

Error “The service did not respond to the start or control request in a timely fashion”

La aplicación tardó más de 30 segundos en abrir el puerto de escucha. Aplicaciones Java grandes o Python con lazy import pueden rozar ese límite. Aumenta el timeout de Windows:

nssm set MiApp AppThrottle 10000
sc config MiApp obj= LocalSystem

Para atacar la raíz del problema, considera mover la inicialización pesada a background después del bind del puerto.

Logs vacíos aunque la aplicación esté crasheando

Verifica que el proceso esté realmente escribiendo en stdout/stderr y no en su propio archivo. Algunas librerías de log (Winston, Log4j) necesitan configuración explícita para mandar a stdout. Confirma también que el usuario del servicio tiene permiso NTFS de escritura en C:\apps\miapp\logs.

Próximos pasos

Con la aplicación corriendo como servicio persistente, conviene endurecer el entorno:

  • Configura una regla en Windows Defender Firewall liberando solo el puerto de la aplicación (New-NetFirewallRule -DisplayName "MiApp" -Direction Inbound -LocalPort 3000 -Protocol TCP -Action Allow)
  • Pon un IIS o un reverse proxy (Caddy, nginx para Windows) por delante para terminar TLS y añadir HTTP/2
  • Configura backup automático del directorio de la aplicación y del registro del servicio (nssm dump MiApp > C:\backup\miapp-service.cmd)
  • Monitorea el servicio externamente — Get-Service solo confirma que el proceso está vivo, no que esté respondiendo correctamente

Si vas a poner esto en producción, una VPS Hostini con Windows Server preconfigurado entrega RDP estable y snapshots programados antes de cada deploy, así que un rollback de configuración de servicio es una operación de minutos, no de horas.

Preguntas frecuentes

¿Puedo usar el Programador de tareas en lugar de NSSM?

Sí, pero con limitaciones. El Programador de tareas con disparador "Al iniciar" funciona para scripts simples, pero no reinicia el proceso si falla, no captura stdout/stderr en archivo y no corre en la sesión 0 aislada. NSSM resuelve esos tres puntos por defecto. Para aplicaciones de producción, NSSM o sc.exe con un binario nativo de Windows Service son la opción correcta.

¿El servicio necesita ejecutarse como Administrador?

No. Usa la cuenta LocalSystem (predeterminada de NSSM) o crea una cuenta de servicio dedicada con privilegios mínimos. Ejecutar como Administrador es innecesario para la mayoría de aplicaciones web — bastan permisos de lectura en el directorio del código y escritura en el directorio de logs.

¿Cómo veo los logs de la aplicación después de convertirla en servicio?

NSSM redirige stdout y stderr a los archivos configurados en AppStdout y AppStderr. Configura rotación con AppRotateFiles=1 y AppRotateBytes=10485760 (10 MB) para evitar logs infinitos. Los eventos del propio servicio (start, stop, crash) quedan en Visor de eventos → Registros de Windows → Aplicación.

La aplicación arranca antes de que la red esté lista — ¿cómo lo evito?

Configura la dependencia del servicio con `sc config NombreServicio depend= Tcpip/Dnscache/LanmanWorkstation`. Eso obliga a Windows a iniciar el servicio solo después de que TCP/IP, el cliente DNS y la estación de trabajo de red estén listos. NSSM también tiene la opción AppStopMethodSkip para control fino del shutdown.

¿Puedo instalar varias instancias de la misma aplicación en puertos distintos?

Sí. Crea un servicio NSSM por instancia con nombres distintos (MiApp-3000, MiApp-3001) y usa AppParameters o variables de entorno (AppEnvironmentExtra PORT=3001) para diferenciarlas. Cada servicio gestiona su proceso de forma independiente.

¿NSSM funciona en Windows Server Core (sin GUI)?

Sí. Toda la interacción con NSSM se puede hacer por línea de comandos — `nssm install`, `nssm set`, `nssm start`. La GUI (nssm install sin argumentos) solo se abre si hay un shell gráfico disponible. Core está totalmente soportado.

Temas:
Próximos pasos Cloud Ryzen con NVMe y protección DDoS siempre activa.Pon en producción en un VPS Hostini →
¿Te resultó útil este tutorial?
Hablar por WhatsApp