Spring Boot Deployment With Systemd
There are many options, how to deploy a Spring Boot application. One of them is via a systemd.
Systemd stands for system and service manager in Linux operating systems. Many of systemd service files are located inside /etc/systemd
directory. For a Spring Boot application we will use a directory system
, i.e. /etc/systemd/system
. So let's create our service file in there first. For our purpose of this tutorial, we will name it as spring-boot.service
.
[Unit]
Description=Spring Boot app
After=syslog.target network.target
[Service]
User=spring
Group=spring
ExecStart=/usr/bin/java -jar /webapps/spring/spring-boot.jar
SuccessExitStatus=143
WorkingDirectory=/webapps/spring
Restart=on-failure
# Sandboxing
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/webapps/spring/data
[Install]
WantedBy=multi-user.target
Let's explain a little what all of those sections mean:
Unit section
We added network.target
to our Spring Boot service file beside syslog.target
because we expect our app to be a web app, so an accessible network is required. A service will be launched with already available network as it depends on it.
Service section
Inside our Service
section we added a custom user spring
with his own group already created in our linux system specifically for this app. It is a good security measure to have a separated user for services that have much less privileges than other users.
ExecStart
options is probably self explanatory and contains what should be executed. If it is necessary, we can even add some other jvm options, like -XX:MaxRAM=2G
to decrease maximum RAM usage for our service or other specific parameters for our Spring Boot app.
SuccessExitStatus
option needs to be set to 143 which is a common value for java apps when they are exiting without a failure. Otherwise our service would catch it as a failure and restart again.
WorkingDirectory
is important if we expect some working with data within our app where our .jar
file resides and our app uses relative paths. Or maybe we have an application.properties
file beside our .jar
file which needs to be automatically read on start time.
Restart
option is set to on-failure
. Our app is a web app, so we need it to be up and running again, in case some failure occurs. Problem is, if a failure occurs on start-up, it restarts again in a loop. There are other options, like StartLimitIntervalSec
or StartLimitBurst
which can prevent a never ending restart loop from happening. If a service achieves limit of StartLimitBurst
within StartLimitIntervalSec
, the service won't be started again.
ProtectSystem
and ProtectHome
are some important security hardening features. ProtectSystem
with a value of strict
mounts the whole file system hierarchy (/etc
, /usr
, /boot
, etc.) as read-only and ProtectHome
with a value of true
prevents accesibility to /home
, /root
and /run/user
directories. Our app is inside /webapps
directory, so we don't need access to /home
directory or other sensitive directories.
ReadWritePaths
option specifies paths that can be writable and accessible by service, which were prohibited by our ProtectSystem=strict
option. If we create a functionality to upload files and store them somewhere, this is the option to specify a writable directory to store those data.
Install section
WantedBy
option specifies a unit after which this service will be started. It actually allows us to call systemctl enable spring-boot.service
which then starts this service after boot automatically.
Applying configuration
After creating and saving our service file, the last thing we need to do, is to execute systemctl daemon-reload
to reload all service configurations and start our service via systemctl start spring-boot.service
. To be able for our service to start on boot, we can enable it via systemctl enable spring-boot.service
.
For more information about options for systemd service file, you can open manual entries via man systemd.exec
, man systemd.service
or man systemd.unit
on a linux system.
So that's it! A custom functional service file for our java app with hardening options for a better security. Neat!