start.sh is the process that actually runs inside the tmux session. Its
primary job is to run the Minecraft server and automatically restart it if it
crashes — unless the shutdown was intentional.
You do not normally invoke start.sh directly. Use serv start instead,
which sets up the tmux session, exports the necessary environment variables,
and runs start.sh inside it.
How the loop works
The script registers a SIGINT/SIGTERM signal trap and runs in a while loop that continues as long as a keep_running flag is true. Each iteration of the loop:
- Checks for a
stop_signal file before launching. If found, sets keep_running=false and removes the file — server does not start.
- Launches the Java process and blocks until it exits.
- Checks for
stop_signal again immediately after the process exits.
- If
keep_running is still true, waits 5 seconds, checks stop_signal one final time, then restarts.
# Trap SIGINT (Ctrl+C) and SIGTERM signals
trap handle_shutdown SIGINT SIGTERM
while $keep_running; do
# Check for stop signal file
if [ -f "stop_signal" ]; then
echo "Stop signal file detected. Server will not restart after stopping."
keep_running=false
rm -f stop_signal
fi
java -Xmx3072M -Xms2048M -XX:+UseG1GC -XX:MaxGCPauseMillis=50 \
-Dlog4j.configurationFile=log4j2.xml \
-jar $SERVER_JAR nogui
# Check again after server stops
if [ -f "stop_signal" ]; then
echo "Stop signal file detected. Server will not restart."
keep_running=false
rm -f stop_signal
fi
if $keep_running; then
echo "Server restarting in 5 seconds..."
echo "Press CTRL+C to prevent restart."
sleep 5
# Check one more time before restarting
if [ -f "stop_signal" ]; then
echo "Stop signal file detected. Server will not restart."
keep_running=false
rm -f stop_signal
fi
fi
done
echo "Server shutdown complete."
The stop_signal file
The stop_signal file is the mechanism that differentiates an intentional stop from a crash. The script also traps SIGINT and SIGTERM — pressing Ctrl+C inside the tmux session sets keep_running=false without needing the file.
| Event | What happens |
|---|
serv stop | Creates stop_signal, sends stop to the console — loop exits cleanly, no restart |
| Server crash | No stop_signal is created — loop detects the process exited, waits 5 seconds, restarts |
serv restart | Sends stop to the console without creating stop_signal — loop restarts the server automatically |
| Ctrl+C in tmux | SIGINT trap sets keep_running=false — loop exits after the current server run finishes |
This means a crash at any time — including during a snapshot window — will
trigger an automatic restart within 5 seconds, unless serv stop was called
first.
JVM flags
The server is launched with the following JVM arguments:
| Flag | Value | Purpose |
|---|
-Xmx | 3072M | Maximum heap size (3 GB) |
-Xms | 2048M | Initial heap size (2 GB) |
-XX:+UseG1GC | — | Use the G1 garbage collector |
-XX:MaxGCPauseMillis | 50 | Target maximum GC pause time of 50 ms |
-Dlog4j.configurationFile | log4j2.xml | Use the custom log4j config to suppress noisy output |
The jar is launched with the nogui flag, which disables the Swing GUI that
would otherwise fail in a headless environment.
tmux session details
| Setting | Value |
|---|
| Session name | minecraft |
| tmux socket | /tmp/minecraft-tmux |
| Working directory | /usr/local/games/minecraft_server/java |
| Error log | /tmp/minecraft_error.log |
The socket is created with permissions 770 after the session is started, so
users in the owning group can attach without root.
Graceful stop vs crash
Graceful stop via serv stop:
Stop signal file detected. Server will not restart after stopping.
Server shutdown complete.
Crash recovery:
Server restarting in 5 seconds...
Press CTRL+C to prevent restart.
The loop will then re-execute the java command and the server comes back up
automatically. The tmux session and the loop itself remain alive throughout,
so serv console continues to work even between restarts.