Thomas Pain :: blog

Running a Minecraft Server

2023-03-23 (updated 2023-03-28) :: 676 words

I'm on a student society's committee at university. During the Easter break that's right around the corner, we (committee) decided that we wanted to run a limited-duration Minecraft server, and I took on the role of setting that all up.

That also meant I was going to find some possible way to over-engineer something about it.

Where to host?

Whereas most people would default to a game-server hosting company for ease of use, I gravitated towards Hetzner to rent a VPS to function as my Minecraft server.

It was kinda the obvious choice - it's good value for our limited budget, I'm already familiar with the company and I'm totally able to handle the sysadmin stuff.1

The VPS option that I went with was the CPX21 option - 3vCPU, 4GB RAM and 80GB storage, all for 8.64 EUR a month, plus IPv4 rental.2 I get the feeling it might be overkill for a relatively small-scale Minecraft server - I only expect 10 concurrent players, maximum - but since we're only running it for a month it doesn't matter too too much.

plz how 2 minceraft

To run the actual Minecraft server, I'm using the itzg/docker-minecraft-server Docker image to do it all for me. It was very simple - would recommend if you're ever wanting to run one yourself.

I made some small modifications to the file, mostly just to enable a whitelist as we want our server to be members-only. I also added a datapack from VanillaTweaks for single-player sleep, though I can't seem to get the automatic installation that working quite right, so I just add it manually when a new world is generated.

Automatically Adding People to the Whitelist

I don't really want to have to manually go and add people to the whitelist whenever someone new wants to join the server, and I definitely don't want to keep people waiting if I'm asleep or otherwise busy. To avoid these pitfalls of being a human being, I built a Discord bot to whitelist people for me! :D

It's written with Go, and makes use of bwmarrin/discordgo and the Docker Engine SDK (more on that later).

The bot works by exposing a single slash command that allows users to input their Minecraft username. This kicks off a train of events that validates their username3, makes a record of their username and Discord user ID (for moderation purposes) and adds them to the whitelist.

Actually adding someone to the whitelist is done with the Docker Engine API - since we're running our Minecraft server in a Docker container, the best way to run a command inside of the container to add somebody to the whitelist - in fact, the command is mc-send-to-console whitelist add <username>.

I chose to use the API because a) I know it exists and b) I want to Dockerise the bot.4 It's actually surprisingly simple, though it did take more steps than anticipated:

 1client, err := docker.NewClientWithOpts(docker.WithHost(Config.DockerSocket)) // Config.DockerSocket can be replaced with "unix:///var/run/docker.sock" on most Linux systems if you're running your app on bare-metal.
 2if err != nil {
 3    return err
 5defer client.Close()
 7ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
 8defer cancel()
10id, err := client.ContainerExecCreate(ctx, Config.ContainerName, types.ExecConfig{
11    Cmd: cmd, // cmd is a []string
13if err != nil {
14    return err
17if err := client.ContainerExecStart(ctx, id.ID, types.ExecStartCheck{Detach: true}); err != nil {
18    return err

All-in-all, the end bot looks like this from the perspective of a regular user:

Running the slash command


Final result

You can find the source code for the bot here.

Update: 2023-03-28

Now there's a backup script too! It's run with a Cron job every day, and manages gracefully stopping the server (with an in-game warning), creating and uploading archives and restarting the server. The script, called, is in the source repository.

  1. I mean - this website is also run on a very similar VPS from Hetzner using a very similar setup.
  2. Update 2023-03-28: This ended up falling flat on its face as soon as we launched because of the demand on it, so we upgraded to a CPX31 system with 4vCPUs, 8GB RAM and 80GB of storage, for 15.72 EUR a month. That's been running very nicely since.
  3. ^[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_]{3,16}$ :)
  4. This means I'll be passing /var/run/docker.sock into the bot container so it can control the host's Docker daemon. If I didn't want to Dockerise the bot, I'd probably stick to running docker exec mc ... instead.