How to Deploy a Spring Boot Application on RHEL 7
Spring Boot has become the de facto standard for building production-ready Java microservices and web applications. Its embedded server model — packaging the entire application, including Tomcat or Jetty, into a single executable JAR — greatly simplifies deployment on Linux servers. Instead of managing a standalone application server, you run a self-contained JAR file as a system service. This guide walks through building a Spring Boot application with Maven, deploying it on RHEL 7, managing it as a systemd service, reverse-proxying it through Nginx, and monitoring its health endpoint.
Prerequisites
- RHEL 7 with root or
sudoaccess - Java 8 or Java 11 installed and
JAVA_HOMEset - Apache Maven installed (see the Maven installation guide)
- Nginx available or installable via
yum - A Spring Boot application project (or the sample shown below)
Step 1: Create and Build the Spring Boot Application
If you do not already have a Spring Boot project, generate a minimal one. The simplest approach is to use the Spring Initializr web interface at https://start.spring.io and download a ZIP, or create the structure manually.
For this guide, assume your project directory is /opt/myapp/myapp-src and contains a standard Maven pom.xml with the Spring Boot parent and the Web starter dependency:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.18</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
Build the executable JAR:
cd /opt/myapp/myapp-src
mvn clean package -DskipTests
This produces target/myapp-0.0.1-SNAPSHOT.jar. The spring-boot-maven-plugin repackages the artifact into a fat JAR containing all dependencies and the embedded Tomcat server.
Step 2: Prepare the Deployment Directory and User
Running a service as root is a security risk. Create a dedicated system user that owns only the application files and cannot log in interactively:
sudo useradd -r -s /sbin/nologin springapp
sudo mkdir -p /opt/myapp/current
sudo cp target/myapp-0.0.1-SNAPSHOT.jar /opt/myapp/current/myapp.jar
sudo chown -R springapp:springapp /opt/myapp
sudo chmod 750 /opt/myapp/current
sudo chmod 640 /opt/myapp/current/myapp.jar
Step 3: Configure Application Environment Variables
Spring Boot reads configuration from environment variables and from application.properties. Sensitive values such as database passwords should be supplied as environment variables rather than stored in the JAR. Create a dedicated environment file owned by root with restricted permissions:
sudo tee /opt/myapp/myapp.env <<'EOF'
SPRING_PROFILES_ACTIVE=production
SERVER_PORT=8080
SPRING_DATASOURCE_URL=jdbc:postgresql://localhost:5432/mydb
SPRING_DATASOURCE_USERNAME=mydbuser
SPRING_DATASOURCE_PASSWORD=changeme
LOGGING_FILE_NAME=/var/log/myapp/myapp.log
EOF
sudo chown root:springapp /opt/myapp/myapp.env
sudo chmod 640 /opt/myapp/myapp.env
Create the log directory:
sudo mkdir -p /var/log/myapp
sudo chown springapp:springapp /var/log/myapp
Step 4: Create the systemd Service Unit
A systemd unit file manages the application lifecycle — starting on boot, restarting on failure, and stopping cleanly. Spring Boot applications exit with code 143 when they receive SIGTERM (the default signal systemd sends on stop), so the unit must declare that exit code as successful to prevent systemd from marking the stop as a failure.
sudo tee /etc/systemd/system/myapp.service <<'EOF'
[Unit]
Description=My Spring Boot Application
After=network.target
After=syslog.target
[Service]
Type=simple
User=springapp
Group=springapp
EnvironmentFile=/opt/myapp/myapp.env
WorkingDirectory=/opt/myapp/current
ExecStart=/usr/bin/java
-Xms256m
-Xmx512m
-Djava.security.egd=file:/dev/./urandom
-jar /opt/myapp/current/myapp.jar
SuccessExitStatus=143
Restart=on-failure
RestartSec=10s
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=myapp
[Install]
WantedBy=multi-user.target
EOF
Key points about this unit file:
SuccessExitStatus=143— tells systemd that exit code 143 (128 + SIGTERM signal 15) is a clean shutdown, not a crashEnvironmentFile— loads environment variables from the file, keeping secrets out of the unit file itself-Djava.security.egd=file:/dev/./urandom— prevents the JVM from blocking on/dev/randomentropy during startup, a common issue on virtual machinesRestart=on-failure— automatically restarts if the process crashes but not on clean stops
Step 5: Enable and Start the Service
sudo systemctl daemon-reload
sudo systemctl enable myapp
sudo systemctl start myapp
sudo systemctl status myapp
Expected output from status:
● myapp.service - My Spring Boot Application
Loaded: loaded (/etc/systemd/system/myapp.service; enabled; vendor preset: disabled)
Active: active (running) since Sun 2026-05-17 10:00:00 UTC; 5s ago
Main PID: 12345 (java)
CGroup: /system.slice/myapp.service
└─12345 /usr/bin/java -Xms256m -Xmx512m ...
May 17 10:00:02 host myapp[12345]: Started MyApplication in 4.231 seconds
View live logs:
sudo journalctl -u myapp -f
Step 6: Configure Nginx as a Reverse Proxy
It is best practice not to expose Spring Boot’s embedded Tomcat directly on port 80 or 443. Instead, run Nginx in front as a reverse proxy. This allows Nginx to handle SSL termination, serve static files efficiently, and rate-limit requests.
Install Nginx:
sudo yum install -y nginx
sudo systemctl enable nginx
sudo systemctl start nginx
Create a server block configuration for your application:
sudo tee /etc/nginx/conf.d/myapp.conf <<'EOF'
upstream springboot_backend {
server 127.0.0.1:8080;
keepalive 32;
}
server {
listen 80;
server_name myapp.example.com;
access_log /var/log/nginx/myapp.access.log;
error_log /var/log/nginx/myapp.error.log;
location / {
proxy_pass http://springboot_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 10s;
proxy_read_timeout 60s;
}
# Block external access to Actuator management endpoints
location /actuator {
deny all;
}
}
EOF
Test the configuration and reload:
sudo nginx -t
sudo systemctl reload nginx
Step 7: Verify the Health Endpoint
Spring Boot Actuator exposes a /actuator/health endpoint that reports the application status. Check it directly on the Spring Boot port (not through Nginx, since Actuator is blocked externally):
curl -s http://localhost:8080/actuator/health | python -m json.tool
A healthy application returns:
{
"status": "UP"
}
If the application connects to a database or other services, their statuses appear under the components key. A DOWN status indicates a dependency is unreachable.
Step 8: Log Configuration
Spring Boot uses Logback by default. To write logs to a rotating file, add these properties to src/main/resources/application.properties:
logging.file.name=/var/log/myapp/myapp.log
logging.file.max-size=50MB
logging.file.max-history=14
logging.level.root=INFO
logging.level.com.example=DEBUG
logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n
Rebuild and redeploy the JAR after changing application properties:
mvn clean package -DskipTests
sudo cp target/myapp-0.0.1-SNAPSHOT.jar /opt/myapp/current/myapp.jar
sudo systemctl restart myapp
Conclusion
Deploying a Spring Boot application on RHEL 7 involves packaging the application as a self-contained JAR, creating a non-privileged system user to run it, writing a robust systemd service unit with the correct SuccessExitStatus=143 setting, and placing Nginx in front as a reverse proxy. This architecture is production-ready: the service starts automatically on reboot, restarts on unexpected crashes, and its management endpoints are shielded from public access. By externalising configuration through an environment file, you keep secrets out of your application binaries and version-controlled configuration.