Quer rodar um .jar como serviço no Windows Server 2019 e evitar a mensagem “o serviço iniciou e parou”? Veja um guia prático, com passo a passo, exemplos de WinSW, NSSM e sc.exe
, além da correção definitiva do erro causado por JAVA_HOME
incorreto.
Visão geral do problema
O cenário típico: você tem um aplicativo Java que inicia sem dificuldades com java -jar XXXX.jar
a partir de um prompt ou de um script de logon. Porém, ao registrá-lo como serviço — seja via SC.exe, WinSW (Windows Service Wrapper) ou NSSM — o serviço aparece, mas ao clicar em “Iniciar” no console de Serviços ele exibe “o serviço iniciou e parou”. No Log de Eventos surge a exceção:
System.ComponentModel.Win32Exception (0x80004005): The system cannot find the file specified
Além disso, você precisa que o serviço suba mesmo sem logon de usuário. A boa notícia: isso tem conserto. A causa mais comum é um erro de ambiente do Java carregado pelo contexto de serviço, normalmente uma referência inválida a JAVAHOME
ou a ausência de %JAVAHOME%\bin
no PATH
do Machine.
Solução principal: ajuste do ambiente Java do sistema
Quando um serviço inicia, ele roda em Session 0, com um conjunto de variáveis de ambiente próprio (o “ambiente do serviço”), que não é o mesmo da sua sessão interativa. Se JAVA_HOME
estiver errado, vazio ou definido apenas no perfil do usuário, o wrapper não encontrará java.exe
, gerando o erro acima.
Como corrigir
- Defina
JAVA_HOME
no nível do sistema para o JDK/JRE válido 64‑bit. Exemplo:C:\Program Files\Java\jdk-17.0.9
- ou
C:\Program Files\Java\jre-17
(se usar apenas JRE)
- Acrescente
%JAVA_HOME%\bin
aoPATH
(Sistema). - Reinicie o serviço (ou o servidor) para garantir que o contexto do serviço recarregue as variáveis de ambiente.
Passo a passo (GUI)
- Abrir System Properties → Advanced → Environment Variables….
- Em System variables, criar/editar:
JAVA_HOME
=C:\Program Files\Java\jdk-17.0.9
PATH
=...;%JAVA_HOME%\bin
(não remova entradas existentes).
- Confirmar e fechar. Reiniciar o serviço (ou o Windows) para aplicar ao contexto do serviço.
Passo a passo (PowerShell, recomendado para servidores)
# Execute em uma janela do PowerShell elevada (Administrador)
$jdk = 'C:\Program Files\Java\jdk-17.0.9'
[System.Environment]::SetEnvironmentVariable('JAVA_HOME', $jdk, 'Machine')
Acrescenta %JAVA\_HOME%\bin ao PATH do sistema se ainda não estiver presente
\$path = \[System.Environment]::GetEnvironmentVariable('Path','Machine')
if (\$path -notmatch '%JAVA\_HOME%\bin') {
\$newPath = \$path.TrimEnd(';') + ';%JAVA\_HOME%\bin'
\[System.Environment]::SetEnvironmentVariable('Path', \$newPath, 'Machine')
}
Reinicie o serviço (substitua pelo nome do seu serviço)
Restart-Service -Name 'MinhaAppJava' -ErrorAction SilentlyContinue
Por que funciona no prompt e falha como serviço?
Quando você testa manualmente, o shell herda as variáveis do seu perfil e da sessão atual (onde JAVAHOME
e PATH
costumam estar corretos). O serviço, entretanto, roda com outra conta (frequentemente Local System ou uma conta de serviço) e outra árvore de ambiente. Se o wrapper tenta executar java
sem caminho absoluto e o PATH
do sistema não aponta para o %JAVAHOME%\bin
, o Windows retorna “The system cannot find the file specified”.
Como criar o serviço corretamente
Você tem três abordagens principais. Todas funcionam, mas cada uma tem seus prós e contras.
Solução | Como funciona | Vantagens | Cuidados |
---|---|---|---|
WinSW | Wrapper nativo que transforma qualquer executável/linha de comando em serviço. Configuração via XML. | Leve, estável, logging integrado e políticas de reinício. | Manter .exe e .xml com o mesmo nome e pasta. |
NSSM | “O serviço não confiável mais bacana” — GUI/CLI que instala seu comando como serviço. | Muito simples; excelente para configurar diretório de trabalho e redirecionamento de stdout/stderr. | Distribua o binário do NSSM junto; defina variáveis de ambiente explícitas. |
SC.exe + wrapper | Cria a entrada de serviço apontando para um wrapper (WinSW, srvany) já preparado. | Sem ferramentas extras além do Windows; scriptável. | Não tente apontar diretamente para java.exe ; serviços exigem um processo que fale com o SCM. |
Exemplo com WinSW (recomendado)
- Copie o binário do WinSW (ex.:
MinhaApp.exe
) e crie ao lado o arquivoMinhaApp.xml
. - No
MinhaApp.xml
, configure:
<service>
<id>MinhaAppJava</id>
<name>Minha App Java</name>
<description>Serviço Windows que executa o JAR MinhaApp</description>
\%JAVA\_HOME%\bin\java.exe\
\-jar "C:\apps\minhaapp\minhaapp.jar" --server.port=8080\
\C:\apps\minhaapp\
\
\C:\apps\minhaapp\logs\
\\
\
\
\
\
- Instale o serviço executando (elevado)
MinhaApp.exe install
. - Abra services.msc → defina Startup type = Automatic (ou Automatic (Delayed Start)).
- Inicie o serviço e verifique os logs na pasta definida em
<logpath>
.
Exemplo com NSSM
# Instala o serviço apontando para java.exe e o .jar
nssm install MinhaAppJava "C:\Program Files\Java\jdk-17.0.9\bin\java.exe" ^
-jar "C:\apps\minhaapp\minhaapp.jar" --server.port=8080
Diretório de trabalho (evita problemas com paths relativos)
nssm set MinhaAppJava AppDirectory "C:\apps\minhaapp"
Variáveis de ambiente adicionais (garantir JAVA\_HOME no contexto do serviço)
nssm set MinhaAppJava AppEnvironmentExtra "JAVA\_HOME=C:\Program Files\Java\jdk-17.0.9"
Saída de logs
nssm set MinhaAppJava AppStdout "C:\apps\minhaapp\logs\stdout.log"
nssm set MinhaAppJava AppStderr "C:\apps\minhaapp\logs\stderr.log"
Política de reinício e início automático
nssm set MinhaAppJava AppExit Default Restart
nssm set MinhaAppJava Start SERVICE\AUTO\START
Iniciar
nssm start MinhaAppJava
Usando SC.exe com wrapper
Se preferir sc.exe
, aponte o binPath=
para o wrapper (por exemplo, o WinSW.exe
) e não para o java.exe
diretamente:
sc.exe create MinhaAppJava binPath= "C:\apps\minhaapp\MinhaApp.exe" start= auto
sc.exe description MinhaAppJava "Serviço do JAR MinhaApp via WinSW"
sc.exe failure MinhaAppJava reset= 86400 actions= restart/5000/restart/5000/restart/5000
Observação: com WinSW é mais limpo instalar com MinhaApp.exe install
, pois o wrapper cria as chaves adequadas sozinho.
Boas práticas essenciais
- Caminhos com espaços: sempre use aspas duplas. Ex.:
"C:\Program Files\Java\jdk-17.0.9\bin\java.exe"
. - Working Directory: defina o diretório de trabalho para a pasta do aplicativo, evitando erros com arquivos relativos.
- Conta de serviço: se o JAR acessa rede, configure o serviço para rodar com uma conta que tenha permissão nos recursos (evite unidades mapeadas; prefira caminhos UNC
\\servidor\share\pasta
). - Logs: habilite logs do wrapper (WinSW
<logpath>
, NSSMAppStdout/AppStderr
). Use rotação. - Recuperação: configure restart on failure (WinSW
<onfailure>
ousc.exe failure
). - Inicialização sem logon: tipo de inicialização Automático e Automatic (Delayed Start) para dar tempo a dependências de rede.
- Arquitetura: use JDK 64‑bit em Windows Server 64‑bit (
C:\Program Files\Java\
). Evite misturar com instalações em(x86)
. - Segurança: mantenha o JDK atualizado, restrinja permissões da pasta da app e da conta de serviço (princípio do menor privilégio).
Diagnóstico rápido
Quando o serviço “inicia e para”, rode este checklist:
Verificação | Comando | O que esperar |
---|---|---|
JAVA_HOME do sistema | reg query "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v JAVA_HOME | Caminho válido de JDK/JRE. |
PATH inclui %JAVA_HOME%\bin | reg query ... /v Path e procure por %JAVA_HOME%\bin | Presente uma única vez. |
Local do java.exe | where java | Resolve para %JAVA_HOME%\bin\java.exe . |
Variáveis vistas pelo serviço | Adicione no wrapper: cmd /c set > env.txt (temporário) | Arquivo com variáveis reais do contexto do serviço. |
Evento de falha | eventvwr.msc → Windows Logs → Application/System | Stack trace/Win32Exception indica o caminho problemático. |
Erros comuns e suas correções
- “The system cannot find the file specified”: quase sempre
JAVAHOME
errado ouPATH
sem%JAVAHOME%\bin
. Ajuste e reinicie o serviço. - Funciona manualmente, mas não como serviço: uso de unidades mapeadas (X:, Z:). Use UNC (
\\srv\share
) e garanta permissões da conta do serviço. - Tempo de inicialização longo (“não respondeu em tempo hábil”): aumente
ServicesPipeTimeout
e/ou use Delayed Start e dependências de serviço. - Conflito de versões do Java: múltiplos JDKs instalados; remova os não usados e certifique-se de que o caminho ativo é o correto.
- Arquivo .jar não encontrado: paths relativos; configure
workingdirectory
e use caminhos absolutos com aspas.
Checklist final (antes de subir para produção)
Item | Sim | Observações |
---|---|---|
JAVA_HOME aponta para JDK/JRE 64‑bit correto | ✅ | |
%JAVA_HOME%\bin no PATH do sistema | ✅ | |
Wrapper configurado (WinSW/NSSM) | ✅ | Com workingdirectory , logs e reinício em falha. |
Conta de serviço e permissões de rede | ✅ | Sem unidades mapeadas, somente UNC. |
Inicialização automática (Delayed Start se necessário) | ✅ | |
Verificação dos eventos e logs do wrapper | ✅ | Sem erros residuais. |
Exemplo completo de instalação automatizada (PowerShell)
O script abaixo instala um JDK, define variáveis de ambiente, gera um MinhaApp.xml
do WinSW e instala o serviço. Adapte os caminhos conforme sua realidade.
# Parâmetros
$AppDir = 'C:\apps\minhaapp'
$Jar = 'minhaapp.jar'
$LogDir = Join-Path $AppDir 'logs'
$WinSWExe = Join-Path $AppDir 'MinhaApp.exe'
$WinSWXml = Join-Path $AppDir 'MinhaApp.xml'
$JdkHome = 'C:\Program Files\Java\jdk-17.0.9'
$ServiceId = 'MinhaAppJava'
Pastas
New-Item -ItemType Directory -Path \$AppDir,\$LogDir -Force | Out-Null
Variáveis de ambiente do sistema
\[Environment]::SetEnvironmentVariable('JAVA\_HOME', \$JdkHome, 'Machine')
\$path = \[Environment]::GetEnvironmentVariable('Path','Machine')
if (\$path -notmatch '%JAVA\_HOME%\bin') {
\[Environment]::SetEnvironmentVariable('Path', (\$path.TrimEnd(';') + ';%JAVA\_HOME%\bin'), 'Machine')
}
Gera o XML do WinSW
@"
\
\\$ServiceId\
\Minha App Java\
\Serviço Windows que executa \$Jar\
\%JAVA\_HOME%\bin\java.exe\
\-jar "\$AppDir\$Jar" --server.port=8080\
\\$AppDir\
\
\\$LogDir\
\
\
\
\
\
"@ | Set-Content -Path \$WinSWXml -Encoding UTF8
Copie o WinSW\.exe pré-baixado para \$WinSWExe antes de rodar a linha abaixo
& \$WinSWExe install
Início automático e start do serviço
Set-Service -Name \$ServiceId -StartupType Automatic
Start-Service -Name \$ServiceId
FAQ rápida
Posso evitar depender de JAVA_HOME
? Sim: aponte diretamente para java.exe
no wrapper (C:\Program Files\Java\jdk-17.0.9\bin\java.exe
). Isso elimina a dependência do PATH
, mas reduz a flexibilidade para upgrades do JDK.
Como garantir que inicia sem logon? Serviços configurados como Automatic sob uma conta válida (Local System ou conta de serviço com “Log on as a service”) iniciam no boot independentemente de sessão de usuário.
Meu serviço para logo após iniciar, mas sem erro claro. Verifique se o seu .jar não finaliza por si só (ex.: modo CLI que executa e encerra). Serviços devem executar em modo daemon, com thread principal bloqueando; ajuste a aplicação ou os parâmetros.
Como lidar com portas ocupadas? Se a aplicação usa HTTP/Socket, confirme que a porta está livre (netstat -ano | findstr :8080
). Ajuste o parâmetro --server.port
ou libere a porta.
Resumo prático do caso real
O solicitante criou o serviço via SC.exe e também testou com WinSW. O serviço “iniciava e parava”, registrando a exceção Win32Exception (0x80004005): “The system cannot find the file specified”. Em execução manual (java -jar
) funcionava; como serviço, falhava. A causa raiz foi um JAVA_HOME
apontando para um local inválido no contexto de máquina. A correção consistiu em:
- Definir
JAVA_HOME
para o JDK correto (C:\Program Files\Java\jdk-17.0.9
). - Adicionar
%JAVA_HOME%\bin
aoPATH
do sistema. - Reiniciar o serviço/servidor.
Depois disso, o serviço passou a iniciar e permaneceu em execução a cada boot, sem depender de logon de usuário.
Tabela de orientação rápida
Tópico | Recomendações práticas |
---|---|
Criação do serviço | Use WinSW ou NSSM; caso use SC.exe, aponte para o wrapper (não para java.exe). Defina -jar e workingdirectory corretamente. |
Paths com espaços | Sempre encapsule em aspas: "C:\Program Files\..." . |
Múltiplas versões do Java | Mantenha apenas a versão necessária ou aponte explicitamente para a desejada; evite conflitos. |
Início automático sem logon | Startup Automatic ou Automatic (Delayed Start). Alternativa corporativa: script de Startup via GPO (Computer Configuration → Windows Settings → Scripts → Startup). |
Conta de serviço | Se o JAR acessa rede, use uma conta com as permissões adequadas e caminhos UNC. |
Diagnóstico | Habilite logs no wrapper; teste o comando exato; verifique eventvwr.msc ; expanda %JAVA_HOME% para validar. |
Boas práticas de produção
- Rotina de atualização do JDK: teste em homologação, ajuste
JAVA_HOME
e validejava -version
no contexto do serviço. - Backups e retenção de logs: configure rotação para evitar discos cheios (WinSW
roll
com limite). - Monitoramento: exponha health checks (se a app suportar) e conecte a um monitor externo (Zabbix, Prometheus, etc.).
- Dependências: declare dependências de serviço (ex.: “TCP/IP”, “DNS Client”) quando necessário para garantir a ordem de início.
- Hardening: limite permissões NTFS da pasta da app; evite rodar como Administrador se não for estritamente necessário.
Conclusão
Executar um .jar como serviço no Windows Server 2019 é simples quando o ambiente está correto. O problema “inicia e para” com a exceção Win32Exception (0x80004005) quase sempre se resolve ao corrigir JAVAHOME
e garantir %JAVAHOME%\bin
no PATH
do sistema. Com um wrapper sólido (WinSW/NSSM), logs habilitados, conta de serviço adequada e políticas de recuperação, seu serviço Java fica estável, inicia no boot e não depende de sessão de usuário — exatamente como um serviço de produção deve ser.