When managing a Minecraft server through systemd on CentOS 7, you might encounter an issue where stopping the service leaves it in a "failed" state despite successful termination. Here's a typical symptom:
systemctl status minecraftd.service
minecraftd.service - Minecraft Server
Loaded: loaded (/usr/lib/systemd/system/minecraftd.service; disabled)
Active: failed (Result: exit-code) since Mon 2015-06-01 16:01:37 UTC; 3s ago
Process: 20975 ExecStart=/bin/java -Xmx1024M -Xms1024M -jar minecraft_server.jar nogui (code=exited, status=143)
Main PID: 20975 (code=exited, status=143)
The exit code 143 indicates the process received SIGTERM (Termination signal), which is normal behavior when stopping a service. However, systemd interprets any non-zero exit code as a failure by default.
Java applications don't typically return exit code 0 when terminated by SIGTERM. This conflicts with systemd's expectation that a properly stopped service should return exit code 0.
Modify your service file to recognize exit code 143 as successful termination:
[Unit]
Description=Minecraft Server
After=syslog.target network.target
[Service]
Type=simple
WorkingDirectory=/root/Minecraft
ExecStart=/bin/java -Xmx1024M -Xms1024M -jar minecraft_server.jar nogui
SuccessExitStatus=143
Restart=on-failure
[Install]
WantedBy=multi-user.target
For more control, implement a shutdown hook in your Java application or wrapper script:
#!/bin/bash
cleanup() {
echo "Shutting down Minecraft server..."
# Send stop command to Minecraft console
screen -S minecraft -X stuff "stop^M"
wait $PID
exit 0
}
trap cleanup SIGTERM
cd /root/Minecraft
java -Xmx1024M -Xms1024M -jar minecraft_server.jar nogui &
PID=$!
wait $PID
Add an explicit stop command to your service file:
[Service]
...
ExecStop=/bin/kill -s TERM $MAINPID
KillMode=process
...
After implementing changes, test the service behavior:
systemctl daemon-reload
systemctl start minecraftd.service
systemctl stop minecraftd.service
systemctl status minecraftd.service
The status should now show as "inactive" rather than "failed" when properly stopped.
For production environments, consider these enhancements:
- Use a dedicated user account instead of root
- Implement proper logging with StandardOutput/StandardError directives
- Consider using screen or tmux for better session management
When working with systemd services on CentOS 7, you might encounter situations where services remain in a "failed" state after being manually stopped, even though the service actually stopped successfully. This issue commonly occurs with Java-based services like Minecraft servers.
The following service unit demonstrates the issue:
[Unit]
Description=Minecraft Server
After=syslog.target network.target
[Service]
Type=simple
WorkingDirectory=/root/Minecraft
ExecStart=/bin/java -Xmx1024M -Xms1024M -jar minecraft_server.jar nogui
Restart=on-failure
[Install]
WantedBy=multi-user.target
After stopping the service with systemctl stop
, checking the status shows:
Active: failed (Result: exit-code)
Process: 20975 ExecStart=... (code=exited, status=143)
Main PID: 20975 (code=exited, status=143)
The service enters failed state because:
- Java process receives SIGTERM (signal 15) when stopped
- The process exits with status 143 (128 + SIGTERM)
- Systemd interprets this as a failure due to non-zero exit code
Here are three approaches to resolve this:
1. Using SuccessExitStatus
Add this to your service file:
[Service]
...
SuccessExitStatus=143
2. Implementing Clean Shutdown
Modify the service to handle SIGTERM properly:
[Service]
...
ExecStop=/bin/kill -15 $MAINPID
TimeoutStopSec=30
KillSignal=15
3. Using ExecStop for Graceful Termination
For Minecraft specifically, implement RCON shutdown:
[Service]
...
ExecStop=/usr/bin/mcrcon -H 127.0.0.1 -p password "stop"
TimeoutStopSec=30
Here's the complete improved service file:
[Unit]
Description=Minecraft Server
After=network.target
[Service]
User=minecraft
Group=minecraft
WorkingDirectory=/opt/minecraft/server
ExecStart=/usr/bin/java -Xmx1024M -Xms1024M -jar server.jar nogui
ExecStop=/usr/bin/mcrcon -H 127.0.0.1 -p password "stop"
Restart=on-failure
SuccessExitStatus=143
TimeoutStopSec=30
[Install]
WantedBy=multi-user.target
After implementing changes:
systemctl daemon-reload
systemctl start minecraftd
systemctl stop minecraftd
- Check status with
systemctl status minecraftd
- For services that must not be restarted after manual stop, use
Restart=on-failure
- Consider implementing
RemainAfterExit=yes
for certain service types - Always test with
systemctl --no-pager status
for complete information