Custom Domains and SRV Records for Game Servers
How A, AAAA, CNAME and SRV records work for game servers, the exact SRV record format, TTL timing before a migration, and why proxying game traffic through a CDN breaks it.
By SweetMask · · updated · 15 min read
A domain is portability, not decoration. An A record maps a name to an IPv4 address, a CNAME aliases one name to another, and an SRV record is the only type that carries a port. Minecraft Java reads SRV records; Source engine games and FiveM do not, so those players still type the port.
Every server that tells players to type 203.0.113.44:25565 is one host move away from losing its regulars. The address goes into a Discord pin, a YouTube description, a forum signature and a few hundred favorites lists, and when the machine changes the address is wrong in all of them at once. A name you control is the fix, and it costs about ten dollars a year. Roughly a third of the entries on the Minecraft server list already publish a domain rather than a raw address.
The honest limit is worth stating first: for most games the domain buys you portability, not a shorter connect string.
Why a domain beats an IP address
Start with the failure case, because it is the whole argument. You are renting a box in Falkenstein, the host raises the price or the node starts throwing packet loss at 20:00 CEST, and you move to a different provider. The new machine has a different address. Every player who saved the old one now gets a connection timeout, and they do not file a support ticket about it. They open the launcher, see the server greyed out, and play something else. A week later the old address is reassigned to another customer, so the few who keep retrying reach a stranger.
With a domain the same move is a single record edit. Players who typed play.example.net reconnect on the next launcher refresh and never learn that anything happened. That is the entire value proposition, and it is why the domain question is really a migration question. Everything else in the guide to migrating a game server between hosts gets easier once the address your players use is a name you own rather than a number your host owns.
There are three smaller benefits worth having as well. A domain lets you run several entry points that move independently: play, eu, na and creative can sit on four different machines and each can be repointed without touching the others. It lets you keep a name during a rebuild, so you can stand the new box up, test it on node4.example.net, and only flip the player-facing name when it passes. And it reads as a real project rather than a hobby box, which matters when someone is scanning a page of entries on the full server list and deciding which three to try.
Cost is not a real objection. A .net or .com runs 10 to 15 US dollars a year at a registrar that does not play renewal games. A .gg is the vanity option at 60 to 100 dollars a year, which is defensible for a large community and pointless for a 20-slot server. Use the cheap TLD and spend the difference on RAM.
The DNS record types a server owner actually uses
DNS is a lookup table with types. You publish records in a zone, resolvers cache the answers, and clients ask for the type they need. Out of the dozens of record types defined, running a game server needs five or six, and the distinctions between them are the part people get wrong.
Why you cannot CNAME the bare domain
A CNAME says this name is an alias for that name, and the rule is that a name holding a CNAME may hold nothing else. The apex of your zone, example.net with no subdomain, must hold SOA and NS records because that is what makes it a zone at all. So a CNAME at the apex is illegal, and a strict provider will refuse to save it. Providers that appear to allow it are running ALIAS or CNAME flattening: they resolve the target themselves, cache the result, and answer with a plain A record. That works, but it hides the target behind their resolver, and their cache refresh interval becomes part of your failover time.
Do not fight it. Put players on a subdomain. play.example.net removes the whole class of problem and leaves the apex free to serve a website. Across the 147 games in the JoinGG game catalogue, the tidiest connect strings are almost all short subdomains rather than flattened apexes.
How an SRV record hides a non-default port
SRV is the only common record type whose payload includes a port number, which is why it is the only way to make a bare name imply a non-default port. It was defined in RFC 2782 for exactly this: let a client discover where a named service lives without hard-coding a port.
The record name has a fixed shape. It is an underscore-prefixed service label, then an underscore-prefixed protocol label, then the name players will type:
_minecraft._tcp.play.example.net
The value has four fields in order: priority, weight, port, target.
0 5 25577 node2.example.net.
Read together, that says: for the Minecraft service over TCP at play.example.net, connect to the host node2.example.net on port 25577. You also need an A record for the target, because the target is a hostname and something has to resolve it: node2.example.net to 203.0.113.44. A player types play.example.net into the launcher, the client asks for the SRV record first, gets the answer above, resolves the target, and opens a socket to 203.0.113.44:25577. The port never appears on screen.
Priority and weight, and why they will not load balance you
Priority works like mail exchange preference: lower wins, and higher values are only used when the lower ones fail. Weight distributes traffic proportionally between targets sharing a priority. Do not build a load balancer out of this. Game clients implement the lookup to find one address, and the retry behavior when the first target refuses a connection is inconsistent across launchers and mod loaders. If you need to spread load, put Velocity or BungeeCord in front and let it route. Set priority 0 and weight 5 and stop thinking about the fields.
Which games actually read SRV
Minecraft Java Edition has read _minecraft._tcp since 1.3.1 and is the main reason anyone learns this. TeamSpeak uses _ts3._udp and Mumble uses _mumble._tcp. Minecraft Bedrock nominally uses _minecraft._udp, but support has been inconsistent across client versions and platforms, so treat it as a bonus rather than a plan. Nothing else in common use on the Minecraft player-count statistics or the other tracked games performs an SRV lookup. If you are standing up a first server and following the guide to running a Minecraft server for free, the simplest move is to keep port 25565 and skip SRV entirely; you only need it once something else on the box has already taken the default.
The two SRV mistakes that break it every time
Both of these look correct in a control panel and fail at connect time, which is what makes them expensive.
Mistake one: the target is an IP address
The SRV target field takes a hostname, not an address. Writing 0 5 25577 203.0.113.44 produces a record that saves cleanly and never works: the client treats the target as a name and gets NXDOMAIN. Some providers now reject a numeric target; plenty still accept it. The fix is two records instead of one. Create node2.example.net as an A record pointing at 203.0.113.44, then point the SRV target at that name. Mind the trailing dot as well, because some registrars treat the target as relative to the zone and will silently turn node2.example.net into node2.example.net.example.net. Enter it as a fully qualified name with a trailing dot or as the bare label node2, whichever the provider expects, then verify rather than assume.
Mistake two: a stale or conflicting A record on the same name
An A record on play.example.net is not a conflict in the DNS sense, and a correct one is a useful fallback for clients that skip the SRV lookup. The problem is when it points somewhere wrong. Half your players read the SRV record and land on port 25577 on the new machine; the other half read the leftover A record from the last host and land on port 25565 on a dead address or, worse, on an old instance that is still running with a two-week-old world. You get bug reports that contradict each other, and the difference is which code path the launcher took.
Fix it by keeping the A record on the player-facing name in sync with the SRV target at all times, or deleting it and letting the SRV record be the only answer. Then verify from outside your network:
dig SRV _minecraft._tcp.play.example.net +shortshould return exactly0 5 25577 node2.example.net.
dig A node2.example.net +shortshould return the current address of the machine.
- On Windows,
nslookup -type=SRV _minecraft._tcp.play.example.net 1.1.1.1does the same job and forces a public resolver.
- Query a second resolver, for example
@8.8.8.8, before you announce anything. One resolver agreeing with you proves nothing.
What the domain buys you when the game ignores SRV
Here is the honest part. For most games there is no way to hide the port, and any guide that implies otherwise is wrong. What you get instead is a stable name, which is still the thing worth having.
Source engine games
CS 1.6, CS:S, CS2, Team Fortress 2, Garry's Mod, Day of Defeat and Left 4 Dead 2 all accept a hostname in the console: connect play.example.net:27015 resolves the name and connects. There is no SRV lookup anywhere in the client. The useful consequence is that if you run on the default port, the port becomes optional, because the client assumes 27015 when you leave it off. So connect play.example.net works, and the bare name is enough. That only breaks when you stack several instances on one machine at 27015, 27016 and 27017. If you are running the kind of multi-instance setup common on the Counter-Strike server list, ask your host for a second IPv4 address instead. They usually cost one to three dollars a month, and each address gives you another default port and therefore another clean bare name.
FiveM, Terraria and the rest
FiveM accepts connect play.example.net from the F8 console and assumes 30120, so the same default-port trick applies. The difference is that most players arrive through a cfx.re join link or the in-client browser rather than by typing anything, which is visible in how the entries on the FiveM server list are addressed. Terraria is stricter: the vanilla client asks for address and port as separate fields and has no SRV support, so servers on the Terraria hub that moved off 7777 must publish both halves. Rust on UDP 28015 and 7 Days to Die on 26900 behave the same way. Publish the domain, publish the port next to it, and accept that the win is the migration you will do in eighteen months, not the four characters you did not have to type.
TTL, propagation, and moving hosts without dropping players
Every DNS record carries a time to live in seconds, which tells resolvers how long they may cache the answer. This single number decides how long a migration hurts, and the thing people miss is that the TTL which governs a change is the TTL that was already published, not the one you publish with the change. Lowering the TTL at the same moment you change the address does nothing for anyone whose resolver already cached the old value.
The timing that actually works
- Two days before the move, look up the current TTL:
dig play.example.net +noall +answerprints it in the second column. Common defaults are 3600 or 14400 seconds.
- Set the TTL on every record you plan to change to 300 seconds, and change nothing else.
- Wait one full old-TTL period. If it was 14400, that is four hours; if it was 86400, wait a day. Now every cache that mattered holds a 300-second copy.
- Do the migration. Change the A record on the machine name and, if you use one, the SRV target. Within about five minutes, resolvers refresh.
- Leave the old machine running and listening for seven days with a message of the day saying the server has moved. A 512 MB box for a week costs a few dollars and catches the stragglers.
- After 24 hours of stable play, put the TTL back to 3600. A permanent 300-second TTL means more queries and slightly slower first connects for no benefit.
Expect a tail. Public resolvers such as 1.1.1.1 and 8.8.8.8 honor TTLs closely, but some ISP resolvers clamp values to a floor of 15 or 30 minutes, and a few consumer routers cache far longer than they should. One or two percent of players lagging by a day is normal. Negative answers cache too: an NXDOMAIN is held for the interval in your zone SOA minimum field, often an hour, so create names before you advertise them. If the move is also a change of country, read the guide to choosing a hosting region first, because a 40 ms latency change will cost you more regulars than the DNS ever will. The hourly sweeps behind the JoinGG statistics pages pick a moved server back up on the next poll once the record resolves.
Why proxying game traffic through a CDN breaks it
Cloudflare and its equivalents proxy HTTP and HTTPS on a fixed list of ports: 80, 443, 8080, 8443 and a handful of others. Nothing on that list is a game port. Turn the orange cloud on for play.example.net and the name stops resolving to your server; it resolves to an anycast edge address that has no listener on 25565, 27015 or 30120. The client opens a socket to nothing and times out. In Minecraft that surfaces as a connection refused error from Netty, which sends people hunting for a firewall problem that does not exist.
The second reason is protocol. A general CDN carries TCP for web traffic. Most game traffic is UDP: Source games run game traffic and A2S queries on UDP 27015, FiveM uses UDP 30120, Rust uses UDP 28015. A HTTP reverse proxy has no concept of any of it. Even where the game is pure TCP, like Minecraft Java, an HTTP proxy will not forward a non-HTTP handshake.
What does work in front of a game server
- Purpose-built TCP proxies. TCPShield for Minecraft Java works because Java Edition is pure TCP and the proxy speaks the protocol, forwarding the real player IP through the handshake so your bans still function.
- Cloudflare Spectrum, which is a genuine layer 4 proxy rather than the HTTP one, priced per gigabyte, with UDP on the higher plans only.
- Network-level scrubbing from the host, such as the game-profile filtering OVH applies at the edge. This is the option most small servers should take, because it costs nothing extra and needs no DNS trickery.
The working rule is simple: orange cloud on for your website and your Pterodactyl panel, DNS-only for anything a game client connects to. That does publish your origin address, which is the tradeoff, and it is worth reading the guide to stopping DDoS attacks on a small server before deciding how much that matters at your size. For most servers under 100 slots, host-level filtering plus a firewall that drops everything except the game port and your admin address is enough.
Setting the domain up end to end
The full sequence, assuming a fresh domain and one machine. It takes about twenty minutes, most of which is waiting.
- Register the domain and point its nameservers at whichever DNS provider you actually want to manage records in. Do not split management between the registrar and a second provider; you will edit the wrong zone within a month.
- Create an A record for the machine:
node1to the server address, TTL 3600. Add an AAAA record only if the game supports IPv6 and you have tested it.
- Create the player-facing name as a CNAME:
playtonode1.example.net. This is the layer that makes moves cheap.
- If the game is Minecraft Java and the port is not 25565, add the SRV record with the target set to
node1.example.net, not to the address and not toplay.
- Wait five minutes, then verify with
digagainst two public resolvers. Do not verify from the server itself; a local hosts file entry or split-horizon resolver will lie to you.
- Join from a phone hotspot or a friend's connection. A LAN test proves nothing about the DNS path.
- Update the connect string on your listing, then your Discord pins, your MOTD and anywhere the old address is written down.
Naming conventions that survive the second server
Name machines after machines and services after services. node1, node2 and db1 are machines; play, eu, creative and panel are services. Players only ever see service names, so a machine can be replaced under any service without a single player-visible change. The instinct to hand out node1.example.net because it is one record fewer is exactly the shortcut that puts you back where you started.
Once the name resolves, put it on your listing rather than the address. A working domain, a current player count and an accurate description are what make an entry trustworthy, which is covered in what makes a server listing trustworthy. Pair it with an uptime check aimed at the name rather than the address, so a broken DNS record pages you the same way a crashed process does; the guide to game server monitoring and uptime covers what to alert on.
Frequently asked questions
Can an SRV record hide the port for CS2, FiveM or Rust?
No. An SRV record only helps if the client looks one up, and Source engine games, FiveM, Rust and Terraria do not. They resolve the hostname to an address and then use the port you typed, or the game default. Publish the SRV record anyway if you like; those clients will ignore it.
Why does my SRV record work for some players and not others?
Almost always caching. A resolver that fetched the old answer holds it for the full TTL, so a 14400 second TTL means four hours of stale results. The other common cause is a launcher or mod that skips the SRV lookup and resolves the A record straight to the default port instead.
Should the player-facing name be a CNAME or an A record?
Use a CNAME pointing at a machine name such as node2.example.com. When you change hosts you edit one A record and every service name follows. Use an A record only at the zone apex, where a CNAME is not legal, and use your provider ALIAS or ANAME feature there instead if it offers one.
How long does a DNS change actually take to reach players?
As long as the TTL you published before the change, not the TTL you publish with it. Drop the record to 300 seconds at least one old TTL period ahead, and most resolvers pick up the new value within five minutes. Expect a small tail of one or two percent for a day.
Do I need a domain to get my server listed?
No. A raw address and port is a valid connect string and gets queried the same way. A domain simply means the listing survives a host move without an edit, and players who saved the name in their favorites keep working. It costs about ten dollars a year to remove that failure mode.
Does using a domain hide my server IP address?
No. A normal A record publishes the address to anyone who runs a lookup, and the query protocol hands it out as well. Hiding the origin needs a real TCP or UDP proxy in front of the server. DNS alone changes the label on the door, not the address behind it.
Set the records once, verify them from outside your own network, and the next host change becomes a five-minute edit instead of a lost month of regulars. When the name resolves and the port answers, add the server to JoinGG using the domain rather than the address, so the listing keeps working the day the machine underneath it changes.
Sources
srv recordgame server domaindns for game serversminecraft srv recordcustom domaina record
More
The person who maintains the modpack
A modded server's stability is mostly one person's judgement about versions and timing, and when that person stops, the pack does not break so much as freeze.
SweetMask · · 4 min
Whatever happened to rented official servers
Publishers kept the server software, licensed the renting, took the renting in-house and finally folded hosting into the game, and each step left communities less of the machine.
SweetMask · · 5 min
What the NeoForge split changed for modded servers
The fork looked like a rename in 2023. By Minecraft 1.21.1 it decided which mods and hybrid servers a modded server could run, while installation and Forge itself carried on.
SweetMask · · 4 min