Der Header: Enauts Thinking!
created:Sun 12 Apr 2015
edited:Mon 04 Sep 2017

Setting up a Minecraft server using Systemd

Minecraft is a well liked sandbox game that can provide hours and days of gaming fun especially if it is on a server with multiple players.

In this article I will describe the setup I used. The important parts of the setup are:

  • spigot as the server
  • Fedora 21 is the OS I'm on
  • systemd including service file and "sandboxing"
  • firewalld to block and open ports
  • mcrcon for connecting to the running instance

Preparing the operating system

First of there are some things in the operating system that improve security and separation from the rest of the server. As a first step we create a dedicated linux user for minecraft:

root# groupadd -r minecraft
root# useradd -r -g minecraft -d "/var/minecraft" -s "/bin/bash" minecraft

The created user has his home directory in /var/minecraft which will be the directory of most of the files that will be installed. The user has no password so you cannot login with it. To change to the minecraft user you have to use su minecraft as root.

root# mkdir -p /var/minecraft/{backup/server,build/spigot,build/mcrcon,server}

This will create the four directories backup, build/spigot, build/mcrcon and server in /var/minecraft.

  • The build directory will contain the build environment for spigot and mcrcon since it is not possible to download the binary servers anymore.
  • The server directory will contain the actual server and maps.
  • The backup directory is something I use to backup old server binaries should an upgrade fail.

The server

For the server update and initial download I created a small bash script:

#!/bin/env bash

# Download
wget https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar  -O BuildTools.jar &> lastdl.log && echo "Download Successful"

# Build
java -jar BuildTools.jar &> lastbuild.log && echo "Build Successful"

# Backup
mv ../../server/spigot.jar ../../backup/server/`date +"%Y-%m-%H-spigot.jar"` && echo "Backup Successful"

# Install
mv spigot-1.*.jar ../../server/spigot.jar && echo "Install Successful"

So simply copy and paste that script into the file /var/minecraft/build/spigot/update.sh and make it executable and change group and owner to the minecraft user.

root# vim /var/minecraft/build/spigot/update.sh # and paste the script
root# chmod +x /var/minecraft/build/spigot/update.sh
root# chown minecraft.minecraft -R /var/minecraft/

Next we download and build the server to do so we first change to the minecraft user and the build/spigot directory. Then we execute the update.sh script. The first time the script is run it shows that it can't move the old server binary wich is expected.

root# su minecraft
minecraft> cd ~/build/spigot
minecraft> ./update.sh

After that step you should have a nice binary /var/minecraft/server/spigot.jar. If you want to check if you are up to date with the tutorial you can try to execute it with java -jar spigot.jar. It will then create all the config files.

Downloading and building mcrcon

Mcrcon is a very small tool that allows to connect to a running minecraft server instance and issue some commands. Since the binary is only available in 32bit for linux I compiled it from source which works like a charm:

root# su minecraft
minecraft> cd ~/build/mcrcon
minecraft> git clone  git://git.code.sf.net/p/mcrcon/code mcrcon-code
minecraft> cd mcrcon-code
minecraft> gcc mcrcon.c -o mcrcon
minecraft> cp mcrcon ~/

If your server is already running you can try the mcrcon tool by executing:

minecraft> ./mcrcon -H localhost -P $port -p $password -t

Replace the port and password with the values specified in the server.properties file. In this howto the next step is to create a systemd minecraft.service file.

The systemd service file

The systemd service file took quite some time for me to create but I think it is quite nice. So here it is (a line by line explanation follows):

[Unit]
Description=Minecraft Server
Documentation=

Wants=network.target
After=network.target

[Service]
User=minecraft
Group=minecraft
Nice=5
EnvironmentFile=-/var/minecraft/unit.conf
KillMode=none
SuccessExitStatus=0 1

ProtectHome=true
ProtectSystem=full
PrivateDevices=true
NoNewPrivileges=true
PrivateTmp=true
InaccessibleDirectories=/root /sys /srv -/opt /media -/lost+found
ReadWriteDirectories=/var/minecraft/server
WorkingDirectory=/var/minecraft/server
ExecStart=/usr/bin/java -Xmx1024M -Xms1024M -jar spigot.jar --noconsole
ExecStop=/var/minecraft/mcrcon -H localhost -P $port -p $password stop

[Install]
WantedBy=multi-user.target

First the easy things: line 2 and 3 contain descriptive information you can fill in anything you like. Line 5 and 6 say that this service likes to have network available.

The Service section is the one that gets more interesting. lines 9, 10 and 11 restrict the minecraft server so that it is run as minecraft user and group with a nice level of 5 meaning that it has a lower priority than most other things that run on the server. I do that because my server hosts other services besides the minecraftserver that are more important to me.

With line 12 I import a unit.conf file that can be used to set various environment variables. I thought it might be usefull but actually I didn't use it.

Line 13 and 14 are more important again KillMode=none says that the server is not killed when the service is stoped but instead the ExecStop command is used to gracefully stop the server. The next line marks the service as sucessfully exited.

The following lines regulate the access of the server. So if the server should be compromised in any way it should not be able to acess anything outside the /var/minecraft/server directory.

ExecStart specifies the command that fires up the server. If you want to pass more advanced options to the server then this is most probably the place to do so.

ExecStop specifies the command that is issued to stop the server. you have to replace $port and $password with the actual values you specify in the server.properties file of the minecraft server.

The Install section specifies how to enable this service so that it is started every boot.

Create the file in the directory /etc/systemd/system/minecraft.service and paste the contents from above.

Note on CentOS

As CentOS has a quite old systemd Version there are some features missing. So on CentOS you have to drop the ProtectHome, ProtectSystem and PrivateDevices otherwise you will probably get warnings in the log because those options were introduced in Systemd v214.

Setting up the server

First of all you have to accept the eula to do so you have to add the line eula=true to /var/minecraft/server/eula.txt. This file should be generated when you first run the server.

Now you are ready to set up your server. This is done in the file /var/minecraft/server/server.properties most of the setings do have good default values but everything can be changed as you like see: server.properties

The following 3 properties are important for the systemd minecraft.service file to work properly. They enable the rcon protokoll of the minecraft server. You can connect to a running instance and execute commands using rcon. the systemd service uses this in its ExecStop part to gracefully shut down the server.

The following settings have to be changed in /var/minecraft/server/server.properties for this setup to work(keep replacing $port and $password with your own values):

rcon.port=$port
rcon.password=$password
enable-rcon=true

There are a lot of additional options in /var/minecraft/server/bukkit.yml and /var/minecraft/server/spigot.yml change anything you like to change.

Securing the server

Since Fedora uses Firewalld I created a nice little firewalld service file in /etc/firewalld/services/Minecraft.xml with the following contents:

<?xml version="1.0" encoding="utf-8"?>
<service>
  <short>Minecraft</short>
  <description>The Minecraftserver that runs on this host. This service has a customized Port.</description>
  <port protocol="tcp" port="$minecraftport"/>
</service>

remember to change the portnumber to the one you specified in server.properties

Now we need to reload the firewall so that it sees the new servicefile and then enable it permanently with:

root# firewall-cmd --reload
root# firewall-cmd --add-service Minecraft --permanent

Running the server

Now comes the big time where you can start your nicely setup server for the first time. First systemd might not be aware of your new minecraft.service so reload it quickly then start the server.

root# systemctl daemon-reload
root# systemctl start minecraft

it should return promtly to the promt and then you can read all the log entries with:

root# journalctl -u minecraft -f  # To see an updating log
root# journalctl -u minecraft # To see all logs in a less like viewer.

Somewhere when the logs stop scrolling you should see something like Done (4.406s)! For help, type "help" or "?" indicating that the server has started successfully. If not try to consult the journal-log what might be missing.

You can then stop the server with systemctl stop minecraft and go then check if the server was nicely shut down without being killed in mid shutdown. More specifically you should see for every world a message in the journal that it is being saved.

If the shutdown is not working correctly then you should first try that the rcon connection is working by manually executing the rcon command from ExecStop.

Finally when everything is working as expected you can enable the service with:

root# systemctl enable minecraft

If you want to update the server try the following commands:

root# su minecraft
minecraft> cd ~/build/spigot/
minecraft> ./update.sh
Download Successful
Build Successful
Backup Successful
Install Successful
minecraft> exit
root# systemctl restart minecraft

Play and profit

Whenver you reboot now the minecraft server is automatically started the appropriate ports are open and everything should be set up for a happy gaming experience.

Comments

created:Sat 25 Jul 2015
edited:Tue 28 Jul 2015

LOAS

This article was exactly what I needed to very quickly get a minecraft server running on my centos 7 server. I had to modify the minecraft.service file a bit, which may have reduced the process isolation a bit.

Thanks a bunch!

created:Fri 31 Jul 2015
edited:Sun 02 Aug 2015

Brandon Zylstra

The script fails in a couple of places.

../../backup/server/ doesn't exist and must first be created.

spigot-1.*.jar doesn't exist either, but I'm not clear on the purpose of this line.

Also, didn't you mean to use cp instead of mv for the backup?

created:Sun 02 Aug 2015
edited:Sun 02 Aug 2015

enaut

Hey Brandon, I added the directory in the mkdir statement. so that should be fixed. As for the Spigot-1.*.jar this file should be created by the build process during the build step in line 7. If it does not exist please check the build log in lastbuild.log.

Also note that this script is customized and pretty much hardcoded for my system. I just added it for others to edit it for their needs.

hope that helped.

created:Sun 13 Sep 2015
edited:Sun 20 Sep 2015

Rob

LOAS could you post the modifications you made? I'm getting Failed at step NAMESPACE spawning /usr/bin/java: Operation not permitted and similar errors when trying to start the process.

created:Sun 20 Sep 2015
edited:Sun 20 Sep 2015

enaut

Hey Rob, I never got that error so I cannot guess what went wrong. However I can try to help you debug the issue. First of is java there? What happens if you execute /usr/bin/java. Next I'd try to run the command from the ExecStart line in the systemd service. Next I'd try to change the user using su to the minecraft user and run the same command again - Carful to change all the permissions of previously generated files accordingly! last run the service and see what happens in the journal.

created:Fri 06 Nov 2015
edited:Tue 08 Dec 2015

Duke

I'm getting the same error on Centos 7. Failed at step NAMESPACE spawning /usr/bin/java: Operation not permitted

note: I do have SE linux enabled 8)and if possibleI'd like to keep it that way.

created:Sat 21 Nov 2015
edited:Tue 08 Dec 2015

Randell Jesup

Thanks! For Fedora 22, java was in /bin/java instead of /usr/bin/java, and /var/minecraft/unit.conf has to exist or it will fail to start the service

created:Sun 06 Dec 2015
edited:Mon 18 Jan 2016

wolfgang dragunov

i'm having the same problem as Rob. i can start the server manually with the command from the service file as root. i have checked file permissions. i have a vanilla minecraft server running to test with but stop it when trying to get this permanent solution running.

systemd[1]: [/etc/systemd/system/minecraft.service:15] Unknown lvalue 'ProtectHome' in section 'Service'
systemd[1]: [/etc/systemd/system/minecraft.service:16] Unknown lvalue 'ProtectSystem' in section 'Service'
systemd[1]: [/etc/systemd/system/minecraft.service:17] Unknown lvalue 'PrivateDevices' in section 'Service'
systemd[1]: Starting Minecraft Server...
systemd[1]: Started Minecraft Server.
systemd[16106]: Failed at step NAMESPACE spawning /usr/bin/java: Operation not permitted
systemd[1]: minecraft.service: main process exited, code=exited, status=226/NAMESPACE
systemd[16108]: Failed at step NAMESPACE spawning /var/minecraft/mcrcon: Operation not permitted
systemd[1]: minecraft.service: control process exited, code=exited status=226
systemd[1]: Unit minecraft.service entered failed state.
created:Tue 08 Dec 2015
edited:Tue 08 Dec 2015

enaut

Sorry for not responding... :( I will look into your problem when I find time. And I really have to add some formatting to the comments... The fact that wolfgangs post looks so ugly is really all my fault! - why do I allways have to use my own software I can only blame myself :P

created:Fri 11 Dec 2015
edited:Sat 12 Dec 2015

ise

For me, to solve the NAMESPACE issue, i just had to remove certain configurations from the systemd script... I used this as the basis: http://linuxrackers.com/doku.php?id=creating_a_custom_systemd_service_script_for_minecraft

I modified the systemd config SERVICE section to use only User, Group, WorkingDirectory, ExecStart and ExecStop

(merged two comments to one by enaut)

created:Sun 13 Dec 2015
edited:Sun 13 Dec 2015

enaut

I now enabled SELinux on my Fedora 23 server and I did not hit any issue with NAMESPACE.It might be some issue with the older Version of Systemd in CentOS?

created:Sun 13 Dec 2015
edited:Mon 14 Dec 2015

wolfgang dragunov

i managed to get the server working following ise's suggestions. i am using centos 7. the only other change i made was to the firewall. after creating the firewalld service the port still wasn't open, so i just added through add-port.

created:Mon 14 Dec 2015
edited:Mon 14 Dec 2015

enaut

Thanks to your help I tracked the issue down. - at least I think so as I cannot test it.

The ProtectHome, ProtectSystem and PrivateDevices options have been added with systemd v214 while CentOS uses 208 I think.

I hope that solved some of the problems and I added a note to the article :).

created:Wed 23 Dec 2015
edited:Mon 28 Dec 2015

bajr

Running CentOS 7 here and systemd v208. I encountered the same problem with the Namespace error. I was able to resolve it completely by removing /lost+found from the InaccessibleDirectories directive. (Even better, prepend it with a '-' so the directory's presence is optional.)

After I did this, I don't encounter the error, even when I include the ProtectHome, ProtectSystem, etc directives that aren't supposed to be supported by v208... interesting.

Hope this helps.

created:Sat 06 Feb 2016
edited:Sat 06 Feb 2016

enaut

@ bajr

Thanks for solving the issue! I adjusted the article to use the - prefix and modified the note for CentOS. According to documentation systemd throws a warning on unknown Variables but does run without problem.

created:Wed 18 May 2016
edited:Tue 31 May 2016

bipsen

I tried to use the description to set up systemd file on a debian jessie on raspberry Pi ... When trying to start, I get:

May 18 20:40:56 minecraft.vangevej1.dk systemd[1]: Starting Minecraft Server...
May 18 20:40:56 minecraft.vangevej1.dk systemd[1]: Started Minecraft Server.
May 18 20:40:56 minecraft.vangevej1.dk systemd[10549]: Failed at step USER spawning /opt/jdk1.8.0_102/bin/java: No such process
May 18 20:40:56 minecraft.vangevej1.dk systemd[1]: minecraft.service: main process exited, code=exited, status=217/USER
May 18 20:40:56 minecraft.vangevej1.dk systemd[1]: minecraft.service: control process exited, code=exited status=217
May 18 20:40:56 minecraft.vangevej1.dk systemd[1]: Unit minecraft.service entered failed state.

But the java binary exists:

# ls -l /opt/jdk1.8.0_102/bin/java
-rwxr-xr-x 1 uucp 143 5920 Apr 26 06:39 /opt/jdk1.8.0_102/bin/java

Any clue on how to fix iy ?

created:Tue 31 May 2016
edited:Tue 31 May 2016

enaut

Mhm I can only guess there!

The thing that confuses me is the No such process part.

Do you happen to use Variables in lines besides execstart?

You could try removing the "sandboxing" for testing purposes (in my file line 16 to 21 - note that in line 21 /opt/ is explicitly set to be invisible but I thought that this is only for the running processes).

Oh and did you double check that the user and group specified in the systemd service file exist?

created:Mon 18 Jul 2016
edited:Sun 24 Jul 2016

goober

I'm using Centos 6, 64-bit, and It's ydying in the BuildTools.jar:

Git name not set, setting it to default value.
Exception in thread "main" java.io.IOException: Cannot run program "git" (in directory "."): error=13, Permission denied
        at java.lang.ProcessBuilder.start(ProcessBuilder.java:1047)
        at org.spigotmc.builder.Builder.runProcess(Builder.java:538)
        at org.spigotmc.builder.Builder.main(Builder.java:161)
Caused by: java.io.IOException: error=13, Permission denied
        at java.lang.UNIXProcess.forkAndExec(Native Method)
        at java.lang.UNIXProcess.<init>(UNIXProcess.java:187)
        at java.lang.ProcessImpl.start(ProcessImpl.java:130)
        at java.lang.ProcessBuilder.start(ProcessBuilder.java:1028)
        ... 2 more
created:Thu 21 Jul 2016
edited:Sun 24 Jul 2016

angrymoose

Thanks for sharing!

When using minecraft_server.jar instead of spigot.jar in combination with:

KillMode=none
SuccessExitStatus=0 1

The java process did not actually exit after systemctl stop minecraft.service

Java apparently exits with status 143 on sucess when receiving SIGTERM. So you can ommit the KillMode option and set

SuccessExitStatus=143

Here is my version of minecraft.service:

[Unit]
Description=Aquarium Minecraft Server

Wants=network.target
After=network.target

[Service]
User=minecraft
Group=minecraft
Nice=5
SuccessExitStatus=143

ProtectHome=true
ProtectSystem=full
PrivateDevices=true
NoNewPrivileges=true
PrivateTmp=true
InaccessibleDirectories=/root /sys /srv -/opt /media -/lost+found
ReadWriteDirectories=/var/minecraft/server
WorkingDirectory=/var/minecraft/server
ExecStart=/usr/bin/java -Xmx4096M -Xms4096M -jar minecraft_server.1.10.2.jar nogui

[Install]
WantedBy=multi-user.target
created:Sun 24 Jul 2016
edited:Sun 24 Jul 2016

enaut

@goober

This sounds like an issue with permissions to me. so probably you have no write permissions for the directory/or there are files in the directory that you do not have write permissions for. Also is the git binary executable?

@angrymoose

If I recall correctly I added the KillmodeNone because I shut the server down with rcon see the ExecStop line. Without that gracefull shutdown I was never seeing the Saving worlds line which got me suspicious. So my approach is to log into rcon and shutdown gracefully and do not let systemd interfere no matter how long the server needs to shut down. So with ExecStop set correctly the server should be shutting down.

created:Sun 05 Mar 2017
edited:Sun 05 Mar 2017

docsen

ough hi... first problem is that i cant user "localhost" nor "127...." for rcon, therefore i used the real broadcast IP. Yes i am trying to find the fault.. guess its portforwarding...

anyway:

I tried to restart from INGAME the MCinstance by using /restart in chat.. after a while i had a sniff into the journal and found this:

Mar 05 16:03:18 ChaosKiste java[750]: [16:03:18 INFO]: Saving chunks for level 'world_nether'/Nether
Mar 05 16:03:18 ChaosKiste java[750]: [16:03:18 INFO]: Saving chunks for level 'ender'/The End
Mar 05 16:03:19 ChaosKiste mcrcon[2197]: Error: connection failed (88.198.XXX.XXX (i made it blind)).
Mar 05 16:03:19 ChaosKiste systemd[1]: minecraft.service: control process exited, code=exited status=255
Mar 05 16:03:19 ChaosKiste systemd[1]: Unit minecraft.service entered failed state.

any clue? can you push me in the right direction please? thanks a bunch :) doc

created:Sun 05 Mar 2017
edited:Sun 12 Mar 2017

enaut

Hey docsen,

first of... rcon is unencrypted (even password transmission)... so this should be really an exception...

So if you do a restart from within minecraft minecraft exits with an exitcode bigger than 255 (which is limited to 255) this causes systemd to think that it did not exit cleanly. You can tell systemd that 255 is perfectly fine by adding 255 to the line that says SuccessExitStatus=0 1 in the minecraft.service file.

That however only hides the error. You can make the server restart, by adding Restart=always see https://www.freedesktop.org/software/systemd/man/systemd.service.html#Restart=

Now your server should restart after you entered the restart command. I don't have enough information on your rcon issue - I just don't know what to look for.

created:Wed 05 Apr 2017
edited:Thu 06 Apr 2017

thundercrack

This saved me a ton of time, thank you!

created:Sat 20 May 2017
edited:Sat 20 May 2017

TinfoilSubmarine

Arch user here, had to modify the InaccessibleDirectories directive so that /media was optional, as suggested by bajr (i.e., changing from /media to -/media). Thanks for the work you did here so that I didn't have to!

created:Thu 24 Aug 2017
edited:Fri 25 Aug 2017

FlyingMongoose

Latest version of CentOS 7 has systemd 219

# systemctl --version
systemd 219
+PAM +AUDIT +SELINUX +IMA -APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ -LZ4 -SECCOMP +BLKID +ELFUTILS +KMOD +IDN

I'm running on Centos 7.3

The only modification I had to make was to comment/remove ProtectHome, but ONLY because I actually install my stuff onto the user, and if ProtectHome is enabled it prevents the functions from being accessible.

created:Sun 03 Sep 2017
edited:Mon 04 Sep 2017

madhartigan

Are the three lines found in the code window of the Setting up the Server section supposed to be added to the file minecraft.service or are they intended to be executed from the command line?

There's no command prompt in front of them, so I'm assuming they're additional lines to be added to minecraft.service, but that's not clear.

Let me know.

Thanks!!

created:Mon 04 Sep 2017
edited:Mon 04 Sep 2017

enaut

@madhartigan

No those three lines are settings of the minecraft server they are intended for the /var/minecraft/server/server.properties settings file (if you stick to the paths used here). Usually they already exist and only need to be changed.

I made that more clear.

created:Mon 04 Sep 2017
edited:Mon 04 Sep 2017

madhartigan

You completely exceeded my expectations for response time. Thank you SO much. Sincere credit for maintaining your page properly. Thank you so much!!!

created:Sat 04 Nov 2017
edited:Sun 05 Nov 2017

Jwguy

Worked one time, and now no longer starts the server. Keeps procing the following:

Nov 04 05:25:19 dedicated1335252.mcprohosting.com systemd[1]: Started Minecraft Server.
Nov 04 05:25:19 dedicated1335252.mcprohosting.com systemd[1]: Starting Minecraft Server...
Nov 04 05:25:19 dedicated1335252.mcprohosting.com java[2387]: Usage: java [-options] class [args...]
Nov 04 05:25:19 dedicated1335252.mcprohosting.com java[2387]: (to execute a class)
Nov 04 05:25:19 dedicated1335252.mcprohosting.com java[2387]: or  java [-options] -jar jarfile [args...]
Nov 04 05:25:19 dedicated1335252.mcprohosting.com mcrcon[2408]: Error: connection failed (localhost).
Nov 04 05:25:19 dedicated1335252.mcprohosting.com systemd[1]: minecraft.service: control process exited, code=exited status=255
Nov 04 05:25:19 dedicated1335252.mcprohosting.com systemd[1]: Unit minecraft.service entered failed state.
Nov 04 05:25:19 dedicated1335252.mcprohosting.com systemd[1]: minecraft.service failed.
created:Sun 05 Nov 2017
edited:Sun 05 Nov 2017

enaut

There seems to be some issue with your minecraft.service file. The command posted in ExecStart is not correct. You can simply copy and paste that command to a terminal and try executing it there. It will probably print an error.

When you fixed the command you can readd it to your service file - careful with paths as they might be different.

created:Wed 20 Dec 2017
edited:Wed 20 Dec 2017

gcarvelli

I've set up a minecraft server to work with systemd before but this solution is a lot more complete than what I came up with. The ExecStop mcrcon call to stop the server is a cool idea and way more elegant than just killing it outright.

Great post!

created:Wed 20 Dec 2017
edited:Wed 20 Dec 2017

enaut

Thank you!

I have even further improved this by adding socket activation...

I will need some quiet hours to document this though.

merry xmas

Add a new comment

Note that all comments are moderated - so your post will not appear till I find time to accept it.

The comments do use markup syntax.

Name:
Email:
Confirm Email: leave the above line empty!
Comment: