Vuoi eseguire un file JAR come servizio su Windows Server 2019 e impedirgli di “avviarsi e poi arrestarsi”? In questa guida pratica trovi diagnosi, cause tipiche e una procedura completa per far partire il tuo XXX.jar
in modo affidabile al boot del server, con log, recupero da errori e configurazioni ottimali.
Scenario e sintomi
Un’applicazione Java impacchettata come XXX.jar
deve rimanere attiva in background senza richiedere login. Il servizio è stato creato con sc create …
(magari puntando a un wrapper) oppure tramite WinSW/NSSM, ma in Servizi compare lo stato “Avviato e poi arrestato”. Nel Visualizzatore eventi si trovano messaggi come:
System.ComponentModel.Win32Exception (0x80004005): The system cannot find the file specified
in winsw.WrapperService...
Questo pattern indica quasi sempre che il processo wrapper riesce a partire, ma fallisce nel lanciare java.exe
o nel raggiungere il JAR/working directory. Di conseguenza Windows considera il servizio terminato.
Perché accade
- Variabile d’ambiente non valida o invisibile: il servizio gira come LocalSystem (o come un account dedicato) e vede solo le variabili di sistema. Se
JAVA_HOME
indica una cartella inesistente (per esempio dopo un aggiornamento/disinstallazione del JDK/JRE), o se è definita solo a livello utente,java.exe
non si trova. - Percorsi e virgolette: path con spazi (es.
C:\Program Files\...
) richiedono virgolette. Insc
la sintassi è pignola: spazi dopo gli=
e corretta citazione del valore dibinPath
. Nei file XML di WinSW/NSSM,<executable>
e<arguments>
vanno riportati con attenzione. - Working directory errata: l’app prova a leggere file relativi che non esistono dal CWD predefinito del servizio. Serve impostare una directory di lavoro.
- Permessi e account: se l’app accede a share di rete (
\\server\share
), LocalSystem potrebbe non bastare; va usato un account di servizio con i diritti appropriati. - Architettura o versione: un JRE a 32 bit in
Program Files (x86)
su server a 64 bit, o unJAVA_HOME
puntato a una versione rimossa, generano “file non trovato”. - Percorsi lunghi: se la lunghezza supera i limiti Win32 e non è abilitato il supporto ai percorsi estesi, il wrapper può non vedere il file.
Soluzione rapida che risolve nella maggior parte dei casi
Impostare JAVA_HOME
e PATH
a livello di sistema, quindi riavviare il servizio.
1. Impostare a livello di sistema:
JAVAHOME = C:\Program Files\Java\jre1.8.0401
PATH = %JAVA_HOME%\bin;%PATH%
2. Riavviare (o eseguire “sc stop / start ”).
3. Impostare il tipo di avvio su “Automatico”.
Nota: sostituisci il percorso con la versione reale presente sul server. Il riavvio del sistema non è obbligatorio; è sufficiente riavviare il servizio (e talvolta il processo wrapper) per far leggere le nuove variabili.
Guida passo passo completa
Verifica dell’installazione Java
Esegui queste verifiche in una console con privilegi elevati:
where java
java -version
Se where
non restituisce un percorso in C:\Program Files\Java\...
(o nella directory del tuo JDK/JRE), significa che PATH
non è configurato oppure JAVA_HOME
è errato.
Impostazione di JAVA_HOME e PATH a livello di sistema
Metodo GUI:
- Apri sysdm.cpl → scheda Avanzate → Variabili d’ambiente.
- Nella sezione Variabili di sistema, crea/modifica
JAVAHOME
con il percorso dell’installazione (es.C:\Program Files\Java\jre1.8.0401
). - Aggiungi
%JAVA_HOME%\bin
all’inizio della variabile di sistemaPath
.
Metodo da prompt (impatta l’intero sistema):
setx JAVAHOME "C:\Program Files\Java\jre1.8.0401" /M
setx PATH "%JAVA_HOME%\bin;%PATH%" /M
Metodo PowerShell:
[Environment]::SetEnvironmentVariable('JAVAHOME','C:\Program Files\Java\jre1.8.0401','Machine')
$cur = [Environment]::GetEnvironmentVariable('PATH','Machine')
[Environment]::SetEnvironmentVariable('PATH',"C:\Program Files\Java\jre1.8.0_401\bin;$cur",'Machine')
Per confermare:
[Environment]::GetEnvironmentVariable('JAVA_HOME','Machine')
[Environment]::GetEnvironmentVariable('PATH','Machine') | Out-String
Creazione del servizio con WinSW
WinSW è un wrapper leggero che espone le API dei servizi Windows e lancia il processo Java. Flusso tipico:
- Posiziona l’eseguibile WinSW in
C:\svc\myapp-service.exe
(rinominando l’eseguibile in base all’ID del servizio). - Nella stessa cartella, crea
myapp-service.xml
con il seguente contenuto base:
<service>
<id>myapp-service</id>
<name>My Java Service</name>
<description>Esecuzione dell'applicazione XXX.jar come servizio.</description>
%JAVA_HOME%\bin\java.exe
-Xms512m -Xmx512m -Dfile.encoding=UTF-8 -jar "C:\app\XXX.jar"
C:\app
C:\app\logs
10485760
8
20 sec
Installa e configura:
C:\svc\myapp-service.exe install
sc config myapp-service start= auto
sc start myapp-service
Vantaggi: variabili d’ambiente dichiarabili nel file, log rolling integrato, recupero da errori, working directory esplicita.
Creazione del servizio con NSSM
NSSM (Non-Sucking Service Manager) è un altro wrapper robusto. Procedura CLI tipica:
nssm install MyJavaService "C:\Program Files\Java\jre1.8.0_401\bin\java.exe" ^
"-Xms512m -Xmx512m -jar C:\app\XXX.jar"
nssm set MyJavaService AppDirectory "C:\app"
nssm set MyJavaService AppStdout "C:\app\logs\stdout.log"
nssm set MyJavaService AppStderr "C:\app\logs\stderr.log"
nssm set MyJavaService Start SERVICEAUTOSTART
nssm start MyJavaService
NSSM semplifica l’impostazione della directory di lavoro e dei log standard senza file XML.
Registrazione con sc puntando al wrapper
Se preferisci usare sc
direttamente per la registrazione, punta il binPath
al wrapper (WinSW/NSSM), non a java.exe
:
sc create myapp-service binPath= "C:\svc\myapp-service.exe" DisplayName= "My Java Service" start= auto
sc description myapp-service "Esegue XXX.jar con Java al boot del server"
sc start myapp-service
Attenzione alla sintassi: in sc
serve lo spazio dopo =
, e i percorsi con spazi vanno sempre tra virgolette.
Configurazione del recupero automatico
Per riavviare il servizio su crash:
sc failure myapp-service reset= 86400 actions= restart/5000/restart/5000/restart/5000
In alternativa, in services.msc → proprietà del servizio → scheda Recupero, imposta Riavvia il servizio ai primi eventi di errore.
Account del servizio, permessi e accesso a rete
- Per accesso a share SMB, database o risorse di dominio, esegui con un account di servizio dedicato (locale o di dominio) con permessi minimi necessari.
- Configura dal wrapper o con
sc config
:sc config myapp-service obj= "DOMINIO\svc-java" password= "PasswordSicura"
- Valuta “Load User Profile” (NSSM) se l’app salva dati in profilo utente.
Diagnostica approfondita
Quando il servizio “parte e si ferma”:
- Controlla i log del wrapper nella cartella del servizio (
winSW
genera file*.log
inlogpath
o a fianco dell’eseguibile). - Event Viewer → Registri di Windows → Applicazione e Sistema. Cerca origine WinSW o Service Control Manager.
- Verifica i percorsi:
Test-Path "C:\Program Files\Java\jre1.8.0_401\bin\java.exe" Test-Path "C:\app\XXX.jar" icacls "C:\app" /T
- Working directory: se l’app usa file relativi, assicurati che
<workingdirectory>
(WinSW) o AppDirectory (NSSM) sia impostata suC:\app
. - Percorsi lunghi: se sospetti limiti, abilita i long paths tramite Criteri di gruppo o con il valore
LongPathsEnabled=1
inHKLM\SYSTEM\CurrentControlSet\Control\FileSystem
. - Architettura: preferisci JRE/JDK a 64 bit su OS a 64 bit e verifica che il percorso non punti a
Program Files (x86)
se non necessario.
Alternative utili
Obiettivo | Strumento consigliato | Passaggi chiave |
---|---|---|
Creare/gestire il servizio in modo più semplice | WinSW o NSSM | Scaricare l’eseguibile → definire myapp.xml : <executable>%JAVA_HOME%\bin\java.exe</executable> , <arguments>-jar C:\app\XXX.jar</arguments> → winsw install → avvio Automatico. |
Avvio senza servizio | Task Scheduler | Nuova attività → trigger At system startup → comando java -jar C:\app\XXX.jar → Run whether user is logged on or not. |
Buone pratiche da adottare
- Log applicativi: indirizza
stdout
/stderr
su file dedicati. Con WinSW:<logpath>C:\app\logs</logpath> <log mode="roll-by-size">...</log>
Con NSSM usa AppStdout e AppStderr. - Verifica post-aggiornamento Java: dopo update o disinstallazione, ricontrolla
JAVA_HOME
,PATH
e i percorsi in WinSW/NSSM. - Recupero da errori: in Proprietà del servizio → Recupero imposta Riavvia il servizio per garantire ripartenza in caso di crash.
- Impostazioni JVM: definisci
-Xms
,-Xmx
,-Dfile.encoding=UTF-8
,-Duser.timezone=Europe/Rome
se utile. Evita valori di heap eccessivi che potrebbero impedire l’avvio. - Dipendenze: se la tua app richiede un database o un servizio di rete, imposta le dipendenze per evitare partenze premature:
sc config myapp-service depend= Tcpip
- Sicurezza: assegna permessi NTFS minimi all’account del servizio sulla cartella
C:\app
e sui log; evita di eseguire come amministratore se non necessario. - Backup dei file di configurazione: includi
myapp-service.xml
o l’export della configurazione NSSM nel tuo sistema di versionamento.
Checklist rapida prima della messa in produzione
- JAVA_HOME e PATH definiti a livello Machine.
- WinSW/NSSM configurato con
<executable>
che punta ajava.exe
e<arguments>
con-jar
e il percorso assoluto del JAR. - Working directory impostata su
C:\app
o cartella equivalente. - Log in output su file con rotazione attiva.
- Avvio automatico e recupero configurati.
- Account servizio corretto e permessi minimi necessari.
- Test di avvio, arresto e riavvio con
sc start/stop
e verifica dei log.
Domande frequenti
Posso creare un servizio puntando direttamente a java.exe -jar
con sc create
?
È sconsigliato: un processo generico non implementa le API dei servizi Windows e potrebbe non rispondere correttamente ai segnali di stop. Usa un wrapper (WinSW, NSSM, Procrun) o un Java Service Wrapper dedicato.
Devo riavviare il server dopo aver cambiato JAVA_HOME
?
Non necessariamente: in genere basta riavviare il servizio. Se il wrapper rimane residente con vecchie variabili, riavvia anche il wrapper o il sistema.
Come faccio a verificare le variabili viste dal servizio?
Imposta temporaneamente, nel wrapper, la stampa delle variabili all’avvio o scrivi uno script che stampi %JAVA_HOME%
/%PATH%
e lanciarlo come executable
per un test. Con WinSW puoi definire <env>
nel file XML per bypassare eventuali incongruenze di sistema.
La mia app usa file relativi: perché non li trova?
Perché la directory di lavoro del servizio differisce dalla tua shell interattiva. Imposta <workingdirectory>
(WinSW) o AppDirectory (NSSM) per allinearla.
Template pronti all’uso
File XML WinSW minimale
<service>
<id>myapp-service</id>
<name>My Java Service</name>
<executable>%JAVA_HOME%\bin\java.exe</executable>
<arguments>-jar "C:\app\XXX.jar"</arguments>
<workingdirectory>C:\app</workingdirectory>
<logpath>C:\app\logs</logpath>
<onfailure action="restart" delay="5 sec"/>
</service>
Script di configurazione rapida con PowerShell
# Percorsi
$Jre = "C:\Program Files\Java\jre1.8.0_401"
$App = "C:\app\XXX.jar"
$SvcDir = "C:\svc"
$SvcId = "myapp-service"
Variabili di sistema
[Environment]: :SetEnvironmentVariable\('JAVA_HOME',$Jre,'Machine'\)
$cur = [Environment]::GetEnvironmentVariable('PATH','Machine')
if ($cur -notlike "$Jre\bin") {
[Environment]::SetEnvironmentVariable('PATH',"$Jre\bin;$cur",'Machine')
}
File XML WinSW
$xml = @"
$SvcId
My Java Service
%JAVA_HOME%\bin\java.exe
-Xms512m -Xmx512m -jar "$App"
$(Split-Path $App)
$(Split-Path $App)\logs
"@
$xml | Out-File -FilePath "$SvcDir$SvcId.xml" -Encoding UTF8
Registrazione e avvio
& "$SvcDir$SvcId.exe" install
sc.exe config $SvcId start= auto | Out-Null
sc.exe start $SvcId | Out-Null
Write-Host "Servizio $SvcId installato e avviato."
Comandi di amministrazione utili
# Stato e configurazione
sc query myapp-service
sc qc myapp-service
Avvio/stop/riavvio
sc stop myapp-service
sc start myapp-service
Recupero su errori
sc failure myapp-service reset= 86400 actions= restart/5000/restart/5000/restart/5000
Dipendenze
sc config myapp-service depend= Tcpip
Esecuzione con account di servizio
sc config myapp-service obj= "DOMINIO\svc-java" password= "PasswordSicura"
Casi reali e soluzioni
Errore “The system cannot find the file specified” in WinSW: quasi sempre JAVAHOME
o il percorso del JAR non esistono nel contesto del servizio. Imposta <env name="JAVAHOME" ... />
nel file XML e usa percorsi assoluti per arguments
. Verifica con Test-Path
.
Servizio che si ferma subito senza errori nei log: il processo Java esce per eccezione non catturata o per configurazione mancante. Abilita stdout/stderr
su file, aumenta il livello di log dell’app, verifica credenziali di database/porte bindate.
Configurazione OK ma l’app non vede i certificati/keystore: specifica il keystore con parametri JVM nel wrapper:
-Djavax.net.ssl.keyStore="C:\app\cert\keystore.jks" -Djavax.net.ssl.keyStorePassword=
e assicurati che l’account abbia permessi di lettura.
Conclusioni
La chiave per eseguire un JAR come servizio su Windows Server 2019 è separare le responsabilità: il wrapper parla con il Service Control Manager, mentre Java esegue l’app. Con variabili d’ambiente corrette, percorsi assoluti e una directory di lavoro definita, il servizio risulta affidabile, si avvia al boot e si riprende automaticamente in caso di guasto. Le procedure e i template sopra ti permettono di passare da “avviato e poi arrestato” a una esecuzione stabile e osservabile in produzione.
Riepilogo delle azioni essenziali
- Definisci
JAVA_HOME
e aggiornaPATH
a livello di sistema. - Usa WinSW o NSSM per creare un vero servizio Windows per il tuo JAR.
- Imposta working directory, log a file e recovery automatico.
- Se necessario, esegui con un account di servizio con i permessi minimi.
- Verifica con
where java
,java -version
e i log del wrapper.
Seguendo questi passaggi, il tuo XXX.jar
si avvierà regolarmente anche senza login utente.