Host Multiple Minecraft Servers with SRV Records & Docker - barkwoofdog/howtowithdog GitHub Wiki

Intro

A while ago I had what I thought to be a unique problem that I wanted to solve with a unique solution: I have more than one group of friends who likes minecraft, and this time their yearly minecraft revisit happened at the same time.

There is of course an already made solution to this, MC Router made by the big homie itzg (Dude is an actual superstar, I use his Docker Minecraft Server image!) But I didn't really feel like deploying a contair, and I felt as if there MUST be another solution out there.

In comes the unique solution to my problem: Using plain old DNS Records to route the traffic to the appropriate container on my Server.


DNS Records We'll Use Explained

Of course, I am making an assumption that you have your own domain. My recommended provider is Cloudflare. I know, original right? I will just be describing the logic of the solution below. If you want to just do the thing, click here

A Record

One part of the two punch combo here. We have to use an A Record because the SRV record we will be using does not allow C-Names to be referenced in their configuration. In order to do what we need to do, we need an A Record. Normally for Subdomains I would recommend a C-Name record. The greatest difference between an A and a C-Name is:

  • An A record references an IP Address
  • A C-Name references a DOMAIN If you just wanted a subdomain, a C-Name works perfectly (and if your A record is updated you won't need to change your other A records for subdomains!) But, we're making a unique use of the system so we will do it a unique way

SRV Record

The linchpin of the whole operation. What this allows us to do is specify a port that will be used when a specific record (the above described record) is requested. Essentially, this allows us to say: "Oh, you're looking for minecraft2.dognet.fun? That actually uses Port 25575 instead of 25565. Use 25575 instead here" This allows us to make a bit of a SRV -> Docker Container relationship with the records, as the Port is the important part of the whole equation Funnily enough, these are pretty frequently and almost exclusively used for VoIP crap.


The Docker Side of Things

If you are hosting multiple Minecraft servers (and it really doesn't have to be just minecraft, this could be applied to other games as well) then you will need to configure your Docker containers to have DIFFERENT bound Listen Ports.

Example

We have two containers.

  • Minecraft1 listens on 25565
  • Minecraft2 listens on 25575 With this setup, you need only one SRV record, as 25565 is the default port for minecraft.

I use Docker Compose and you should too :] Here is how you would define the bound Listen port on your system (Make sure no other service is utilizing this port!)

version: "3"

services:
  gameserver:
    image: itzg/minecraft-server
    tty: true
    stdin_open: true
    ports:
      - 25575:25565

In the above block, the ports section allows us to bind the physical servers port 25575 as the listen port for this container. It will then convert this to 25565 internally.

Solution

Now that we have the explanation for the solution, let's put all the pieces together to make it happen! At this point, we should have the following:

  • A Domain that we own
  • Access to the DNS Dashboard for our Domain
  • A Server capable of hosting multiple Minecraft Servers
  • Access to any relevant firewalls
  • Privileges to execute docker commands on our Server
  • Either Yourself, or a Friend to help you test

To start off from absolute Square One, we will need to make an A Record for the root of our domain. Essentially, this just means we are making a record that references exclusively the domain you own.

Yeah that's an IP Address and yes, I own it. Getting past that, you will need TWO further A records (assuming we are just hosting two servers. Expand to your needs)

#1 will define the default port minecraft record #2 will define the modified port minecraft record

For consistencies sake, we will utilize pmc and mcs as our Minecraft Subdomains To make the subdomain A record, simply replace the @ in the above image with the string for your subdomains. In my case it would be pmc and mcs Because you have already defined a root, your DNS will recognize that, and prepend your subdomains. For clarities sake, our subdomains are now mcs.dognet.fun pms.dognet.fun

We now move on to the SRV record. These are a bit more involved in their configuration, but are still relatively simple in nature.

Here's a good image with a breakdown for what an SRV record looks like as a string, and the different parts of it

And here is what it looks like inside of Cloudflare

Do note, that between all the DNS providers, this seems to look different. While in the box with the _minecraft._tcp.mcs string i typed _minecraft._tcp.mcs.dognet.fun Cloudflare shortened it to just mcs Mileage may vary, but you get the gist. Make sure your target is the FQDN of your server, so in this example mcs.dognet.fun so that when someone makes a request for that record, DNS will tell them to use the different port

Remember, you only need this for the NON-STANDARD A Record.

At the end of this portion, you should have the following

  • An A Record defining your root
  • An A record defining the subdomain for your default port minecraft server
  • An A record defining the subdomain for your modified port minecraft server
  • An SRV record referencing the port you are using for the modified server, and using its domain name as the target

Moving on to Docker, it's pretty simple. Just deploy two containers. One will be the default port mapping 25565:25565 and one will be the modified port. In our examples in the images, it will be 27000:25565

Now comes the part that you will need to do yourself. Ensure that these ports are open on both your edge firewall and your server's host firewall. You are dealing with iptables, firewalld, or ufw for your Server's host firewall most likely, and I am not sure what you are using at your edge so I can't help you there.

Conclusion

At the end of all this you should have a working setup. In all my tests this was all I needed to get this to work. Just type the domain name in to your server browser and away you go!

In some cases you may need to stream redirect using something like NGINX Proxy Manager or hey screw it, you could just go ahead and use MC Router because it makes this easy.

You might also be finding yourself saying "Hey Dog, you know people can just type the port number at the end of the address right?" to which I respond "Hey smartass I know that." I make money off of running stuff like this for people, and I want the connection to be as simple as possible and look nice for the user. People get nervous or think they're hackers (the more annoying of the two options) when they see an IP Address. I enjoy this solution and I think it's a neat use of DNS, which is already cool.

I hope you enjoyed this, learned something, and implement it if it fits a use case. At the end of the day doing cool stuff with computers is all this is about. Have fun!