¿Tu aplicación Java se detiene al intentar ejecutarse como servicio en Windows Server 2019? Aprende a diagnosticar el error 0x80004005
y a desplegar tu .jar
para que arranque en segundo plano, sin necesidad de iniciar sesión, mediante WinSW, NSSM o la propia utilidad sc.exe
.
Resumen del problema
Al registrar un servicio con sc.exe
o con un wrapper (WinSW / NSSM) el servicio arranca y se detiene al instante. En el Visor de eventos aparece la excepción:
System.ComponentModel.Win32Exception (0x80004005): The system cannot find the file specified
El código indica que Windows no localiza el binario configurado como binPath —normalmente java.exe
— o el propio .jar
, por lo que el Administrador de servicios marca el proceso como fallido.
Causas habituales
- Variable
JAVA_HOME
mal definida o ausente. %JAVA_HOME%\bin
no agregado aPATH
.- Ruta del
.jar
con espacios no encerrada entre comillas. - Permisos insuficientes de la cuenta de servicio sobre la carpeta que contiene el
.jar
o sobre el JRE. - Timeout de inicio demasiado corto en el wrapper.
Verificación rápida antes de crear el servicio
- Asegúrate de que el
.jar
se ejecuta de forma interactiva:java -jar "C:\Apps\MiAplicacion\app.jar"
- Comprueba que la versión de Java coincide con la que usó el desarrollador (por ejemplo Java 8 u201 o Java 17 LTS).
- Valida que el usuario «Servicio» (o la cuenta dedicada que vas a emplear) tenga acceso de lectura y ejecución en la carpeta de la aplicación.
Cómo corregir las variables de entorno Java
- Panel de control → Sistema → Configuración avanzada → Variables de entorno.
- Crea o edita JAVAHOME con la ruta del JRE o JDK, p. ej.
C:\Program Files\Java\jre1.8.0401
. - En PATH, añade:
%JAVA_HOME%\bin
(sitúalo antes de otras rutas que incluyan Java). - Abre una nueva ventana de PowerShell y comprueba:
java -version
Si Java responde correctamente y el .jar
corre manualmente, ya puedes envolverlo como servicio.
Enfoques para convertir un .jar
en servicio
Opción | Ventajas | Limitaciones |
---|---|---|
WinSW (Windows Service Wrapper) | No requiere instalación; un exe y un xml Soporta reinicios automáticos, logs rotativos, argumentos complejos | Tiempo de inicio predeterminado 30 s (ajustable) |
NSSM (Non‑Sucking Service Manager) | Interfaz interactiva para crear servicios Permite redirigir stdout/stderr a fichero | Proyecto sin releases formales desde 2018, aunque estable |
sc.exe + ejecutable propio | No dependes de terceros; usa utilidades nativas | Necesitas un wrapper lanzable (Launch4j, JSW, JSL) o un .bat convertido a .exe |
Implementación con WinSW (recomendado)
- Descarga la versión estable de WinSW (x64) y cópiala en la carpeta de la aplicación.
- Renómbrala acorde al servicio:
MiServicio.exe
. - Crea
MiServicio.xml
en la misma carpeta:
<service>
<id>MiServicio</id>
<name>Mi Servicio Java</name>
<description>Ejecuta app.jar como servicio.</description>
<executable>%JAVA_HOME%\bin\java.exe</executable>
<arguments>-jar "C:\Apps\MiAplicacion\app.jar" --spring.profiles.active=prod</arguments>
<logpath>C:\Logs\MiServicio</logpath>
<log mode="roll-by-size">
<sizeThreshold>10MB</sizeThreshold>
<keepFiles>5</keepFiles>
</log>
<onfailure action="restart" delay="10 sec"/>
</service>
- Instala el servicio:
.\MiServicio.exe install
- Configura el arranque automático (opcionalmente retrasado):
sc config MiServicio start= auto sc config MiServicio delayed-auto= yes
- Inícialo y verifica:
net start MiServicio
¿Qué hace WinSW internamente?
Levanta un proceso hijo con java.exe
; captura stdout/stderr; vigila el PID. Si el proceso sale con código distinto de 0, aplica la directiva <onfailure>
.
Implementación con NSSM
- Descarga
nssm.exe
y cópialo, por ejemplo, enC:\NSSM
. - En PowerShell (Admin):
# Crear el servicio
nssm install MiServicio "C:\Program Files\Java\jre1.8.0_401\bin\java.exe" "-jar" "C:\Apps\MiAplicacion\app.jar"
Opciones recomendadas
nssm set MiServicio Start SERVICE\AUTO\START
nssm set MiServicio AppDirectory "C:\Apps\MiAplicacion"
nssm set MiServicio AppStdout "C:\Logs\MiServicio\stdout.log"
nssm set MiServicio AppStderr "C:\Logs\MiServicio\stderr.log"
Iniciar
net start MiServicio
Implementación con sc.exe
+ script .bat
- Crea
launch.bat
:
@echo off
set "JAVAHOME=C:\Program Files\Java\jre1.8.0401"
"%JAVA_HOME%\bin\java.exe" -jar "C:\Apps\MiAplicacion\app.jar"
- Convierte el
.bat
a.exe
con launch4j o similar (require .NET 2 runtime). - Registra el servicio:
sc create MiServicio binPath= "C:\Apps\MiAplicacion\launch.exe" start= auto
Ejecución sin iniciar sesión
Un servicio se inicia en la fase de arranque gestionada por el Service Control Manager (SCM), mucho antes de que un usuario interactúe con la consola. No obstante, debes elegir la cuenta de servicio adecuada:
- LocalSystem: permisos máximos; no recomendado salvo necesidad.
- Servicio local / Servicio de red: suficientes en la mayoría de los casos.
- Cuenta de dominio: imprescindible si accedes a recursos compartidos (UNC) o base de datos con autenticación integrada.
Para cambiarla: services.msc → propiedades → Inicio de sesión o con PowerShell:
Set-Service MiServicio -StartupType Automatic
$cred = New-Object System.Management.Automation.PSCredential ("DOMINIO\svc_java", (ConvertTo-SecureString "Contraseña!" -AsPlainText -Force))
Set-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Services\MiServicio" -Name "ObjectName" -Value $cred.UserName
Contraseña en registro protegido
sc.exe config MiServicio obj= "DOMINIO\svc_java" password= "Contraseña!"
Métodos alternativos al servicio
Tarea programada
- Programador de tareas → Nueva tarea.
- Disparador: «Al iniciar el sistema».
- Acción:
java.exe -jar "C:\Apps\MiAplicacion\app.jar"
. - Marca «Ejecutar con los privilegios más altos».
La ventaja principal es la simplicidad; el inconveniente, la falta de supervisión nativa que sí ofrece el SCM.
Script de inicio de GPO
En entornos de dominio, añade launch.bat
en Computer Configuration → Policies → Windows Settings → Scripts (Startup/Shutdown). Recuerda que el script se ejecuta bajo LocalSystem y solo después de que el equipo se una al dominio.
Habilitar reinicio automático y retención de logs
Wrapper | Configuración | Resultado |
---|---|---|
WinSW | <onfailure action="restart" delay="15 sec"/> | Reintentos ilimitados cada 15 s |
NSSM | nssm set MiServicio AppExit Default Restart | Reinicia al salir con código ≠ 0 |
SCM nativo | sc failure "MiServicio" reset= 30 actions= restart/60000 | Tras 60 s reinicia; cuenta fallos por 30 días |
Seguridad y buenas prácticas
- Prueba siempre el
.jar
en un entorno de preproducción. - Asigna NTFS de solo lectura a la carpeta de la aplicación para el usuario del servicio.
- Ubica los logs fuera de
Program Files
para no requerir privilegios elevados. - Encripta credenciales sensibles con DPAPI o variables de entorno cifradas si tu app las necesita.
- Audita intentos de inicio de sesión fallidos y excepciones NoClassDefFoundError en el log de la JVM.
Checklist de resolución de problemas
- ¿El servicio arranca manualmente desde services.msc?
- Si se detiene, consulta Visor de eventos → Aplicación (filtra por Error).
- Revisa
%SystemRoot%\system32\config\systemprofile\AppData\Local\WinSW
si WinSW no crea los logs donde esperas. - Ejecuta
sc queryex MiServicio
para comprobar el PID y el último código de salida. - Eleva el nivel de log de Java con
-Djava.util.logging.config.file=logging.properties
. - Asegúrate de que no haya puertos ocupados (usa
netstat -ano | findstr :8080
).
Conclusión
El error 0x80004005
al crear un servicio Java en Windows Server 2019 suele deberse a rutas incorrectas o a la ausencia de JAVA_HOME
. Con WinSW o NSSM puedes encapsular tu .jar
en un servicio robusto que se inicia antes de que cualquier usuario inicie sesión, dispone de reinicio automático y genera logs rotativos. Ajustar correctamente las variables de entorno, los permisos NTFS y las opciones de recuperación garantiza que tu aplicación Java permanezca disponible tras cada reinicio del servidor.