Executar .JAR como serviço no Windows Server 2019: corrigindo “The system cannot find the file specified” (WinSW, NSSM e SC.exe)

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.

Índice

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

  1. 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)
  2. Acrescente %JAVA_HOME%\bin ao PATH (Sistema).
  3. 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)

  1. Abrir System PropertiesAdvancedEnvironment Variables….
  2. Em System variables, criar/editar:
    • JAVA_HOME = C:\Program Files\Java\jdk-17.0.9
    • PATH = ...;%JAVA_HOME%\bin (não remova entradas existentes).
  3. 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çãoComo funcionaVantagensCuidados
WinSWWrapper 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 + wrapperCria 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)

  1. Copie o binário do WinSW (ex.: MinhaApp.exe) e crie ao lado o arquivo MinhaApp.xml.
  2. 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\
\\

\
\
\
\ 
  1. Instale o serviço executando (elevado) MinhaApp.exe install.
  2. Abra services.msc → defina Startup type = Automatic (ou Automatic (Delayed Start)).
  3. 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>, NSSM AppStdout/AppStderr). Use rotação.
  • Recuperação: configure restart on failure (WinSW <onfailure> ou sc.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çãoComandoO que esperar
JAVA_HOME do sistemareg query "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v JAVA_HOMECaminho válido de JDK/JRE.
PATH inclui %JAVA_HOME%\binreg query ... /v Path e procure por %JAVA_HOME%\binPresente uma única vez.
Local do java.exewhere javaResolve para %JAVA_HOME%\bin\java.exe.
Variáveis vistas pelo serviçoAdicione no wrapper: cmd /c set > env.txt (temporário)Arquivo com variáveis reais do contexto do serviço.
Evento de falhaeventvwr.msc → Windows Logs → Application/SystemStack trace/Win32Exception indica o caminho problemático.

Erros comuns e suas correções

  • “The system cannot find the file specified”: quase sempre JAVAHOME errado ou PATH 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)

ItemSimObservaçõ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 redeSem unidades mapeadas, somente UNC.
Inicialização automática (Delayed Start se necessário)
Verificação dos eventos e logs do wrapperSem 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:

  1. Definir JAVA_HOME para o JDK correto (C:\Program Files\Java\jdk-17.0.9).
  2. Adicionar %JAVA_HOME%\bin ao PATH do sistema.
  3. 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ópicoRecomendações práticas
Criação do serviçoUse WinSW ou NSSM; caso use SC.exe, aponte para o wrapper (não para java.exe). Defina -jar e workingdirectory corretamente.
Paths com espaçosSempre encapsule em aspas: "C:\Program Files\...".
Múltiplas versões do JavaMantenha apenas a versão necessária ou aponte explicitamente para a desejada; evite conflitos.
Início automático sem logonStartup Automatic ou Automatic (Delayed Start). Alternativa corporativa: script de Startup via GPO (Computer Configuration → Windows Settings → Scripts → Startup).
Conta de serviçoSe o JAR acessa rede, use uma conta com as permissões adequadas e caminhos UNC.
DiagnósticoHabilite 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 valide java -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.

Índice