In this post, I’ll describe how to use systemd to manage a Minecraft server. A named pipe will allow us to send commands to that server, which we’ll use in order to set up a job that periodically makes backups and uploads them to Google drive. This may sound fancy, but luckily systemd makes this a breeze to set up, once you’ve done a little Googling.
This tutorial does not assume you’ve ever set up a Minecraft server before. You
don’t need to be familiar with
systemd, but you should know how to use Ubuntu
at a basic level. I won’t cover how to set up an Ubuntu server.
Let’s get started!
Setting up a Minecraft-Server-as-a-Service
First, we must create a systemd service that runs a Minecraft server. You don’t
want to run that server as root, so create a
minecraft user and group:
$ useradd minecraft
Next, install the Java Runtime Environment:
$ sudo apt-get install openjdk-9-jre-headless
Next, let’s create a directory to run the server from. The Minecraft server JAR will go in this directory.
$ mkdir /srv/minecraft/ $ cd /srv/minecraft/ $ curl -o minecraft_server.jar https://s3.amazonaws.com/Minecraft.Download/versions/1.10.2/minecraft_server.1.10.2.jar
At this point, you could start a server by running:
$ java -jar minecraft_server.jar
Instead, we’ll create a service that does almost the same thing, but runs as the
minecraft user we just created.
[Unit] Description=Minecraft server [Service] WorkingDirectory=/srv/minecraft User=minecraft Group=minecraft ExecStart=/srv/minecraft/run-server.sh [Install] WantedBy=multi-user.target
As you can probably guess, this will invoke a file named
create this file in
#!/bin/bash tail -f /tmp/minecraft_server_in | java -jar minecraft_server.jar
You’ll need to
chmod +x run-server.sh.
Before this script can work, we must create a named pipe at
$ mkfifo /tmp/minecraft_server_in
And that’s it, you’ve service-ized Minecraft! You can start the server by running:
$ service minecraft-server start
You can test that the input is working by connecting to your new server, and running:
$ echo "time set day" >> /tmp/minecraft_server_in
Hopefully, dawn’s rosy-red fingers should caress your realm.
Adding a backup job
To take a backup of a Minecraft server, you need to copy the
/srv/minecraft. However, you can’t simply copy that directory at any time;
you need to disable “auto-saving” first. Otherwise, you may get a corrupted copy
of the data, since you might be reading a file while the server is still writing
Luckily, the Minecraft server has some commands to deal with this:
save-allsaves the server
Our approach will be to tell the server to
then monitor the server’s logs, waiting for the server to output “Saved the
world”. Once that happens, we’ll copy the
world directory. When we’re
finished, we run
Create a backup script called
#!/bin/bash echo "save-off" >> /tmp/minecraft_server_in echo "save-all" >> /tmp/minecraft_server_in # See comment below echo "seed" >> /tmp/minecraft_server_in # `journalctl -f` produces an infinite stream of output from the Minecraft server. # `sed` will quit once one of those lines matches "Saved the world". Once `sed` # dies, `journalctl` will die the next time it logs anything -- it will receive a # SIGPIPE. That's why we send "seed" to the server -- it will generate additional # logs that will cause `journalctl` to die. The `stdbuf -oL` is to prevent # buffering from delaying the SIGPIPE. stdbuf -oL journalctl --since "3 seconds ago" -f -u minecraft-server.service | sed '/\[Server thread\/INFO\]: Saved the world/q' # If there's a particular directory you want to put this in, look into the # --parent option. gdrive upload backup.zip --name "backup-$(date).zip" rm backup.zip echo "save-on" >> /tmp/minecraft_server_in
chmod +x on this file. Before this script can work, you need to set up
gdrive. Do so by running:
# This assumes you're using Ubuntu 64-bit. If not, you can use another download # link from https://github.com/prasmussen/gdrive $ curl -o /usr/local/bin/gdrive -L https://docs.google.com/uc?id=0B3X9GlR6EmbnQ0FtZmJJUXEyRTA\&export=download
minecraft user (run
su minecraft), run
gdrive list and it’ll help
you with the Google API key shenanigans.
You’ll also need to add
minecraft to two groups in order to silence a warning:
$ usermod -G adm -a minecraft $ usermod -G systemd-journal -a minecraft $ id minecraft uid=1000(minecraft) gid=1000(minecraft) groups=1000(minecraft),4(adm),101(systemd-journal)
At this point, you should be able to run
backup-job.sh successfully. Once it
finishes executing, you should be able to find a file called “backup-Some Date
Next, we’ll need to create a systemd service and a systemd timer. The timer will
invoke the service periodically, and our new service will run
Create the service in
[Unit] Description=Minecraft Backup [Service] Type=oneshot User=minecraft Group=minecraft WorkingDirectory=/srv/minecraft ExecStart=/srv/minecraft/backup-job.sh
Enable this service with:
$ systemctl enable minecraft-backup.service
You can verify the service works by running:
$ service minecraft-backup start
A backup should appear in your Google Drive.
Next, create the timer in
[Unit] Description=Run minecraft-backup.service daily [Timer] OnCalendar=*-*-* 12:00:00 [Install] WantedBy=multi-user.target
This timer will execute
minecraft-backup.service every day at 12PM. My
server’s clock is on UTC; 12PM UTC is early in the morning in California, where
Kick off your timer by running:
$ systemctl enable minecraft-backup.timer $ systemctl start minecraft-backup.timer
You can check on your timer with
And that’s it, you now have automatic backups! Now go out and have fun.
If you notice any errors or shortcomings in this post, please let me know! You can reach me by emailing: firstname.lastname@example.org .