(It's been a while since I did this stuff. Please don't blindly assume that all the details below are correct. But I hope I'm not too embarrassingly wrong. :))
As the previous answer stated, the Minecraft client (as of 1.3.1) supports SRV record lookup using the service name _minecraft
and the protocol name _tcp
, which means that if your zone file looks like this...
arboristal.com. 86400 IN A <your IP address>
_minecraft._tcp.arboristal.com. 86400 IN SRV 10 20 25565 arboristal.com.
_minecraft._tcp.arboristal.com. 86400 IN SRV 10 40 25566 arboristal.com.
_minecraft._tcp.arboristal.com. 86400 IN SRV 10 40 25567 arboristal.com.
...then Minecraft clients who perform SRV record lookup as hinted in the changelog will use ports 25566 and 25567 with preference (40% of the time each) over port 25565 (20% of the time). We can assume that Minecraft clients who do not find and respect these SRV records will use port 25565 as usual.
However, I would argue that it would actually be more "clean and professional" to do it using a load balancer such as Nginx. (I pick Nginx just because I've used it before. I'm not claiming it's uniquely suited to this task. It might even be a bad choice for some reason.) Then you don't have to mess with your DNS, and you can use the same approach to load-balance any service, not just ones like Minecraft which happen to have done the hard client-side work to look up and respect SRV records. To do it the Nginx way, you'd run Nginx on the arboristal.com
machine with something like the following in /etc/nginx/sites-enabled/arboristal.com
:
upstream minecraft_servers {
ip_hash;
server 127.0.0.1:25566 weight=1;
server 127.0.0.1:25567 weight=1;
server 127.0.0.1:25568 weight=1;
}
server {
listen 25565;
proxy_pass minecraft_servers;
}
Here we are controlling the load-balancing ourselves on the server side (via Nginx), so we no longer need to worry that badly behaved clients might prefer port 25565 to the other two ports. In fact, now all clients will talk to arboristal.com:25565
! But the listener on that port is no longer a Minecraft server; it's Nginx, secretly proxying all the traffic onto three other ports on the same machine.
We load-balance based on a hash of the client's IP address (ip_hash
), so that if a client disconnects and then reconnects later, there's a good chance that it'll get reconnected to the same Minecraft server it had before. (I don't know how much this matters to Minecraft, or how SRV-enabled clients are programmed to deal with this aspect.)
Notice that we used to run a Minecraft server on port 25565; I've moved it to port 25568 so that we can use port 25565 for the load-balancer.
A possible disadvantage of the Nginx method is that it makes Nginx a bottleneck in your system. If Nginx goes down, then all three servers become unreachable. If some part of your system can't keep up with the volume of traffic on that single port, 25565, all three servers become flaky. And not to mention, Nginx is a big new dependency in your ecosystem. Maybe you don't want to introduce yet another massive piece of software with a complicated config language and a huge attack surface. I can respect that.
A possible advantage of the Nginx method is... that it makes Nginx a bottleneck in your system! You can apply global policies via Nginx, such as rejecting packets above a certain size, or responding with a static web page to HTTP connections on port 80. You can also firewall off ports 25566, 25567, and 25568 from the Internet, since now they should be talked to only by Nginx over the loopback interface. This reduces your attack surface somewhat.
Nginx also makes it easier to add new Minecraft servers to your backend; now you can just add a server
line to your config and service nginx reload
. Using the old port-based approach, you'd have to add a new SRV record with your DNS provider (and it could take up to 86400
seconds for clients to notice the change) and then also remember to edit your firewall (e.g. /etc/iptables.rules
) to permit external traffic over that new port.
Nginx also frees you from having to think about DNS TTLs when making ops changes. Suppose you decide to split up your three Minecraft servers onto three different physical machines with different IP addresses. Using Nginx, you can do that completely via config changes to your server
lines, and you can keep those new machines inside your firewall (connected only to Nginx over a private interface), and the changes will take effect immediately, by definition. Whereas, using SRV records, you'll have to rewrite your zone file to something like this...
arboristal.com. 86400 IN CNAME mc1.arboristal.com.
mc1.arboristal.com. 86400 IN A <a new machine's IP address>
mc2.arboristal.com. 86400 IN A <a new machine's IP address>
mc3.arboristal.com. 86400 IN A <a new machine's IP address>
_minecraft._tcp.arboristal.com. 86400 IN SRV 10 20 25565 mc1.arboristal.com.
_minecraft._tcp.arboristal.com. 86400 IN SRV 10 40 25565 mc2.arboristal.com.
_minecraft._tcp.arboristal.com. 86400 IN SRV 10 40 25565 mc3.arboristal.com.
...and you'll have to leave all three new machines poking outside your firewall so that they can receive connections from the Internet. And you'll have to wait up to 86400
seconds for your clients to notice the change, which could affect the complexity of your rollout plan. And if you were running any other services (such as an HTTP server) on arboristal.com
, now you have to move them to the mc1.arboristal.com
machine because of how I did that CNAME. I did that only for the benefit of those hypothetical Minecraft clients who don't respect SRV records and will still be trying to connect to arboristal.com:25565
.
So, I think both ways (SRV records and Nginx load-balancing) are reasonable, and your choice will depend on your personal preferences. I caricature the options as:
- SRV records: "I just need it to work. I don't want complexity. And I know and trust my DNS provider."
- Nginx: "I foresee
arboristal.com
taking over the world, or at least moving to a bigger machine someday. I'm not scared of learning a new tool. What's a zone file?"