HexTechie
A web for devs from 0 to F

Spring Boot Deployment With Systemd

Have you ever wondered, how a Spring Boot is deployed on a Linux system? Well, let's look at it how exactly.
-- By Jan
February 03, 2022
article image
Photo by Markus Spiske. Unsplash

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.

/etc/systemd/system/spring-boot.service

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!