Spring Boot application as a Service
Solution 1
The following works for springboot 1.3 and above:
As init.d service
The executable jar has the usual start, stop, restart, and status commands. It will also set up a PID file in the usual /var/run directory and logging in the usual /var/log directory by default.
You just need to symlink your jar into /etc/init.d like so
sudo link -s /var/myapp/myapp.jar /etc/init.d/myapp
OR
sudo ln -s ~/myproject/build/libs/myapp-1.0.jar /etc/init.d/myapp_servicename
After that you can do the usual
/etc/init.d/myapp start
Then setup a link in whichever runlevel you want the app to start/stop in on boot if so desired.
As a systemd service
To run a Spring Boot application installed in var/myapp you can add the following script in /etc/systemd/system/myapp.service:
[Unit]
Description=myapp
After=syslog.target
[Service]
ExecStart=/var/myapp/myapp.jar
[Install]
WantedBy=multi-user.target
NB: in case you are using this method, do not forget to make the jar file itself executable (with chmod +x) otherwise it will fail with error "Permission denied".
Reference
Solution 2
What follows is the easiest way to install a Java application as system service in Linux.
Let's assume you are using systemd
(which any modern distro nowadays does):
Firstly, create a service file in /etc/systemd/system
named e.g. javaservice.service
with this content:
[Unit]
Description=Java Service
[Service]
User=nobody
# The configuration file application.properties should be here:
WorkingDirectory=/data
ExecStart=/usr/bin/java -Xmx256m -jar application.jar --server.port=8081
SuccessExitStatus=143
TimeoutStopSec=10
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
Secondly, notify systemd
of the new service file:
systemctl daemon-reload
and enable it, so it runs on boot:
systemctl enable javaservice.service
Eventually, you can use the following commands to start/stop your new service:
systemctl start javaservice
systemctl stop javaservice
systemctl restart javaservice
systemctl status javaservice
Provided you are using systemd
, this is the most non-intrusive and clean way to set up a Java application as system-service.
What I like especially about this solution is the fact that you don't need to install and configure any other software. The shipped systemd
does all the work for you, and your service behaves like any other system service. I use it in production for a while now, on various distros, and it just works as you would expect.
Another plus is that, by using /usr/bin/java
, you can easily add jvm
paramters such as -Xmx256m
.
Also read the systemd
part in the official Spring Boot documentation:
http://docs.spring.io/spring-boot/docs/current/reference/html/deployment-install.html
Solution 3
You could also use supervisord which is a very handy daemon, which can be used to easily control services. These services are defined by simple configuration files defining what to execute with which user in which directory and so forth, there are a zillion options. supervisord has a very simple syntax, so it makes a very good alternative to writing SysV init scripts.
Here a simple supervisord configuration file for the program you are trying to run/control. (put this into /etc/supervisor/conf.d/yourapp.conf)
/etc/supervisor/conf.d/yourapp.conf
[program:yourapp]
command=/usr/bin/java -jar /path/to/application.jar
user=usertorun
autostart=true
autorestart=true
startsecs=10
startretries=3
stdout_logfile=/var/log/yourapp-stdout.log
stderr_logfile=/var/log/yourapp-stderr.log
To control the application you would need to execute supervisorctl, which will present you with a prompt where you could start, stop, status yourapp.
CLI
# sudo supervisorctl
yourapp RUNNING pid 123123, uptime 1 day, 15:00:00
supervisor> stop yourapp
supervisor> start yourapp
If the supervisord
daemon is already running and you've added the configuration for your serivce without restarting the daemon you can simply do a reread
and update
command in the supervisorctl
shell.
This really gives you all the flexibilites you would have using SysV Init scripts, but easy to use and control. Take a look at the documentation.
Solution 4
I just got around to doing this myself, so the following is where I am so far in terms of a CentOS init.d service controller script. It's working quite nicely so far, but I'm no leet Bash hacker, so I'm sure there's room for improvement, so thoughts on improving it are welcome.
First of all, I have a short config script /data/svcmgmt/conf/my-spring-boot-api.sh
for each service, which sets up environment variables.
#!/bin/bash
export JAVA_HOME=/opt/jdk1.8.0_05/jre
export APP_HOME=/data/apps/my-spring-boot-api
export APP_NAME=my-spring-boot-api
export APP_PORT=40001
I'm using CentOS, so to ensure that my services are started after a server restart, I have a service control script in /etc/init.d/my-spring-boot-api
:
#!/bin/bash
# description: my-spring-boot-api start stop restart
# processname: my-spring-boot-api
# chkconfig: 234 20 80
. /data/svcmgmt/conf/my-spring-boot-api.sh
/data/svcmgmt/bin/spring-boot-service.sh $1
exit 0
As you can see, that calls the initial config script to set up environment variables and then calls a shared script which I use for restarting all of my Spring Boot services. That shared script is where the meat of it all can be found:
#!/bin/bash
echo "Service [$APP_NAME] - [$1]"
echo " JAVA_HOME=$JAVA_HOME"
echo " APP_HOME=$APP_HOME"
echo " APP_NAME=$APP_NAME"
echo " APP_PORT=$APP_PORT"
function start {
if pkill -0 -f $APP_NAME.jar > /dev/null 2>&1
then
echo "Service [$APP_NAME] is already running. Ignoring startup request."
exit 1
fi
echo "Starting application..."
nohup $JAVA_HOME/bin/java -jar $APP_HOME/$APP_NAME.jar \
--spring.config.location=file:$APP_HOME/config/ \
< /dev/null > $APP_HOME/logs/app.log 2>&1 &
}
function stop {
if ! pkill -0 -f $APP_NAME.jar > /dev/null 2>&1
then
echo "Service [$APP_NAME] is not running. Ignoring shutdown request."
exit 1
fi
# First, we will try to trigger a controlled shutdown using
# spring-boot-actuator
curl -X POST http://localhost:$APP_PORT/shutdown < /dev/null > /dev/null 2>&1
# Wait until the server process has shut down
attempts=0
while pkill -0 -f $APP_NAME.jar > /dev/null 2>&1
do
attempts=$[$attempts + 1]
if [ $attempts -gt 5 ]
then
# We have waited too long. Kill it.
pkill -f $APP_NAME.jar > /dev/null 2>&1
fi
sleep 1s
done
}
case $1 in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
esac
exit 0
When stopping, it will attempt to use Spring Boot Actuator to perform a controlled shutdown. However, in case Actuator is not configured or fails to shut down within a reasonable time frame (I give it 5 seconds, which is a bit short really), the process will be killed.
Also, the script makes the assumption that the java process running the appllication will be the only one with "my-spring-boot-api.jar" in the text of the process details. This is a safe assumption in my environment and means that I don't need to keep track of PIDs.
Solution 5
If you want to use Spring Boot 1.2.5 with Spring Boot Maven Plugin 1.3.0.M2, here's out solution:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.5.RELEASE</version>
</parent>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.3.0.M2</version>
<configuration>
<executable>true</executable>
</configuration>
</plugin>
</plugins>
</build>
<pluginRepositories>
<pluginRepository>
<id>spring-libs-milestones</id>
<url>http://repo.spring.io/libs-milestone</url>
</pluginRepository>
</pluginRepositories>
Then compile as ususal: mvn clean package
, make a symlink ln -s /.../myapp.jar /etc/init.d/myapp
, make it executable chmod +x /etc/init.d/myapp
and start it service myapp start
(with Ubuntu Server)
Related videos on Youtube
MariuszS
Devskiller - Powerful tool to test developers’ skills
Updated on November 01, 2021Comments
-
MariuszS over 2 years
How to configure nicely Spring Boot application packaged as executable jar as a Service in the Linux system? Is this recommended approach, or should I convert this app to war and install it into Tomcat?
Currently, I can run Spring boot application from the
screen
session, which is nice but requires manual start after a server reboot.What I'm looking for is general advice/direction or sample
init.d
the script, if my approach with executable jar is proper.-
yglodt over 10 yearsTo get started, does your distribution use upstart or systemd ?
-
Dan Torrey over 9 yearsCheck this out github.com/rburgst/spring-boot-initscript/blob/master/…
-
Raja Anbazhagan about 3 years
-
-
MariuszS almost 10 yearsUnfortunately systemd is not available for Centos 6
-
mist about 9 yearshow does it know how to stop it? Records the pid and then kills it?
-
MariuszS almost 9 yearsThanks, it is also possible to install as a systemd service
-
lrkwz almost 9 yearsIs it for the 1.2.5/1.3.x only? I'm triyng with a 1.2.4 jar build for jdk8 and it throws a java.lang.UnsupportedClassVersionError: ... : Unsupported major.minor version 52.0
-
Abdull almost 9 yearsHow does the "fully executable JAR" approach work? I use CentOS 6.6. I added
<executable>true</executable>
to mypom.xml
, but the packaged JAR file does not execute (..../myapp.jar ... cannot execute binary file
.) -
voor almost 9 yearsThis answer only works for the current 1.3 Milestone, which is not released yet. 1.1 and 1.2 branches will need to check the other responses here.
-
nKognito almost 9 yearsDo you know guys how to pass spring's arguments such as
-Dspring.profiles.active=prod
to this services? Question - stackoverflow.com/questions/31242291/… -
Radu Toader over 8 yearswhat about runnable WAR files ? it does not work for me with WAR layout.
-
JBCP over 8 yearsInterestingly this works with release
1.3.0.M2
, but I got an error when I tried1.3.0.RC1
. -
Geir over 8 yearsAny idea on how to do this with gradle instead of maven?
-
igracia over 8 years@chad Is there a way to manage this with
service myapp {start|stop}
? I couldn't get it to work that way, and I get aFailed to stop spring.service: Unit spring.service not loaded
error. -
tintin over 8 yearsI am not able to stop the spring-boot application.
/etc/init.d stop
is not stopping the app, its trying to start it again. -
Pierre Henry over 8 yearsWith Spring Boot 1.3+ you can generate a fully executable war file, so no need for the java -jar ... bit, just use the file's name there.
-
ruX about 8 yearsIf you want to monitor process and restart it if it die without writing system daemons check out patrickgrimard.com/2014/06/06/…
-
wired00 almost 8 yearsfor me that was
sudo ln -s /var/myapp/myapp.jar /etc/init.d/myapp
inubuntu
-
Sajib Ghosh almost 8 yearsNo need to write your own start/stop script. This is provided as of Spring Boot 1.3 and up. See docs.spring.io/spring-boot/docs/current/reference/htmlsingle/… for more details.
-
Steve almost 8 yearsGood to know that's an option, but all it does is remove the need to execute using
java -jar
. The rest of the script is still needed. -
yglodt almost 8 yearsI prefer using the full java commandline because that way you can add jvm parameters.
-
ashirman over 7 years@tintin i need to mention about spring-boot application stop command issues under some versions of linux. the latest available version of spring boot (1.4.0.RELEASE) use following piece of code to check is process running
isRunning() { ps -p "$1" &> /dev/null }
so evenps -p
command can't find process by id it still returns 0 (means success). as result spring-boot generated service doesn't remove appropriate .pid file and it is impossible to start the service again after that. detected on ps version "procps version 3.2.8" -
Vorsprung over 7 yearsThe answer I've given works for me with springboot 1.3, Centos 7.2 and systemd
-
bernardn over 7 yearsVery useful for when /etc/init.d or systemd is not an option, thanks for sharing.
-
Derek Mahar over 7 years@yglodt, can a Spring Boot executable jarfile not accept JVM parameters? (See my question at stackoverflow.com/q/40893530/107158.)
-
Martin Schröder over 7 years@DerekMahar: Of course it can. Configurable via
/etc/default/$service.conf
-
Martin Schröder over 7 years@Steve: Nope. You are reinventing the wheel. Oh, and we have systemd now.
-
Natix over 7 yearsWhen using Gradle, this configuration in done using
springBoot { executable = true }
block. -
Dyorgio over 7 yearsWhen you need to pass parameters to JVM (like -javaagent or -D parameters) this is the unique way, tks @Steve !
-
humkins about 7 yearsHello chad, you wrote "The executable jar has the usual start, stop, restart, and status commands". Can you please explain what does this mean? Should I process "start"|"stop"|"restart"|"status" arguments in main() method of main jar class or is it internal jar function?
-
Admin over 6 years@gumkins no, these are passed on the command line e.g.
/etc/init.d/yourApp status
you don't parse them yourself -
Marged almost 6 yearsI had some hard to find error because Java wrote to stderr which systemd did not grab. You might want to add some lines that include stderrs output
-
Tristan over 5 yearsNot really, because Spring Boot offers special features to do this.
-
spinlok over 5 yearsFor others wondering,
SuccessExitStatus=143
means "Treat exit status 143 (which corresponds to SIGTERM) as a normal exit status for this service" -
naveenkumarbv over 5 years@RaduToader : Were you able to execute the WAR file as a service?
-
Radu Toader over 5 yearsI ended up configuring systemd with war/jar file as is easier to manage start/restart enable at boot
-
MariuszS over 4 yearsLooks the same like this -> stackoverflow.com/a/30497095/516167
-
Vitaly Sazanovich over 4 yearsFinally something worked for me right out of the box. Thanks a lot for the supervisord hint.
-
rustyx over 4 yearsThis does the same job as
systemd
, which is built into most current Linux distros. -
rustyx over 4 yearsFor a proper boot sequence you might want to add ordering statements to the
[Unit]
section, e.g.After=mysql.service
,Before=apache2.service
. -
Nikhil Singh Bhadoriya about 4 yearsI have followed the same steps to run spring boot jar as windows service in company's intranet env, but the service is not getting up. There is a window coming out with error: Error:1067 The process terminated unexpectedly Could you please help or suggest what need to be done?
-
Arundev about 4 yearsDo you have all the permission to do that? If you are an administrator this won't cause any issue. Can u please check you have administrator rights.
-
Arundev about 4 yearsstackoverflow.com/questions/18205111/… can u please try this may be this will help u to resolve the issue.
-
Nikhil Singh Bhadoriya about 4 yearsthanks for the quick response, I got my service up and running by correcting an issue with the tag in xml file.
-
TheRealChx101 almost 3 yearsNice... The issue now is running the app on a privileged port with that non-sudoer user.
-
TheRealChx101 almost 3 yearsDoesn't spring boot manage its own rotation of log files?
-
TheRealChx101 almost 3 yearsWhat i don't personally like is to scatter configuration file around or related files around. Ideally, I like having everything in one place that way you're only looking in one place during maintenance or when someone else has to take over your stuff.
-
TheRealChx101 almost 3 yearsThe issue with deleting the old directory contents of that you could end up deleting configuration files or other important files. But good script nonetheless
-
Radu Toader over 2 yearsIf you have application that writes to console, you better do something with it. Also if the application doesn't start, and doesn't write anything to logging is probably because it has an exception before logging framework setup, and that error is present in system.out/err