RE:NODE

Networking11 min read

SRV records for Minecraft: the fields, and how to test them

How a Java client resolves an SRV record, the exact fields to enter at your registrar, the mistakes that fail silently, and the dig commands that prove it.

Updated

1 reader

An SRV record lets players type play.example.com instead of an address and a port. It is four values and a target, and almost every failed attempt is one of the same handful of mistakes. Here is the whole thing in one line of zone file:

The record, in BIND zone format
_minecraft._tcp.play   300  IN  SRV  0  5  25571  node.example.com.node                   300  IN  A        203.0.113.10

Two records, not one. The SRV record says "the Minecraft service for this name lives on node.example.com port 25571", and the A record says where node.example.com is. Forgetting the second one is the single most common reason an SRV record does nothing, because nothing in the SRV record itself is an address.

What the Java client actually does#

When a player types a hostname with no port, the Minecraft Java client does not go straight to an A lookup. It asks for _minecraft._tcp.<hostname> first. If an SRV record comes back, the client takes the target and the port out of it and connects there. If nothing comes back, it falls back to a plain A or AAAA lookup on the name and assumes port 25565.

step 1nothing returnedport 25571TCP connectJava clientno port typedSRV lookup_minecraft._tcpNo SRV foundport 25565A lookupnode.example.comMinecraft server203.0.113.10:25571
How a Java client resolves play.example.com

Three consequences fall straight out of that, and they explain most of the confusion people have with these records.

Typing a port skips the SRV lookup entirely. A player who enters play.example.com:25565 gets an A lookup and port 25565, whatever your SRV record says. This is a useful diagnostic and a common source of "it works for me": one person has the address saved with a port from before you set it all up.

The same lookup happens for the server list ping. The MOTD, the player count and the green connection bars all go through the SRV record too, so if the entry in the multiplayer list shows the server as unreachable, that is already the SRV path failing and you do not need to click Join to know.

Bedrock ignores all of this. The Bedrock client has a separate port field and does not perform SRV lookups, so Bedrock players type the address and the port. If you run Geyser, hand out the hostname and the Bedrock port as two things.

The fields, exactly#

FieldValue for MinecraftNotes
Service_minecraftLeading underscore, always
Protocol_tcpJava Minecraft is TCP, never UDP
Nameplay, or the apexThe name players will type
TTL300 to 3600Seconds a resolver may cache it
Priority0Lowest number wins
Weight5Tie-break between equal priorities
Port25571The server's actual port
Targetnode.example.comA hostname with an A record. Never an IP

Priority and weight exist for services that genuinely run several endpoints, and nothing in Minecraft depends on them. Any values will do; 0 and 5 are conventional and will not make you think about it again.

The target is the field that catches everyone. It must be a hostname, and that hostname must resolve to an address somewhere in DNS. In a zone file it needs the trailing dot, which means "this is fully qualified, do not append my domain to it". Most web-based DNS editors add the dot for you, and some show it back to you afterwards - node.example.com. in the record list is correct, not a typo.

One extra rule from the specification that occasionally bites: the target is supposed to point directly at an A or AAAA record, not at a CNAME. Most resolvers will follow a CNAME anyway and it usually works, but if everything looks right and the connection still fails, replacing the CNAME with a real A record is the first thing to try.

Where your registrar's form differs#

The record is standard; the forms are not. There are three shapes in the wild, and putting the right string in the wrong shape produces a record for a name nobody will ever look up.

  • Separate fields. Cloudflare and several others give you Service, Protocol and Name as three boxes. Service is _minecraft, Protocol is _tcp, and Name is just play - or @ for the bare domain.
  • One relative name. Many registrars have a single host field and expect _minecraft._tcp.play, with the zone appended automatically. Do not type the domain here.
  • One absolute name. A few want the whole thing: _minecraft._tcp.play.example.com.

Work out which you have by looking at an A record you already created. If your existing record shows www in the host column, the form is relative and your SRV name is _minecraft._tcp.play. If it shows www.example.com, use the full name. Getting this wrong produces _minecraft._tcp.play.example.com.example.com, which is a perfectly valid record for a name that does not exist, and no error anywhere will tell you.

Some providers also insist on a combined "data" or "content" field holding 0 5 25571 node.example.com. - priority, weight, port and target separated by spaces, in that order.

The mistakes that fail silently#

DNS almost never tells you that you made a mistake. It tells you the name does not exist, which looks the same as a server being down. In rough order of how often they happen:

  1. An IP address in the target. Not valid. The client tries to resolve 203.0.113.10 as a hostname, gets nothing, and reports that it cannot reach the server. Put the IP in an A record and point the target at that record's name.
  2. No A record for the target. The SRV record can point at any name at all, including one you invented while filling in the form. Create the A record first, then the SRV record aimed at it.
  3. The zone appended twice. Covered above, and worth checking first because it is invisible in the record list unless you read carefully.
  4. The target A record is behind an HTTP proxy. Cloudflare's orange cloud proxies HTTP and HTTPS. Minecraft is neither, so a proxied record hands clients an address that will never accept a game connection. The record that the SRV target points at must be DNS-only - the grey cloud. Cloudflare for websites and game servers goes through what the orange cloud will and will not carry.
  5. The wrong port. The game port, not the query port, not RCON, not the port you had last month. On a panel, copy it from the server's address rather than from memory.
  6. `_tcp` written as `tcp`, or as `_udp`. Both underscores are part of the name. Java Minecraft is TCP.
  7. Stale cache. You fixed the record ten minutes ago and your resolver is still serving the old answer for the rest of the TTL. Test against a public resolver to see the truth.

Proving it works before you announce it#

Never announce an address you have not resolved yourself. Two commands settle it:

bash
$ dig +short SRV _minecraft._tcp.play.example.com0 5 25571 node.example.com.$ dig +short A node.example.com203.0.113.10

If the first returns nothing, the record is missing, misnamed, or not published yet. If the first works and the second returns nothing, you have the classic missing-A-record case. On Windows without dig installed:

Windows
nslookup -type=SRV _minecraft._tcp.play.example.com 1.1.1.1

Naming the resolver matters. Querying 1.1.1.1 or 8.8.8.8 explicitly bypasses whatever your router and your ISP have cached, which is how you tell "not published" apart from "not propagated". Ask the authoritative servers directly with dig +trace if you want to remove every cache from the picture.

Then check the port is actually open, because a correct record pointing at a closed port looks identical from the client:

bash
$ nc -vz node.example.com 25571Connection to node.example.com 25571 port [tcp/*] succeeded!

PowerShell has Test-NetConnection node.example.com -Port 25571 for the same job. Game server ports explained covers why a game can be listening and still unreachable.

The last test is the real one: add play.example.com in the Minecraft client with no port, and see whether the MOTD and the player count appear in the server list. That exercises exactly the path your players will use.

What an SRV record cannot do#

It does not hide your server's address. The target has a public A record and anyone can dig it in two seconds. An SRV record is a convenience, not a layer of protection. What actually sits between your server and a flood is upstream filtering, and even that only drops obvious volumetric traffic - see what we do about attacks for the honest version of what filtering does and does not catch.

It does not load balance. DNS SRV has priority and weight fields precisely for that, but the Minecraft client does not implement weighted selection in any way you can plan around. Publishing several SRV records and expecting players to be spread across them will produce something, and it will not be what you designed. If you need more than one backend, put a proxy in front.

It does not help anyone who types a port. Nor does it apply to RCON, the query port, a web map, or any other service on the box. Those are separate names and separate ports, and the query port in particular has its own record type that Minecraft does not use.

It does nothing for Bedrock clients. They do not ask.

SRV, proxies and forced hosts#

If you run a proxy such as Velocity in front of several backends, you probably do not need an SRV record at all. The proxy listens on 25565 and a plain A record on play.example.com is enough, which is one fewer thing to get wrong. Ports become an internal matter, and only the proxy's port is ever public.

The interesting part is routing by name. A proxy can map a hostname to a specific backend - creative.example.com lands people directly in the creative server, play.example.com in the lobby - using the hostname the client sent in its handshake. That is a nice way to hand different communities different front doors without running more than one public port. Test it rather than assume it: whether the handshake carries the name the player typed or the SRV target varies between clients and proxy versions, and forced hosts only work if it is the former. What a reverse proxy does has the general shape of the idea.

For a single server on the default port, the simplest thing that works is an A record and no SRV at all. Connecting a domain to a game server is that version of the job, and subdomains for servers covers giving each of your servers its own name. SRV earns its place exactly when the port is not 25565 and you do not want players to have to know that.

TTL and moving the server#

TTL is how long a resolver is allowed to keep the answer. A record with 3600 can be stale for an hour after you change it, which is fine until the day you are migrating.

The routine for a move is dull and reliable:

  1. A day ahead, drop the TTL on both the SRV record and its target A record to 300.
  2. Wait out the old TTL, so that every cache in the world has picked up the short one.
  3. Make the move, change the A record, and watch.
  4. Leave the old server running and reachable for an hour or two. Players who are mid-session do not re-resolve anything, and clients with a stale cache will still arrive there.
  5. Put the TTL back up once you are settled.

Because the address lives in one A record, changing where the server lives is a one-line edit and the SRV record never needs touching again. That is the second reason to point the SRV target at a name rather than an address - the first being that an IP in the target is invalid. Moving a server without losing players covers the rest of the migration, and DNS records explained is the background if any of the record types here were unfamiliar.

FAQ#

Do I need an SRV record if my server uses port 25565?

No. Clients assume 25565 when there is no SRV record, so a plain A record on the name is enough and is simpler to debug. SRV exists for servers on any other port.

Why does the address work for me but not for my friends?

Usually because you saved it with the port attached, which skips the SRV lookup entirely, or because your resolver has a different answer cached than theirs does. Remove the port from your saved entry and test again, then check the record against 1.1.1.1 rather than your own DNS.

Can I point the SRV target straight at an IP address?

No. The target field must be a hostname. Create an A record for something like node.example.com that holds the IP, then point the SRV target at that name. It also makes future moves a single edit.

How long does an SRV record take to work?

Publication at your DNS provider is usually seconds. After that, anyone who already looked up that name may hold the old answer for the length of the previous TTL. If the name is brand new there is nothing cached, so it generally works immediately.

Does an SRV record hide my server's IP address?

Not at all. The target resolves to a public A record that anyone can query. If concealing the address matters, that is a job for a proxy in front of the server, not for DNS.

Can I use one domain for several Minecraft servers?

Yes. Give each one its own name - smp.example.com, creative.example.com - with its own SRV record pointing at the right port on the same host. All of them can share a single A record for the machine.


Comments

Completely anonymous: no account, no email, no cookie. We store the name you type, the text and the time - nothing else. Links are limited and markup is not rendered.

0/2000