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.
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.log2. 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 1Make the script executable:
chmod +x /opt/apps/start.sh3. 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.target4. 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 logsCommon 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.logStartup 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: 30sSolution 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 supervisorCreate 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 logsComparison 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
fiAdd to the service file:
[Service]
HealthCheckSec=30
HealthCheckCmd=/opt/apps/healthcheck.sh
HealthCheckFailureAction=restartEnable the health endpoint in SpringBoot:
management:
endpoints:
web:
exposure:
include: health
endpoint:
health:
show-details: always
probes:
enabled: truePrevent infinite restart loops
systemd limits:
[Unit]
StartLimitInterval=600 # 10 minutes
StartLimitBurst=5 # max 5 restarts
StartLimitAction=poweroff # extreme caseSupervisor limits:
[program:demo-app]
autorestart=unexpected # restart only on unexpected exits
exitcodes=0,143 # treat these as normal terminationConclusion
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.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
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!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
