Dockerize the Minetest server

Please note: This article was migrated from the old website

Dockerizing Minetest makes hosting a Minetest server much easier than it used to be, especially when it comes to more complicated setups, e.g. when using PostgreSQL as database backend and sofar’s Minetest Media Server for media delivery. In this first article, I’ll show you how to dockerize the Minetest server.

What you’ll need

  • A Docker-compatible OS, perferably a Linux of your choice; I’m using Ubuntu 16.04 for this article
  • sudo access for running Docker

Prerequisites

Please follow the instructions on docker.com to install Docker on your OS.

Creating the Dockerfile

TLDR: Final Dockerfile

Every Docker Container needs an image to run from. It contains your application and serves as the model from which your container is created. Let’s start our Dockerfile:

We’ll use the latest Ubuntu image to stay as close to the official documentation as possible. Of course, you can also use other images, like Alpine, but the dependencies might be a little different. Next, we need to install the Minetest dependencies, as listed in Minetest’s README.

Download and compile Minetest

Now we need to download the source code and the default subgame minetest_game. If you need a specific version, be sure to change the URL and the filenames.

Eventually it’s time to compile our server. Let’s tell cmake to build a run in place server:

Great! We should now be able to build a Minetest server! But we’re not done yet!

Persisting worlds, subgames and mods

Every time you start a new container, it’s initial state equals its image. This means that you lose all data gathered during runtime. For a Minetest server, you usually don’t want this, so we need to tell Docker to store the important data somewhere persistent: the host machine. To do this, Docker can create volumes, which map directories from the host to container. Let’s start by collecting the important files and directories that need to persist, relative to our Minetest directory:

  • the world(s): ./worlds
  • the subgames: ./games (we might want to add, remove or update certain subgames without building a new image)
  • the mods: ./mods (same reason as for the subgames)
  • the configuration: ./minetest.conf

Let’s add them to our Dockerfile:

We also need to expose the server’s port - 30000 by default - to the outside world. It’s important to add the /udp suffix to make sure Docker maps a UDP port instead of a TCP port.

Finally, when just need to tell Docker which application should be started, when the container starts up. Surprisingly, that’s our Minetest server. Add an ENTRYPOINT line to the Dockerfile:

Did you notice this last CMD line? CMD can provide a default list of arguments to the ENTRYPOINT. In our case, it’s empty, but it’s useful if you have multiple worlds in your world directory, so you can add the --worldname argument to it when starting your container. I’ll get back to this later.

Building the image

Now that we have a Dockerfile, we can build the corresponding Docker image using the docker build command. Make sure that your Dockerfile is in an empty directory. This reduces the overhead sent to the Docker daemon, since the docker build command sends the whole directory to it. cd into the directory and run the following:

$ docker build -t minetest/server:latest .

This command tells the Docker daemon to build a Docker Image tagged as minetest/server with version latest based on the directory containing the Dockerfile (in this case the current one, indicated using a single dot). After some minutes, Docker should have finished bulding the image successfully. If not, you’ll get an error message explaining exactly where it failed. Check your local images:

$ docker images

The output should contain our minetest/server image. Docker Images Output

Running the server

Running the server is quite simple. The easiest command will create a container using our previously generated image and start the minetestserver as declared in the Dockerfile’s entrypoint. However, it will not mount any host directories, so the world etc. it generates is lost when the container is removed. The -p flag maps a port of the host machine a port of the container, follwoing the syntax HOST_PORT:CONTAINER_PORT. The container port is the one we exposed in out Dockerfile (30000), again with the /udp suffix.

$ docker run -p 30000:30000/udp minetest/server

If you want to mount the volumes we exposed in our Dockerfile, you need to add -v flags to the command. The syntax is similar to the one of the p flag: -v HOST_DIRECTORY:CONTAINER_DIRECTORY. For this example, I’ll mount the mods and the worlds directory:

$ docker run -p 30000:30000/udp -v /home/webD97/minetest/mods:/minetest/mods -v /home/webD97/minetest/worlds:/minetest/worlds minetest/server

Running a minetest server docker container with mounted volumes

Docker will do exactly the same as before, but this time it will take care of mounting the desired directories into the container. If they don’t exist on the host machine, they will be created.As you can see on the screenshot, it created the world’s directory and added all files to it. This way they will be persisted on the host, even if the container is deleted. Whenever you restart it, the directories will be mounted again, but you have to use the -v flags again!

Conclusion

You just learned how to create a Dockerfile for a Minetest server, how to build an image from it and how to run it. The cool thing about using a Docker image, is that the only dependency your host machine has, is Docker itself. All Minetest-related dependencies are inside the container, so your host stays clean.You can do even more with this container. For example, you could start an additional PostgreSQL container and use it for storing your world and player data. I’ll explain such a setup in a future article. Have fun with your Minetest server container!

Christian Danscheid Written by:

Trouble with the trolley, eh?