Operations 13 min read

How to Ensure Your SpringBoot App Auto‑Starts and Recovers with systemd & Supervisor

This guide walks through configuring a SpringBoot application to automatically start on Linux boot and recover from crashes using native systemd service files or the cross‑platform Supervisor tool, covering scripts, service definitions, common pitfalls, health checks, and restart‑limit strategies.

Java Tech Enthusiast
Java Tech Enthusiast
Java Tech Enthusiast
How to Ensure Your SpringBoot App Auto‑Starts and Recovers with systemd & Supervisor

Incident Overview

"Little Wang, what's happening in production? All services are down!" A power outage caused all servers to reboot, but the SpringBoot application did not start automatically, leading to a 40‑minute outage. The lack of a startup configuration and occasional OOM crashes compounded the problem.

Solution 1: systemd (Recommended)

What is systemd?

systemd is the modern init system for Linux, responsible for managing system boot and service processes. It is supported by most major distributions such as CentOS, Ubuntu, and Debian.

Step‑by‑step configuration

1. Prepare SpringBoot application

Application name: demo-app

JAR path: /opt/apps/demo-app.jar Run user: appuser (non‑root recommended)

Log path:

/var/log/demo-app.log

2. Create start script (key)

#!/bin/bash
# SpringBoot application start script
APP_NAME="demo-app"
JAR_FILE="/opt/apps/demo-app.jar"
LOG_FILE="/var/log/${APP_NAME}.log"
JVM_OPTS="-Xms512m -Xmx512m -XX:+UseG1GC -XX:MaxGCPauseMillis=200"
SERVER_PORT=8080

# Check JAR existence
if [ ! -f "$JAR_FILE" ]; then
    echo "Error: JAR file $JAR_FILE not found!"
    exit 1
fi

# Check port availability
check_port() {
    netstat -tlnp | grep ":$SERVER_PORT " > /dev/null
    return $?
}

if check_port; then
    echo "Error: Port $SERVER_PORT is already in use!"
    netstat -tlnp | grep ":$SERVER_PORT "
    exit 1
fi

# Start application
echo "Starting $APP_NAME ..."
nohup java $JVM_OPTS -jar $JAR_FILE --server.port=$SERVER_PORT > $LOG_FILE 2>&1 &

# Wait for startup
echo "Waiting for $APP_NAME to start on port $SERVER_PORT ..."
for i in {1..30}; do
    if check_port; then
        echo "$APP_NAME started successfully!"
        echo "Log file: $LOG_FILE"
        exit 0
    fi
    sleep 1
done

echo "Error: $APP_NAME startup timed out!"
echo "Check logs with: tail -f $LOG_FILE"
exit 1

Make the script executable:

chmod +x /opt/apps/start.sh

3. Create systemd service file

[Unit]
Description=Demo SpringBoot Application
After=network.target mysql.service
Wants=mysql.service

[Service]
User=appuser
Group=appuser
WorkingDirectory=/opt/apps
ExecStart=/opt/apps/start.sh
ExecStop=/bin/bash -c "PID=$(pgrep -f 'demo-app.jar'); if [ -n \"$PID\" ]; then kill -15 $PID; sleep 10; if ps -p $PID > /dev/null; then kill -9 $PID; fi; fi"
ExecStartPre=/bin/bash -c "if [ -f /var/log/demo-app.log ]; then mv /var/log/demo-app.log /var/log/demo-app.log.$(date +%Y%m%d%H%M%S); fi"
SuccessExitStatus=143
Restart=always
RestartSec=5
TimeoutStartSec=300
TimeoutStopSec=60
Environment="SPRING_PROFILES_ACTIVE=prod"
Environment="JAVA_HOME=/usr/lib/jvm/java-11-openjdk"

[Install]
WantedBy=multi-user.target

4. Service management commands

sudo systemctl daemon-reload
sudo systemctl start demo-app
sudo systemctl stop demo-app
sudo systemctl restart demo-app
sudo systemctl enable demo-app   # enable on boot
sudo systemctl disable demo-app  # disable on boot
sudo systemctl status demo-app
sudo journalctl -u demo-app -f   # follow logs

Common pitfalls

Permission issues

Ensure the appuser has read/write access to the JAR file and log directory.

sudo chown -R appuser:appuser /opt/apps /var/log/demo-app.log

Startup timeout

If the application takes longer to start, increase TimeoutStartSec in the service file.

Graceful shutdown not working

Configure proper kill signals and timeout, and enable SpringBoot graceful shutdown.

KillSignal=SIGTERM
TimeoutStopSec=60
server:
  shutdown: graceful
spring:
  lifecycle:
    timeout-per-shutdown-phase: 30s

Solution 2: Supervisor (Compatible with older systems)

Supervisor is a Python‑based process manager that works across Linux, Unix, and macOS.

Installation

# CentOS
sudo yum install -y epel-release
sudo yum install -y supervisor
sudo systemctl start supervisord
sudo systemctl enable supervisord

# Ubuntu
sudo apt-get update
sudo apt-get install -y supervisor

Create program configuration

[program:demo-app]
command=/usr/bin/java -Xms512m -Xmx512m -XX:+UseG1GC -jar /opt/apps/demo-app.jar --server.port=8080
directory=/opt/apps
user=appuser
autostart=true
autorestart=true
startretries=3
startsecs=10
redirect_stderr=true
stdout_logfile=/var/log/demo-app.log
stdout_logfile_maxbytes=10MB
stdout_logfile_backups=10
environment=SPRING_PROFILES_ACTIVE="prod",JAVA_HOME="/usr/lib/jvm/java-11-openjdk"

Supervisor commands

sudo supervisorctl update          # reload config changes
sudo supervisorctl status          # view process status
sudo supervisorctl start demo-app
sudo supervisorctl stop demo-app
sudo supervisorctl restart demo-app
sudo supervisorctl tail -f demo-app   # follow logs

Comparison and recommendation

systemd: native integration, moderate configuration complexity, Linux‑only, strong process monitoring.

Supervisor: simple installation, works on many platforms, centralized configuration for multiple services.

Use systemd for production Linux environments; choose Supervisor when you need to manage many micro‑services on heterogeneous systems. Docker containers already provide their own process management.

Advanced configuration: health checks and automatic recovery

systemd health check

Create /opt/apps/healthcheck.sh:

#!/bin/bash
PORT=8080
TIMEOUT=5
result=$(curl -s -w "%{http_code}" -o /dev/null --connect-timeout $TIMEOUT http://localhost:$PORT/actuator/health)
if [ "$result" -eq 200 ]; then
    exit 0
else
    echo "Health check failed, HTTP status: $result"
    exit 1
fi

Add to the service file:

[Service]
HealthCheckSec=30
HealthCheckCmd=/opt/apps/healthcheck.sh
HealthCheckFailureAction=restart

Enable the health endpoint in SpringBoot:

management:
  endpoints:
    web:
      exposure:
        include: health
  endpoint:
    health:
      show-details: always
      probes:
        enabled: true

Prevent infinite restart loops

systemd limits:

[Unit]
StartLimitInterval=600   # 10 minutes
StartLimitBurst=5       # max 5 restarts
StartLimitAction=poweroff   # extreme case

Supervisor limits:

[program:demo-app]
autorestart=unexpected   # restart only on unexpected exits
exitcodes=0,143           # treat these as normal termination

Conclusion

Following these steps gives your SpringBoot application the ability to start automatically after a server reboot and to recover automatically from crashes, ensuring higher availability in production environments.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Deploymentprocess managementSpringBoothealth checkSupervisorsystemdauto-restart
Java Tech Enthusiast
Written by

Java Tech Enthusiast

Sharing computer programming language knowledge, focusing on Java fundamentals, data structures, related tools, Spring Cloud, IntelliJ IDEA... Book giveaways, red‑packet rewards and other perks await!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.