-
-
Save carchrae/3dc0da023c8e9bb36441dcd439950870 to your computer and use it in GitHub Desktop.
#!/bin/bash | |
# /home/minecraft/bin/minecraft-sleep.sh | |
#set -v | |
cd "$(dirname "$0")" | |
# service name (i'm using systemd) | |
SERVICE_NAME="$1" | |
# set this to the port your minecraft server is on | |
#PORT=25565 | |
PORT=`grep server-port ../$SERVICE_NAME/server.properties | cut -d '=' -f2` | |
# delay before starting | |
START_DELAY=600 | |
# how frequently do we check for connections (seconds) | |
CHECK_DELAY=600 | |
# script will start the server briefly duing each cycle | |
POLL_CYCLE=20 | |
# how long to resume server during poll cycle | |
POLL_RUN=1 | |
# delay in checking for connections during poll | |
POLL_DELAY=1 | |
# maybe you want to customise this, eg if not using systemd | |
function find_pid(){ | |
echo $(ps -o 'pid,ppid,args,unit' `pgrep java` | grep $SERVICE_NAME | xargs | cut -d ' ' -f1) | |
} | |
function pause(){ | |
# this stops the process (like ctrl-z) | |
PID=$(find_pid) | |
if [ -n "$PID" ]; then | |
kill -STOP $PID | |
else | |
echo "could not find PID" | |
fi | |
} | |
function resume(){ | |
PID=$(find_pid) | |
if [ -n "$PID" ]; then | |
kill -CONT $PID | |
else | |
echo "could not find PID" | |
fi | |
} | |
resume | |
sleep $START_DELAY | |
while true; do | |
# wait a bit before looping again | |
sleep 120 | |
# some random so processes don't wake up all at the same time | |
sleep $[ ( $RANDOM % 10 ) + 1 ]s | |
echo "checking for activity on $PORT" | |
# while ( netstat -tn | grep $PORT | grep ESTABLISHED ); do | |
while ( netstat -tn | grep $PORT ); do | |
#echo "still active..." | |
sleep $CHECK_DELAY | |
done | |
echo "no active connections on $PORT, so pausing process $(find_pid)" | |
pause | |
echo "waiting for activity on $PORT, will run server for $POLL_RUN seconds every $POLL_CYCLE seconds." | |
ACTIVE="" | |
while [ -z "$ACTIVE" ]; do | |
#echo "Resume process $(find_pid) for $POLL_RUN seconds to prevent crashes/timeouts" | |
resume | |
sleep $POLL_RUN | |
pause | |
#echo "waiting for activity on $PORT" | |
POLL_UNTIL=$((SECONDS+POLL_CYCLE)) | |
while [ $SECONDS -lt $POLL_UNTIL ]; do | |
ACTIVE=`netstat -tn | grep $PORT` | |
#echo "ACTIVE=$ACTIVE" | |
if [ -n "$ACTIVE" ]; then | |
break | |
else | |
sleep $POLL_DELAY | |
fi | |
done | |
done; | |
echo "Resuming process $(find_pid) due to activty $ACTIVE" | |
resume | |
done |
#!/bin/bash | |
# /home/minecraft/bin/minecraft-wake.sh | |
## this just pokes the port of a minecraft instance, making it wake up. equivalent to `resume` in minecraft-sleep.sh | |
## you might want to use this if you have some scripts that run, eg backups, that need the server responding | |
## as if a user was logged in | |
cd "$(dirname "$0")" | |
#set -v | |
# service name (i'm using systemd) | |
SERVICE_NAME="$1" | |
# set this to the port your minecraft server is on | |
#PORT=25565 | |
PORT=`grep server-port ../$SERVICE_NAME/server.properties | cut -d '=' -f2` | |
echo "boop" | nc -q 3 localhost $PORT |
# /etc/systemd/system/[email protected] | |
# this is a systemd service, use start and/or enable (over reboots) | |
# presumes that minecraft runs as a restricted user 'minecraft' | |
[Unit] | |
Description=Minecraft Server: %i | |
After=network.target | |
[Service] | |
WorkingDirectory=/home/minecraft/%i | |
User=minecraft | |
Group=minecraft | |
Restart=always | |
ExecStartPre=/home/minecraft/bin/start-minecraft-sleep.sh %i | |
ExecStart=/usr/bin/screen -DmS mc-%i /home/minecraft/%i/start.sh | |
ExecStop=/home/minecraft/bin/stop-minecraft-sleep.sh %i || true | |
ExecStop=/bin/sleep 3 | |
ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "say SERVER SHUTTING DOWN IN 15 SECONDS..."\015' || true | |
ExecStop=/bin/sleep 5 | |
ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "say SERVER SHUTTING DOWN IN 10 SECONDS..."\015' || true | |
ExecStop=/bin/sleep 5 | |
ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "say SERVER SHUTTING DOWN IN 5 SECONDS..."\015' || true | |
ExecStop=/bin/sleep 5 | |
ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "save-all"\015' || true | |
ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "stop"\015' || true | |
[Install] | |
WantedBy=multi-user.target |
#!/bin/bash | |
# /home/minecraft/bin/start-minecraft-sleep.sh | |
cd "$(dirname "$0")" | |
# the gawk is to add timestamps | |
./minecraft-sleep.sh $1 | gawk '{ print strftime("[%Y-%m-%d %H:%M:%S]"), $0 }' >> ../$1/logs/sleep.log & | |
#!/bin/bash | |
# /home/minecraft/bin/stop-minecraft-sleep.sh | |
cd "$(dirname "$0")" | |
#set -v | |
SERVICE_NAME=$1 | |
# maybe you want to customise this, eg if not using systemd | |
function find_pid(){ | |
echo $(ps -o 'pid,ppid,args,unit' `pgrep java` | grep $SERVICE_NAME | cut -d ' ' -f1) | |
} | |
function resume(){ | |
PID=$(find_pid) | |
if [ -n "$PID" ]; then | |
kill -CONT $PID | |
else | |
echo "could not find PID" | |
fi | |
} | |
echo "stopping minecraft-sleep.sh" | |
pkill -f "bin/minecraft-sleep.sh $1" || true | |
sleep 1 | |
echo "resuming process $(find_pid)" | |
resume |
it is intentional that the script will keep running as i'm managing this with systemd. systemd will restart minecraft if it exits, and if i stop the service, then the service will kill the sleep script. for the same reason, i don't presume the PID stays the same either.
That makes sense. I just incorporated your code as part of my run.sh script when my VPS boots and while looking through the logic I noticed there was no handling of the situation that there was no server actually available. If Minecraft dies on mine for some reason I wanted to script to stop polling. Thanks again! I've got it doing what I need for now. This was a huge help! I was going to write something much less elegant.
glad it was of help. and i'm not sure this is my most elegant code - but is bash ever elegant!? :D
and indeed, adapt to fit. that is what i did based on michiel's code. i just had to generalise it a bit, since i am running three servers on the same box, and knockd seemed like overkill.
as an aside, i looked at this briefly too; https://github.com/jkutner/heroku-buildpack-minecraft - which is pretty clever (and free, but low RAM), but convoluted in how it exposes the port using ngrok. in the end, i hosted the minecraft servers on a pc at home, since 512mb isn't enough for a minecraft server unless you run an old version.
it is intentional that the script will keep running as i'm managing this with systemd. systemd will restart minecraft if it exits, and if i stop the service, then the service will kill the sleep script. for the same reason, i don't presume the PID stays the same either.
i've added the full set of scripts (at this point, i guess this should be a repo) to better describe my context, but there is no reason you need to use systemd, init.d, monit, etc, to ensure the server is running.