![]() |
VOOZH | about |
This is an example of possible Minecraft server startup and maintenance script for GNU/Linux distros.
For all modern Servers supporting Systemd. Systemd is the jack of all trades. For Ubuntu, it comes with 15.04 (15.04 is an old version which have had end-of-support, we suggest using later LTS versions instead, but the following contents is fully working in this version).
[Unit] Description=Minecraft Server %i After=network.target [Service] WorkingDirectory=/opt/minecraft/%i # Solves the issue where the minecraft server will endlessly restart itself # See https://askubuntu.com/questions/953920/systemctl-service-timed-out-during-start for more info Type=simple PrivateUsers=true # Users Database is not available from within the unit, only root and minecraft is available, everybody else is nobody User=minecraft Group=minecraft ProtectSystem=full # Read only mapping of /usr /boot and /etc ProtectHome=true # /home, /root and /run/user seem to be empty from within the unit. It is recommended to enable this setting for all long-running services (in particular network-facing ones). ProtectKernelTunables=true # /proc/sys, /sys, /proc/sysrq-trigger, /proc/latency_stats, /proc/acpi, /proc/timer_stats, /proc/fs and /proc/irq will be read-only within the unit. It is recommended to turn this on for most services. # Implies MountFlags=slave ProtectKernelModules=true # Block module system calls, also /usr/lib/modules. It is recommended to turn this on for most services that do not need special file systems or extra kernel modules to work # Implies NoNewPrivileges=yes ProtectControlGroups=true # It is hence recommended to turn this on for most services. # Implies MountAPIVFS=yes # Set default memory values Environment="MCMINMEM=512M" "MCMAXMEM=1024M" "SHUTDOWN_DELAY=5" "POST_SHUTDOWN_DELAY=10" # Change memory values in environment file EnvironmentFile=-/opt/minecraft/%i/server.conf # Uncomment this to fix screen on RHEL 8 #ExecStartPre=+/bin/sh -c 'chmod 777 /run/screen' ExecStart=/bin/sh -c \ 'find -L . \ -maxdepth 1 \ -type f \ -iregex ".*/\\(FTBServer\\|craftbukkit\\|spigot\\|paper\\|forge\\|minecraft_server\\).*jar" \ -print0 \ -quit \ | xargs -0 -I{} \ /usr/bin/screen -DmS mc-%i \ /usr/bin/java \ -server \ -Xms${MCMINMEM} \ -Xmx${MCMAXMEM} \ -XX:+UseG1GC \ -XX:ParallelGCThreads=2 \ -XX:MinHeapFreeRatio=5 \ -XX:MaxHeapFreeRatio=10 \ -jar {} \ --nogui' # Alternative to the above ExecStart. Found to work better as this creates the screen session prior to invoking java to run the server. # Solves the problem many encountered when starting the service where it would fail with the error 'no screen session found'. ExecStartPre=/bin/sh -c \ 'find -L . \ -maxdepth 1 \ -type f \ -iregex ".*/\\(FTBServer\\|craftbukkit\\|spigot\\|paper\\|forge\\|minecraft_server\\).*jar" \ -print0 \ -quit \ | xargs -0 -I{} \ /usr/bin/screen -DmS mc-%i' ExecStart=/bin/sh -c \ '/usr/bin/java \ -server \ -Xms${MCMINMEM} \ -Xmx${MCMAXMEM} \ -XX:+UseG1GC \ -XX:ParallelGCThreads=2 \ -XX:MinHeapFreeRatio=5 \ -XX:MaxHeapFreeRatio=10 \ -jar {} \ # insert server jar name. i.e. 'server.jar' --nogui' # Simplified of alternative ExecStartPre=/bin/sh -c '/usr/bin/screen -dmS mc-%i' ExecStart=/bin/sh -c '/usr/bin/java -server -Xmx${MCMAXMEM} -Xms${MCMINMEM} -jar server.jar --nogui' ExecReload=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "reload"\\015' ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "say SERVER SHUTTING DOWN. Saving map..."\\015' ExecStop=/bin/sh -c '/bin/sleep ${SHUTDOWN_DELAY}' ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "save-all"\\015' ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "stop"\\015' ExecStop=/bin/sh -c '/bin/sleep ${POST_SHUTDOWN_DELAY}' Restart=on-failure RestartSec=60s [Install] WantedBy=multi-user.target ######### # HowTo ######### # # Create a directory in /opt/minecraft/XX where XX is a name like 'survival' # Add minecraft_server.jar into dir with other conf files for minecraft server # # Enable/Start systemd service # systemctl enable minecraft@survival # systemctl start minecraft@survival # # To run multiple servers simply create a new dir structure and enable/start it # systemctl enable minecraft@creative # systemctl start minecraft@creative # # To change specific server memory assignment, create file /opt/minecraft/XX/server.conf (where XX is your server name) and add below lines: # MCMINMEM=512M # MCMAXMEM=2048M
Now you can Upload your FTB Modpacks into a subfolder of /opt/minecraft/. For example, you would place the modpack "FTB Beyond" in "/opt/minecraft/FTBBeyond" (without spaces in the name). If you want to run vanilla instances, just create a folder within /opt/minecraft and upload the minecraft_server.jar and create the eula.txt file (using: echo "eula=true" > /opt/minecraft/vanilla/eula.txt).
After you uploaded the minecraft server files, make sure, that "minecraft" is the owner and owning group. To do so just run "ls -la /opt/minecraft". If it is not, run "chown minecraft:minecraft /opt/minecraft/FTBBeyond". You may also require to complete the installation. For current FTB packages you would run:
cd /opt/minecraft/FTBBeyond echo "eula=true" > /opt/minecraft/FTBBeyond/eula.txt su -c "/opt/minecraft/FTBBeyond/FTBInstall.sh" -s "/bin/bash" minecraft
You start your server using "systemctl start minecraft@FTBBeyond" and stop it using "systemctl stop minecraft@FTBBeyond". The part behind the "@" is your instance name e. g. the Folder Name. This script also takes care to automatically stop your minecraft server if you reboot the server.
systemctl enable minecraft@FTBBeyond
systemctl disable minecraft@FTBBeyond
For legacy Servers which don't have OS-integrated Systemd
Screen package must be installed.
On CentOs and Red Hat-based distributions:
yum install screen
On Debian based systems such as Ubuntu:
apt-get install screen python
To download the script with wget, run the following (WATCH OUT SCRIPT NEEDS WORK: change the WORLD, MCPATH and BACKUPPATH variables.
Important: If you use the wget method and the first character of every line is an empty space, the script won't work and update-rc.d outputs errors. If so, you have to remove the leading empty spaces from each line. Be careful not to delete anything else than empty space though!)
wget -O minecraft "http://minecraft.wiki/Tutorials/Server_startup_script/Script?action=raw"
#!/bin/bash # /etc/init.d/minecraft # version 0.4.2 2016-02-09 (YYYY-MM-DD) # ### BEGIN INIT INFO # Provides: minecraft # Required-Start: $local_fs $remote_fs screen-cleanup # Required-Stop: $local_fs $remote_fs # Should-Start: $network # Should-Stop: $network # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Minecraft server # Description: Starts the minecraft server ### END INIT INFO #Settings SERVICE='minecraft_server.jar' SCREENNAME='minecraft_server' OPTIONS='--nogui' USERNAME='minecraft' WORLD='world' MCPATH='/home/minecraft' BACKUPPATH='/minecraft/minecraft.backup' MAXHEAP=2048 MINHEAP=1024 HISTORY=1024 CPU_COUNT=1 INVOCATION="java -Xmx${MAXHEAP}M -Xms${MINHEAP}M -XX:+UseConcMarkSweepGC \ -XX:+CMSIncrementalPacing -XX:ParallelGCThreads=$CPU_COUNT -XX:+AggressiveOpts \ -jar $SERVICE$OPTIONS" ME=`whoami` as_user(){ if["$ME"="$USERNAME"];then bash-c"$1" else su-"$USERNAME"-c"$1" fi } mc_start(){ ifpgrep-u$USERNAME-f$SERVICE>/dev/null;then echo"$SERVICE is already running!" else echo"Starting $SERVICE..." cd$MCPATH as_user"cd $MCPATH && screen -h $HISTORY -dmS ${SCREENNAME}$INVOCATION" sleep7 ifpgrep-u$USERNAME-f$SERVICE>/dev/null;then echo"$SERVICE is now running." else echo"Error! Could not start $SERVICE!" fi fi } mc_saveoff(){ ifpgrep-u$USERNAME-f$SERVICE>/dev/null;then echo"$SERVICE is running... suspending saves" as_user"screen -p 0 -S ${SCREENNAME} -X eval 'stuff \"say SERVER BACKUP STARTING. Server going readonly...\"\015'" as_user"screen -p 0 -S ${SCREENNAME} -X eval 'stuff \"save-off\"\015'" as_user"screen -p 0 -S ${SCREENNAME} -X eval 'stuff \"save-all\"\015'" sync sleep10 else echo"$SERVICE is not running. Not suspending saves." fi } mc_saveon(){ ifpgrep-u$USERNAME-f$SERVICE>/dev/null;then echo"$SERVICE is running... re-enabling saves" as_user"screen -p 0 -S ${SCREENNAME} -X eval 'stuff \"save-on\"\015'" as_user"screen -p 0 -S ${SCREENNAME} -X eval 'stuff \"say SERVER BACKUP ENDED. Server going read-write...\"\015'" else echo"$SERVICE is not running. Not resuming saves." fi } mc_stop(){ ifpgrep-u$USERNAME-f$SERVICE>/dev/null;then echo"Stopping $SERVICE" as_user"screen -p 0 -S ${SCREENNAME} -X eval 'stuff \"say SERVER SHUTTING DOWN IN 10 SECONDS. Saving map...\"\015'" as_user"screen -p 0 -S ${SCREENNAME} -X eval 'stuff \"save-all\"\015'" sleep10 as_user"screen -p 0 -S ${SCREENNAME} -X eval 'stuff \"stop\"\015'" sleep7 else echo"$SERVICE was not running." fi ifpgrep-u$USERNAME-f$SERVICE>/dev/null;then echo"Error! $SERVICE could not be stopped." else echo"$SERVICE is stopped." fi } mc_update(){ ifpgrep-u$USERNAME-f$SERVICE>/dev/null;then echo"$SERVICE is running! Will not start update." else as_user"cd $MCPATH && wget -q -O $MCPATH/versions --no-check-certificate https://piston-meta.mojang.com/mc/game/version_manifest.json" if["$1"=="snapshot"];then JSONVERSION=`cd$MCPATH&&catversions|python-c"exec(\"import json,sys\nobj=json.load(sys.stdin)\nversion=obj['latest']['snapshot']\nfor v in obj['versions']:\n if v['id']==version:\n print(v['url'])\")"` else JSONVERSION=`cd$MCPATH&&catversions|python-c"exec(\"import json,sys\nobj=json.load(sys.stdin)\nversion=obj['latest']['release']\nfor v in obj['versions']:\n if v['id']==version:\n print(v['url'])\")"` fi as_user"cd $MCPATH && wget -q -O $MCPATH/versions --no-check-certificate $JSONVERSION" MC_SERVER_URL=`cd$MCPATH&&catversions|python-c'import json,sys;obj=json.load(sys.stdin);print(obj["downloads"]["server"]["url"])'` as_user"rm $MCPATH/versions" as_user"cd $MCPATH && wget -q -O $MCPATH/minecraft_server.jar.update --no-check-certificate $MC_SERVER_URL" if[-f$MCPATH/minecraft_server.jar.update];then if`diff$MCPATH/$SERVICE$MCPATH/minecraft_server.jar.update>/dev/null`;then echo"You are already running the latest version of $SERVICE." else as_user"mv $MCPATH/minecraft_server.jar.update $MCPATH/$SERVICE" echo"Minecraft successfully updated." fi else echo"Minecraft update could not be downloaded." fi fi } mc_backup(){ mc_saveoff NOW=`date"+%Y-%m-%d_%Hh%M"` BACKUP_FILE="$BACKUPPATH/${WORLD}_${NOW}.tar" echo"Backing up minecraft world..." #as_user "cd $MCPATH && cp -r $WORLD $BACKUPPATH/${WORLD}_`date "+%Y.%m.%d_%H.%M"`" as_user"tar -C \"$MCPATH\" -cf \"$BACKUP_FILE\" $WORLD" echo"Backing up $SERVICE" as_user"tar -C \"$MCPATH\" -rf \"$BACKUP_FILE\" $SERVICE" #as_user "cp \"$MCPATH/$SERVICE\" \"$BACKUPPATH/minecraft_server_${NOW}.jar\"" mc_saveon echo"Compressing backup..." as_user"gzip -f \"$BACKUP_FILE\"" echo"Done." } mc_command(){ command="$1"; ifpgrep-u$USERNAME-f$SERVICE>/dev/null;then pre_log_len=`wc-l"$MCPATH/logs/latest.log"|awk'{print $1}'` echo"$SERVICE is running... executing command" as_user"screen -p 0 -S ${SCREENNAME} -X eval 'stuff \"$command\"\015'" sleep.1# assumes that the command will run and print to the log file in less than .1 seconds # print output tail-n$((`wc-l"$MCPATH/logs/latest.log"|awk'{print $1}'`-$pre_log_len))"$MCPATH/logs/latest.log" fi } mc_listen(){ ifpgrep-u$USERNAME-f$SERVICE>/dev/null;then as_user"tail -f $MCPATH/logs/latest.log" else echo"$SERVICE is not running. Cannot listen to server." fi } #Start-Stop here case"$1"in start) mc_start ;; stop) mc_stop ;; restart) mc_stop mc_start ;; update) mc_stop mc_backup mc_update$2 mc_start ;; backup) mc_backup ;; status) ifpgrep-u$USERNAME-f$SERVICE>/dev/null;then echo"$SERVICE is running." else echo"$SERVICE is not running." fi ;; command) if[$#-gt1];then shift mc_command"$*" else echo"Must specify server command (try 'help'?)" fi ;; listen) mc_listen ;; *) echo"Usage: $0 {start|stop|update|backup|status|restart|command \"server command\"}" exit1 ;; esac exit0
Use your favorite editor to create file called minecraft in /etc/init.d/ and paste the script above in that file.
Edit the USERNAME and MCPATH -variables according to your setup. If you use a wrapper script, change INVOCATION to start it instead of starting the server directly.
Make sure the newly created file has required permissions You can set the permissions by running:
chmod a+x /etc/init.d/minecraft
Then run (on Debian-based distributions)
update-rc.d minecraft defaults
Starting with Debian 6.0, the insserv command is used instead, if dependency-based booting is enabled. insserv will produce no output if everything went OK. Examine the error code in $? if you want to be sure.
insserv minecraft
On CentOs and RHEL(Redhat enterprise Linux) You will need to add the process into the chkconfig list chkconfig manages startup scripts under systemd
chkconfig --add minecraft
To check if the process is done correctly use the ntsysv command keep scrolling until you see the minecraft process if you don't repeat the chkconfig command. to add required symbolic links. Note: your system will most likely warn you that the script does not meet all requirements. The script will however work.
You can also setup an entry in your crontab to backup the server. A sample crontab to backup every half hour on the hour, and 30 minutes into the hour:
crontab -e
and add this
0,30 * * * * /etc/init.d/minecraft backup
If the process is unsuccessful, try:
VISUAL=/usr/bin/nano crontab -e
(In debian based GNU/Linux distribution)
update-rc.d -f minecraft remove
(In CentOs/RHEL)
chkconfig --del minecraft
The script may be invoked via the following command on most systems, where "(command)" will be "stop", "start", "restart", or any of the other options it supports.
/etc/init.d/minecraft (command)
On most RedHat- or Debian-based distribution where the `service` command is available, it should be invoked as:
service minecraft (command)
To view the screen, use:
screen -r
To exit the screen, use:
CTRL+a+d
If you still want to view the live log file, use this command in the server directory.
tail -f logs/latest.log
The following scripts offer the same functions as the above script but contain more useful features: