Skip to content

Run a Minecraft Bedrock Server on Linux under Systemd.

License

Notifications You must be signed in to change notification settings

apiskors/saprolith

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

34 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Saprolith:
------------------------------------------------------------

Run and control the Minecraft Bedrock Edition server on Linux, under
SystemD, using the "mcb" shell script and SystemD service files
provided here.


Download the Server Software from Mojang:
------------------------------------------------------------

Download the "Minecraft Dedicated Server software for Ubuntu (Linux)"
from:

  https://www.minecraft.net/en-us/download/server/bedrock

Note that Mojang/Microsoft periodically updates the server, and does
NOT make older versions available for download!  Different versions
are typically NOT compatible with each other.  Clients and servers
must each be running at least the same major version, and usually the
exact same version.

Mojang also has a bad habit of sometimes using version numbers that
are out of sequence.  E.g., in early May 2022, their current
Production server version was 1.18.33.02, which matched the client
version.  In late May, they updated the server to 1.19.10.20, which
was a bogus version number assigned to what was in fact a beta release
of the upcoming 1.19.0.0.

At that time all normal client software was still running 1.18.x, and
so could NOT work with the 1.19.x server at all.  Eventually, in early
June, Mojang finally released the real Production 1.19.1.01 server
software, and clients started auto-updating to that version within the
next few weeks.

Thus I do NOT recommend auto-installing new versions of Bedrock Server,
but I DO suggest auto-downloading every new version for later use!

The script offers a "download-server" command, which you should schedule
in your crontab once a day or so.  It is careful to always embed the
date in the filename when downloaded.  Thus at the time I'm writing
this, I have these saved versions of the Linux server software:

  bedrock-server_2022-05-14_1.18.33.02.zip
  bedrock-server_2022-05-28_1.19.10.20.zip
  bedrock-server_2022-06-07_1.19.1.01.zip
  bedrock-server_2022-06-23_1.19.2.02.zip


Ubuntu Prerequisites:
------------------------------------------------------------
As this bug ticket describes:

  https://bugs.mojang.com/browse/BDS-16913
  Bedrock server won't start on Ubuntu 22.04 LTS

Bedrock Server still required libssl1.1, but Ubuntu 22.04 (jammy)
ships only with libssl3, and no longer includes libssl1.1 at all.  The
workaround is to simply install libssl1.1 from the older Ubuntu 20.04
(focal), like so:

  echo "deb http://security.ubuntu.com/ubuntu focal-security main" | sudo tee /etc/apt/sources.list.d/focal-security.list
  sudo apt update && sudo apt install libssl1.1

This may no longer be necessary, as that ticket suggests it was fixed
either in bedrock-server 1.19.30 (c. 2022-09-21) or 1.19.51 (2022-12-14).


Initial Install:
------------------------------------------------------------

The script does NOT offer an initial install command.  It DOES have an
upgrade command - more on that below.

Here's how to manually do the initial install:

We ALWAYS want to run the actual server process as Linux user "mc",
NEVER as your own account.  Create the mc user the normal way (on
Debian or Ubuntu), something like this:

  adduser --disabled-password --group mc

Then make sure that your personal Linux account (with sudo) is also a
member of mc's group.

Since we are using multiple Linux users, pay careful attention to
permission settings on files and directories.  You are likely to mess
them up at some point.  If you ever get mysterious errors, check the
file permissions first thing.  A cryptic error message from
bedrock_server might REALLY just mean that it lacks read access to
some important file!

[TODO: I should probably add a command to check and correct file
permissions.]

Install the following Ubuntu packages:

  sudo apt install  screen sysstat zstd

Use Git to clone this project, and put your copy wherever you want.
Then open up your copies of these three files:

  mcb  systemd/[email protected]  systemd/[email protected]

And search for all occurences of "/data" in those files.  Those are
pathnames pointing to either directories or files.  Most of them are
near the top of the files, for easy modification.  Change each of
those settings to the values YOU want.  Those paths are the only
settings that you MUST edit.

For the -s "mc_server" setting, I STRONGLY recommend that you always
use a simple ASCII alphanumeric string with NO punctuation characters
of any sort, not even dashes.  (Underscores are probably ok.)  I
usually just use "mc1", "mc2", "mc3", etc.  This is because SystemD's
Template unit files aggressively escape such strings, converting
e.g. "my-server-name" into a different (ugly and inconvenient) string.
This project makes NO attempt to handle such escaped strings; it is
easiest to just avoid them.  See also:

  https://www.freedesktop.org/software/systemd/man/systemd.unit.html#id-1.6
  String Escaping for Inclusion in Unit Names

In the script, you may also want to change the default "mc_user" and
"mc_server", although you can always specify them on the command-line
instead.

By default, the "[email protected]" and "[email protected]" files
are configured to backup and restart your Minecraft server every day
at 4 am.  If you want a different schedule, simply edit those files.
(And then later tell SystemD about the changes.)

Once you have those files edited the way you like, use should probably
use Git to commit your changes locally, so you can track your own
version history.  [TODO: Add tips on how to avoid conflicts with my
upstream changes.]

Next, copy the three SystemD service files into the location they'll
actually run from:

  sudo cp -p systemd/mcb*{.service,.timer} /etc/systemd/system/

It is not convenient to actually use version control on the live
/etc/systemd/system/mcb* files, so what I do is keep them in sync with
my version-controlled copy in saprolith/systemd/.  The script includes
a command to compare the files in the two locations with diff like so:

  ./mcb svc-diff

Create the directory where your new bedrock_server will live, and
unzip the bedrock_server software into it.  In my case here, my new
server is named "mc3", so:

  cd /data/jails/mc-1/
  umask 002 ; mkdir mc3 ; chgrp mc mc3 ; chmod 2775 mc3
  cd /data/jails/mc-1/mc3/
  sudo -u mc unzip /data/pub/download/minecraft/bedrock-server/bedrock-server_2022-06-23_1.19.2.02.zip

Next shut down your running bedrock_server (if any), take a backup,
LEAVE it down, and restore that latest backup into your new directory
above.  We also should disable your old SystemD service (if any) now,
rather than waiting till later.

Note that restoring the backup from your old "mc2" server creates an
"mc2" subdirectory inside the new "mc3".  This lets you compare the
old files to any new stock versions from Mojang.  E.g., you might want
to examine the new stock server.properties before you replace it with
your own old file.

Also, you want most but NOT necessarily all files from your backup.
In particular, (so far) I think the valid_known_packs.json is specific
to the version of the software you will run, NOT to the world you have
saved.  So I recommend NOT restoring that file.

  ./mcb -s mc2 d-status
  sudo ./mcb -s mc2 d-stop backup d-disable
  cd /data/jails/mc-1/mc3/ ; umask 002
  sudo -u mc tar xf /data/jails/mc-1/mc-backups/mc2.2022-06-26T13-53-08.tar.zst
  rm mc2/valid_known_packs.json
  mv mc2/* . ; rmdir mc2

Your old worlds/, server.properties, allowlist.json, etc. should now
be restored into your new directory.  If you are starting a new server
from scratch, edit your "server.properties" etc. as you like.

Enable your new server in SystemD, start it up, and then check that
the server side of things seems to be working correctly:

  sudo ./mcb -s mc3 d-enable d-start
  ./mcb -s mc3 d-status
  ps -u mc -f
  tail /data/jails/mc-1/mc3/logs/mc3.2022-06.log
  journalctl -n 50 -u [email protected]
  journalctl -n 50 -u [email protected] -u [email protected]

Finally, open up your Minecraft client, and verify that it can connect
to and play in your new server world!


Upgrade Install:
------------------------------------------------------------

To upgrade, we always install to a new empty directory and restore
from a backup file.  Your old directory remains as is, untouched,
until YOU decide to delete it.

You'll have noticed that in the previous "Initial Install" section I
actually did a manual upgrade.  Essentially that same process is now
automated.  Here's an example of running it:

  sudo ./mcb -s mc1 -n mc2 -z bedrock-server_2022-08-10_1.19.20.02.zip upgrade

If I get some of the command-line settings badly wrong above, like
leaving off sudo, the script will "pretend" to proceed, showing as
much as possible of what it WOULD do, without actually changing
anything important.  So, you may wish to run an upgrade command like
the above WITHOUT sudo as a test run, and then finally add sudo at the
end when you're convinced you have the command line correct.

Be careful.  The upgrade does everything in one shot, it does NOT stop
and pause for any sort of human interaction.


Regular Operations:
------------------------------------------------------------

Our SystemD services are configured to automatically start every time
your Linux box boots, so you normally shouldn't need to do much of
anything.

As discussed above, you probably want to use crontab to check for and
download new versions of bedrock_server every day.  Something like:

13 06 * * *  (umask 002; /data/jails/mc-1/saprolith/mcb download-server)

I definitely recommend reading the script to see what further features
it supports!


In-Game Server Commands:
------------------------------------------------------------

There are two ways you can give commands to the running bedrock_server.
One, you can use the script to send them from the Linux command line, e.g.:

  sudo -u mc ./mcb -s mc3 cmd 'say Everybody having fun?'

Or, you can take over the screen session that's running the
bedrock_server, type your commands normally at the console, then
detach from the screen session and leave it running.  Something like
this:

  sudo -u mc screen -list
  sudo -u mc screen -d -r mc3

  gamerule showcoordinates true
  say Hey Everybody, GPS coordinates should be turned on now.
  allowlist add MyFavoritePlayer
  allowlist reload
  Ctrl-o d


Known Bugs or Problems:
------------------------------------------------------------

Running multiple Bedrock servers on the same machine may not work, due
to well-known limitations and bugs in Mojang's bedrock_server software:

  https://bugs.mojang.com/browse/BDS-1094
  Additional IPv4 and IPv6 port opening upon starting server

  https://bugs.mojang.com/browse/BDS-3989#comment-979611
  Default server port is used even if another port is defined

  TheRemote/MinecraftBedrockServer#70 (comment)
  Bedrock Server is not listening to Ports #70

  https://bugs.mojang.com/browse/BDS-10608
  Can't connect from non-local networks (outside of LAN)

  https://feedback.minecraft.net/hc/en-us/community/posts/360040238051-Multiple-Worlds-on-One-Bedrock-Server?page=1#community_comment_360010427012

So far I haven't actually tried running multiple servers myself.  If I
do, perhaps I'll add workarounds for the problems to this project.


Other Potentially Useful Tools:
------------------------------------------------------------

Phantom, a proxy to make remote Bedrock Servers look like they are on
your LAN:
  https://github.com/jhead/phantom


Design and Implementation Notes:
------------------------------------------------------------

This tool is a relatively simple Bourne Shell script that you run
as-is, possibly after changing some default settings near the top of
the script.  It does not need to be installed in any particular way,
and ONE copy of the script should work for any number of Minecraft
servers you wish to run.

It was inspired by, and some bits copied from, the MinecraftBedrockServer
scripts by James Chambers:

  https://github.com/TheRemote/MinecraftBedrockServer
  https://jamesachambers.com/minecraft-bedrock-edition-ubuntu-dedicated-server-guide/

This tool purposely does NOT include many of Chambers's features, as I
wanted something simpler, easier for me to extend, and using certain
different approaches.  But his scripts are a valuable source of
examples of how to do many tasks.

I developed and tested this only on Linux, initially Ubuntu 20.04 LTS,
and later Ubuntu 22.04 LTS.  It may well require tweaking for other
distributions.

This project includes three SystemD scripts in its "systemd" subdirectory.
Because they use SystemD's "templating" feature (with %I etc.), these
three files plus the mcb script itself are all you need.  You will
need to tweak the hard-coded path names, but otherwise this set of
files should work as-is for any number of servers you want to run.

The shell script uses /bin/sh.  Bash is not necessary.  However, my
Linux /bin/sh is actually dash.  Truly ancient Bourne Shell versions
(sometimes included with non-Linux Unix systems) would probably break
on trivial syntax errors, and might also break in trickier more
fundamental ways.  (E.g., modern Bourne shells always have SEPARATE
positional parameter lists for individual functions vs. the whole
script, but some older shells did not.)

Mojang's "alpha" Minecraft bedrock_server is not a traditional Unix
daemon, it runs attached to a terminal in the foreground.  Also,
unlike their Java Edition server, which can accept commands via the
RCON protocol, the ONLY way to give bedrock_server commands is via its
terminal.

On Linux there are many different ways to "daemonize" a foreground
terminal app like bedrock_server.  For discussion of some of the
options, see e.g.:

  https://unix.stackexchange.com/questions/453998/systemd-connect-to-stdin-stdout-after-service-has-started
  https://blogs.gentoo.org/marecki/2020/09/16/console-bound-systemd-services-the-right-way/

Here I have certain specific requirements:
1. Run bedrock_server in the background, from the SystemD init service.
2. Give a way to write to the console's stdin, for issuing commands.
3. Log all stdout from the console to a file, so we can easily see what
   the server says has been happening.

It is possible to do both [1] and [2] with SystemD alone.  However
some of that is tricky, and I don't see any good way to do [3]
(logging) at all.  Yes, SystemD's journalctl is useful, but I don't
want ALL bedrock_server output to go to the SystemD journal.

dtach is smaller and simpler than Gnu Screen, should have a smaller
attack surface, and is likely easier to run inside a chroot jail (or
other similar confined environment).  It should do [1] and [2] just as
well as screen, but it lack's screen's "-Logfile" option, so AFAICT
[3] is not possible.  (I have no idea whether it would be feasible to
add logfile support to dtach.)

Note that the bedrock_server binary already prefixes most of its
output with its own timestamps.  If you really want to pre-pend your
own additional timestamps, you can easily do so by piping stdout
through Awk.  (mawk and gawk both have strftime now, so either will
work.)  So in the script, you'd change the command string you pass to
'/bin/sh -c' from this:
  "LD_LIBRARY_PATH=$base_dir $bs_bin"
to something like this:
  "LD_LIBRARY_PATH=$base_dir $bs_bin | awk '{ print strftime(\"[%Y-%m-%d %H:%M:%S %z %a]\"), \$0 }'"

My use of "sudo -u $mc_user" when "backup" calls mc_screen_session()
seems a bit ugly, but I couldn't think of anything better.  Of course
my Linux account has sudo, while mc's does not.  This article has some
interesting related commentary:

  http://jdebp.info/FGA/dont-abuse-su-for-dropping-privileges.html

But I think its criticisms (and advice to use setuidgid, setpriv, or
the like) are not relevent here, as I (typically) do NOT want to run
the script as root and then drop privileges by switching to the mc
user.  Rather I am running the script as me, and really do need to
explicitly switch to user mc for certain commands.


Security Notes:
------------------------------------------------------------

We are running the bedrock_server binary provided by Mojang/Microsoft,
and have no ability to audit its source code in any way.  Oh well.
That means the best we can do is to limit the damage if/when a remote
attacker manages to compromise the running bedrock_server process.
Fortunately modern Linux distributions give us tools to help with that.

In "systemd/[email protected]", I turn on many SystemD security features.
This seems like enough to me, while still keeping things fairly simple.

It is of course possible that some future bedrock_server will include
new features that break due to those security restrictions.  If so,
you can test the obvious way, by repeatedly commenting out various
lines in the service file, restarting the service, and seeing whether
it works correctly.  That's how I figured out that for SystemCallFilter,
the bedrock_server NEEDS @privileged, @chown, and @setuid, but it's ok
to turn off most of the others.

If you want to lock things down further, there are two approaches you
could try:

One, right now a remote attacker who takes control of the running
bedrock_server process would have read-access to all the normal Linux
binaries and libraries (although limited by RestrictSUIDSGID=yes,
etc.), and could attempt to use them for some sort of privilege
escalation attack.

To further reduce that attack surface you could try using the SystemD
TemporaryFileSystem, BindReadOnlyPaths, etc. directives to hide ALL
the normal Linux binaries and libraries, and then make only the bare
minimum available to the running bedrock_server.  (But since we are
using dash and screen, that "bare minimum" might be rather large.)

Essentially you would build a chroot-like environment, although you'd
likely want to do it using the SystemD Linux kernel tools, rather than
the older (but cross-platform) chroot call.  (If you did use chroot,
you'd probably want to use a tool to make setting up the the chroot
environment easier, like Olivier Sessink's JailKit.)

Two, you could run all this inside a virtualized container of some
sort, such as Red Hat's Podman.  Others have done similar setups, e.g.:

  https://github.com/TheRemote/Legendary-Bedrock-Container
  https://jamesachambers.com/legendary-minecraft-bedrock-container/

Good luck!

About

Run a Minecraft Bedrock Server on Linux under Systemd.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages