RE:NODE

Networking13 min read

Subdomains for servers: a name per game server and app

Why every server should have its own name, how to create the record, what a subdomain cannot carry, and the TTL routine that makes a migration boring.

Updated

0 readers

A subdomain is one record in a zone you already own. It costs nothing, it takes five minutes, and what it buys is the ability to change the address underneath without telling anybody. That is the entire argument, and it comes due the first time you move a server, which is always sooner than you planned.

Handing out 203.0.113.10:25571 works right up to the moment it changes. Then it lives in forty Discord pins, three server-list entries, a wiki page nobody can edit any more and the muscle memory of every player you have. Handing out play.example.com means the change is one line in a form. The technique below goes slightly further than one name: two layers of names, so that moving a service and moving a machine are two different one-line edits.

What a subdomain actually is#

A domain name is a list of labels separated by dots, read right to left. com is a zone, example.com is a name inside it that your registrar delegated to you, and play.example.com is a name inside the zone you now control. Creating it is not a purchase and not a registration. It is a record in your zone file, and every DNS provider gives you a form for it.

The rules worth knowing are short:

  • Each label is at most 63 characters, the whole name at most 253. You will never hit either.
  • Labels may contain letters, digits and hyphens, but not a leading or trailing hyphen.
  • Names are case-insensitive. Play.Example.com and play.example.com are the same name.
  • Underscores are not legal in a hostname but are used deliberately by service records such as _minecraft._tcp.play.example.com. That is why they look strange: they are not hostnames.
  • Depth is free. eu.play.example.com is no more expensive or slower than play.example.com.

The one distinction that trips people is between adding a record and delegating a zone. If you add an A record for play, your DNS provider answers for it. If you add NS records for play, you have handed the whole of play.example.com and everything under it to somebody else's nameservers, and your own records for those names stop being used. Delegation is for handing a subtree to another team or another provider. For putting a server behind a name, you want a record. Nameservers versus DNS records has the longer version of that distinction, and it is worth reading before you move a domain between providers.

A naming scheme that survives three servers#

The mistake is to point every name straight at an address. It works, and then you move the machine and edit nine records, and you miss one.

Use two layers. Machine names hold addresses, service names point at machine names.

The two layers, in BIND zone format
; layer 1 - one name per machine, the only place an address appearsde01        300  IN  A      203.0.113.10de02        300  IN  A      203.0.113.11; layer 2 - one name per service, pointing at a machineplay        300  IN  CNAME  de01.example.com.creative    300  IN  CNAME  de01.example.com.api         300  IN  CNAME  de02.example.com.

Now there are two kinds of move and each is one edit. The machine gets a new address: change the A record on de01, and every service on it follows. A single service moves to a different box: change its CNAME, and nothing else in the zone notices. Compare that with nine A records, of which you will update seven.

The names themselves are worth ten seconds of thought, because players type them and say them out loud:

NameRecordPoints atWho uses it
play.example.comCNAMEde01.example.comPlayers, in the game client
mc.example.comCNAMEde01.example.comA second, shorter alias for the same thing
api.example.comCNAMEde02.example.comYour app, over HTTPS
de01.example.comA203.0.113.10Nothing directly. It is the address
_minecraft._tcp.playSRVde01.example.com port 25571The Java client, automatically

Name the service, not the software. play survives the day you move from Paper to something else; paper.example.com does not. Avoid version numbers and avoid new-, because new-play.example.com is still called that in two years. Keep it short and unambiguous when spoken: people will read it to each other over voice chat, and mc beats minecraft-survival-01 every time.

One name you should not skip: give yourself a boring administrative name such as de01 even if only one server exists. The moment there are two, you will be glad the address lives in exactly one record.

Creating the record at your DNS provider#

Wherever your domain's nameservers point is where the record goes, and that is often not your registrar and almost never your hosting provider. RE:NODE does not sell domains and does not run DNS for you, so this step happens at Cloudflare, Namecheap, Porkbun, your registrar's own panel or wherever your zone actually lives.

  1. Confirm which provider is authoritative. dig +short NS example.com tells you, and it is the only answer that matters. Editing records in a panel that is not authoritative is a popular way to spend an afternoon.
  2. Choose the record type. A for an IPv4 address, AAAA for IPv6, CNAME for another name. Never both A and CNAME on the same name.
  3. Fill in the name field in the shape that form expects. This is the part that goes wrong.
  4. Set a TTL. 300 while you are working, 3600 once it is settled.
  5. Save, then resolve it yourself before you tell anybody it exists.

There are three shapes of name field in the wild. Some forms want the label only (play), some want the fully qualified name (play.example.com), and a few accept either. Work out which you have by looking at a record you already created: if the existing www record shows www in the host column, the form is relative and you type play. If it shows www.example.com, type the whole thing. Typing the full name into a relative form produces play.example.com.example.com, which is a perfectly valid record for a name nobody will ever look up, and no error anywhere will tell you. @ or an empty field means the bare domain.

What a subdomain cannot carry#

A name maps to an address. That is all it does, and nearly every disappointment with subdomains comes from expecting more.

It carries no port. play.example.com resolves to 203.0.113.10 and the client still has to know it needs port 25571. There are exactly three ways around that, and picking one is the whole of connecting a domain to a game server: publish an SRV record for a game whose client reads one, run the service on the port its client assumes by default, or put a proxy in front that listens on the expected port and forwards internally.

It carries no protocol and no path. DNS has no idea what HTTPS is. Redirecting old.example.com to https://example.com/new is a web server's job, not a record's - see www versus apex domains and redirects.

A `CNAME` cannot share a name with anything else. This is in the original specification and providers enforce it unevenly. If play.example.com is a CNAME, it cannot also hold a TXT record for a domain verification, and adding one will either be refused or will quietly break the CNAME. It is also why a CNAME at the apex is illegal: the apex already holds NS and SOA records. Providers that appear to allow it are doing ALIAS, ANAME or CNAME flattening, which is a synthetic A record generated on their side. That is fine, and it is not a CNAME.

It hides nothing. Anyone can resolve the name in two seconds and read the address. A subdomain is a convenience layer, not a security layer. What sits between your server and a flood is upstream filtering, and even that only drops obvious volumetric traffic - what we do about attacks is the honest account.

Wildcards, and when to avoid them#

*.example.com answers for any name below the domain that has no more specific record of its own. It is genuinely useful for a multi-tenant app where every customer gets customer.example.com, and it is a bad idea for a handful of servers.

A wildcard and an exception
*           300  IN  A      203.0.113.20play        300  IN  CNAME  de01.example.com.

Here anything.example.com lands on 203.0.113.20, play.example.com still goes to de01 because a specific record always wins, and example.com itself is not matched at all - a wildcard never answers for the apex.

The reasons to avoid it on a small estate are practical. Typos resolve, so paly.example.com silently works and nobody reports the broken link. Monitoring that checks whether a name resolves becomes useless, because everything resolves. And you lose the inventory: the record list stops being the list of what you run.

A wildcard also changes how certificates work. A certificate for *.example.com can only be issued after proving control of the zone with a DNS-01 challenge, which means an API token for your DNS provider sitting on a server. Per-name certificates use the much simpler HTTP-01 challenge. HTTPS and Let's Encrypt explained covers both validation methods.

TTL, and the migration routine that is boring#

TTL is how many seconds a resolver is allowed to keep an answer before asking again. It is the only knob that decides how long a change takes to reach everybody, and the decision has to be made before the change, not during it.

There is a second cache that catches people out. When a name does not exist, the negative answer is cached too, and its lifetime comes from the zone's SOA minimum field rather than from any record. Test play.example.com before you create it and your resolver may keep saying it does not exist for an hour afterwards, while the record is sitting there working perfectly for everyone else. Do not test a name you have not created yet.

The routine for moving a server is dull on purpose:

  1. A day ahead, drop the TTL on the service name and its target to 300.
  2. Wait out the old TTL in full, so that every cache in the world has picked up the short one.
  3. Move the service. Change the one record that points at it.
  4. Leave the old server running and reachable for a few hours. Sessions already in progress do not re-resolve anything, and stale caches will still arrive there.
  5. Watch the old server's connection log. When it goes quiet, the move is finished.
  6. Put the TTL back to 3600.

Moving a server without losing players covers the rest of a migration, including the part where you copy the world before the DNS, not after.

Checking it before you hand it out#

Never publish an address you have not resolved yourself, from outside your own network.

bash
$ dig +short CNAME play.example.comde01.example.com.$ dig +short A play.example.com @1.1.1.1203.0.113.10$ dig +short A de01.example.com @8.8.8.8203.0.113.10

Naming the resolver explicitly is the important part. Querying 1.1.1.1 or 8.8.8.8 bypasses whatever your router and your ISP have cached, which is how you tell "not published yet" apart from "not propagated yet". If you want to remove every cache from the picture, dig +trace play.example.com walks down from the root servers and shows you what the authoritative nameservers themselves say.

On Windows without dig installed:

Windows
nslookup -type=A play.example.com 1.1.1.1

Then prove that something is actually listening at the other end, because a correct record pointing at a closed port looks identical to a broken record from the client's side:

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

PowerShell has Test-NetConnection play.example.com -Port 25571 for the same job. For a UDP game there is no equivalent handshake to test, so the real check is the game client itself - game server ports explained goes through why a UDP service can be running and still unreachable.

Subdomains, certificates and the proxy slot#

For anything that speaks HTTP, the name is only half the job. The other half is a certificate, and which name you point at what decides how painful that is.

On RE:NODE, app and web plans include a reverse-proxy slot. You add an A record for your name pointing at the address shown in the panel, and the certificate is issued and renewed automatically inside a 21-day window before expiry. Because the proxy makes the connection to your application, your code sees the proxy as the client and the real visitor address arrives in the X-Forwarded-For header - read that header if you log, rate limit or geolocate, or every visitor will look like the same person. What a reverse proxy does walks through the request in order, and pointing a domain at your server is the step-by-step version including why issuance fails.

Each name needs its own record and its own certificate, so api.example.com and app.example.com are two of everything. That is a feature: the two can move independently, which was the point of the exercise.

Game plans have no proxy slot, and that is the right design - there is nothing sensible for an HTTP proxy to do with a UDP game stream. Your subdomain points straight at the server's address, the port stays in what players type or in an SRV record, and the panel shows both values on the server's own page.

DNS lookupone edit to move a serviceone edit to move a machineHTTPS 443Playerstype play.example.comapi.example.comCNAMEplay.example.comCNAMEde01.example.comA recordGame server203.0.113.10:25571App serverproxy slot, TLS
Two layers of names, one address

Where subdomains bite#

None of these are theoretical. All of them are ordinary.

Dangling records. You delete a server and leave old.example.com pointing at an address that is reassigned to somebody else next week. If the record pointed at a platform rather than a raw address, whoever claims that platform name inherits your subdomain and can serve whatever they like from it, cookies and all. Delete the record at the same time as the server, and treat "resolves to something I do not run" as an incident.

A proxied record in front of game traffic. Cloudflare's orange cloud proxies HTTP and HTTPS. A game protocol is neither, so a proxied record hands players an address that will never accept a game connection. The record a game client resolves must be DNS-only, the grey cloud. Cloudflare for websites and game servers is the full list of what the orange cloud will and will not carry.

Public DNS as a map of your estate. db.example.com, staging.example.com and grafana.example.com are all publicly enumerable, and certificate transparency logs publish every name you ever requested a certificate for. Nothing about that is fatal, but it does mean the name is a hint, and the actual control is the firewall in front of the service. If nothing outside the machine connects to your database, it should have neither a public record nor an open port - the firewall rules that actually matter covers which ports genuinely belong open.

Mail. MX records live on the apex and are not inherited by subdomains. Mail to you@play.example.com is a different configuration from mail to you@example.com, and neither of them is anything a game host provides. We do not host mail, so mail records always stay with whoever does.

FAQ#

Do subdomains cost anything?

No. A subdomain is a record in a zone you already pay for, and every mainstream DNS provider lets you create as many as you want at no extra charge. If somebody is quoting you a price per subdomain, they are selling you hosting, not DNS.

How many subdomains can I have?

Effectively as many as you like. The technical limits are 63 characters per label and 253 for the whole name, and providers cap the number of records per zone at figures in the thousands. The practical limit is how many names you can remember the purpose of, which is much lower.

Should a game server name be an A record or a CNAME?

Either works. A CNAME pointing at a machine name is tidier once you have more than one server, because moves become a single edit. A direct A record is one lookup shorter and perfectly fine for a single server. The one place CNAME is banned is the apex of the domain.

Can a subdomain include the port so players do not have to type it?

Not by itself. A and AAAA records carry an address and nothing else. Use an SRV record for a game whose client reads one, such as Minecraft Java - SRV records for Minecraft has the exact fields - or run the service on its default port.

How long before a new subdomain works?

Publication at your provider is usually seconds. A brand new name has nothing cached anywhere, so it generally works immediately. The delay people experience is when they change an existing record, or when they tested the name before creating it and cached the negative answer.


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