DNS Records Setup in Practice — Connecting a Domain to a Server or the Cloud (A, CNAME, apex, TTL)
You bought a domain and set up a server, but typing the address doesn’t bring up the site. The point where this gets stuck is almost always DNS configuration. In this post I’ll walk through connecting a domain to an actual server or the cloud, step by step, centered on A, CNAME, apex, and TTL. If you want to start from what a domain, nameserver, and record even are, I recommend reading What Is a Domain, and Why Do You Need One? first.
First decide: where to put the nameserver #
The first decision when connecting a domain is “who will operate this domain’s DNS?” There are broadly two options.
- Use the registrar’s default nameservers: write records directly into the DNS provided by where you bought the domain (e.g., GoDaddy, Cloudflare Registrar). Enough for a simple site.
- Delegate to an external DNS: at the registrar, change only the nameservers to an external service (Cloudflare, AWS Route 53, etc.) and manage the records there. Choose this when you need features like caching, a proxy, or health checks.
To delegate, change the nameserver entries on the registrar’s screen to the values the external service gives you.
# Example: delegating to Cloudflare, set these nameservers at the registrar
ns1.cloudflare.com
ns2.cloudflare.comRight after changing nameservers, some places still look at the old ones, so it takes time for the change to fully settle. That’s why it’s safer to finish nameserver delegation a few days before you seriously move the site.
Core records and their real values #
Five record types are enough for most connection work.
| Record | Role | Example value |
|---|---|---|
| A | name → IPv4 address | 203.0.113.10 |
| AAAA | name → IPv6 address | 2001:db8::1 |
| CNAME | name → another name | schoolofweb.net |
| MX | designate mail-receiving server | 10 mail.example.com |
| TXT | authentication / ownership note | v=spf1 include:... |
The simplest form looks like this. If you put the site on a single server with a fixed IP, set the apex domain and www like so.
# name type value
@ A 203.0.113.10
www CNAME schoolofweb.netHere @ means the apex domain with no prefix like www — that is, schoolofweb.net itself.
The apex domain trap #
The place where people get stuck most in practice is the apex domain. By the rules, you cannot put a CNAME on the apex (@). A CNAME can’t coexist with any other record on that name, and the apex has records that must be present, like MX and TXT.
The problem is that hosting and CDNs these days give you a name (e.g., myapp.vercel.app) rather than a fixed IP as the connection target. Since you can’t use a CNAME on the apex, you can’t attach that name directly. The fix is one of the following features your DNS service provides.
- ALIAS or ANAME record: a special record that lets the apex point to a name too. (Route 53’s Alias, some DNS providers’ ANAME.)
- CNAME flattening: you write a CNAME-like entry on the apex, and the DNS service swaps it for the real IP at response time. (Cloudflare is the well-known example.)
If you have neither, your only option is to get the target’s fixed IP and put an A record directly on the apex. In that case, if the target IP changes, you have to follow and fix it yourself.
Setup by environment #
Putting it on a Linux server directly #
If you run the site with Nginx on a Linux server with a fixed public IP, the connection is one A record.
@ A 203.0.113.10
www CNAME schoolofweb.netOn the server, configure Nginx to accept both names.
server {
listen 80;
server_name schoolofweb.net www.schoolofweb.net;
# ...
}After setup, check with dig that the name resolves to the intended IP.
dig +short schoolofweb.net A
# 203.0.113.10
dig +short www.schoolofweb.net
# schoolofweb.net.
# 203.0.113.10Putting it on managed cloud #
When you sit behind a load balancer or CDN, the target is often a name rather than a fixed IP.
- AWS (Route 53 + ALB/CloudFront):
wwwpoints to the load balancer name with a CNAME or Alias, and the apex points to the same target with an Alias record. Alias works without charge when pointing to AWS-internal resources. - Cloudflare: write the target name CNAME-style on both apex and
www, and thanks to CNAME flattening it works on the apex too. Turn on the orange cloud (proxy) and traffic comes through Cloudflare.
# Cloudflare example (proxy on)
@ CNAME myapp.example-host.com (flattening applied)
www CNAME myapp.example-host.comTTL and propagation: lower the TTL before you move #
Each record has a TTL (Time To Live) — a value in seconds for how long others may cache it. If the TTL is 3600, others may not see the changed value for an hour.
So work that changes an IP, like a server migration, must be done in the right order.
- A day before the move, lower the record’s TTL to
300(5 minutes) or less. - Wait until the lowered TTL has propagated (as long as the original TTL).
- At the actual move, change the record’s value to the new IP. Now most of it reflects within 5 minutes.
- Once stable, raise the TTL back to around
3600.
This spreading of the changed record across the world’s caches is called propagation, and lowering the TTL in advance greatly reduces the gap caused by it.
Verification tool: how to read dig #
Don’t guess whether the setup resolves as intended — check with dig. dig (Domain Information Groper) queries DNS directly and shows the response as is; it’s usually included by default on Linux and macOS.
Basic query and reading the output #
Query with no options and the full response appears.
$ dig schoolofweb.net A; <<>> DiG 9.18.18 <<>> schoolofweb.net A
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 24561
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; QUESTION SECTION:
;schoolofweb.net. IN A
;; ANSWER SECTION:
schoolofweb.net. 300 IN A 203.0.113.10
;; Query time: 31 msec
;; SERVER: 127.0.0.53#53(127.0.0.53) (UDP)
;; WHEN: Tue Jul 28 10:12:04 KST 2026
;; MSG SIZE rcvd: 71There are two places to read.
status:NOERRORmeans a normal response.NXDOMAINmeans the domain itself doesn’t exist, andNOERRORwithANSWER: 0means the domain exists but has no record of that type.ANSWER SECTION: the actual answer. Each line is in the ordername / TTL / class (IN) / type / value; above,300is the TTL (seconds) and203.0.113.10is the connected IP.
See just the value: +short #
To see the value quickly, add +short.
$ dig +short schoolofweb.net A
203.0.113.10A name with a CNAME, like www, shows the chain as is. The top is the CNAME target, below it the final IP.
$ dig +short www.schoolofweb.net
schoolofweb.net.
203.0.113.10Query by record type #
Check the same way, swapping the type.
$ dig +short schoolofweb.net MX
10 mail.schoolofweb.net.
$ dig +short schoolofweb.net TXT
"v=spf1 include:_spf.example.com ~all"
$ dig +short schoolofweb.net NS
ns1.cloudflare.com.
ns2.cloudflare.com.Ask a specific server directly: @ #
Use @ to specify which server to query. Asking the authoritative nameserver directly lets you see the original value regardless of propagation, and asking a public resolver (e.g., 1.1.1.1) shows the cached value ordinary users get.
# Directly to the authoritative nameserver (the original, even before propagation)
$ dig @ns1.cloudflare.com schoolofweb.net A +short
203.0.113.10
# Through a public resolver (what users actually get)
$ dig @1.1.1.1 schoolofweb.net A +short
203.0.113.10If the two differ, it’s a sign propagation hasn’t finished yet.
Read propagation state from the TTL #
In a cached response, the TTL counts down toward 0. Trim to just the answer with +noall +answer and query again a little later, and you’ll see the number shrink.
$ dig +noall +answer schoolofweb.net A
schoolofweb.net. 287 IN A 203.0.113.10287 means 13 seconds have passed since the original TTL of 300. When it hits 0, the resolver asks the authoritative server again and gets the new value, so lowering the TTL before a move makes the new value reflect that much faster.
Trace from the root step by step: +trace #
When a response looks off, +trace lets you follow step by step who answers what, from the root down to the authoritative server.
$ dig +trace schoolofweb.net. 518400 IN NS a.root-servers.net.
...
net. 172800 IN NS a.gtld-servers.net.
...
schoolofweb.net. 86400 IN NS ns1.cloudflare.com.
schoolofweb.net. 300 IN A 203.0.113.10From top to bottom, delegation flows root → net → the domain’s authoritative nameserver. If it breaks in the middle or an unexpected server appears, that stage’s delegation is wrong.
When dig isn’t available #
In environments without dig (some Windows, etc.), you can do basic lookups with nslookup.
$ nslookup schoolofweb.net
$ nslookup -type=MX schoolofweb.netCommon-mistake checklist #
- Stuck trying to put a CNAME on the apex: use ALIAS/ANAME or CNAME flattening, or put an A record on a fixed IP.
- Only
wwwworks, apex doesn’t: you left out the apex (@) record. Check that you set both names. - An old A record is still there: if you only add the new record without deleting the old value, some visitors still go to the old server.
- A high TTL hides the change: don’t keep re-editing the value because it didn’t change instantly; check the TTL and propagation time first.
- Mail breaks: you delegated the nameservers but didn’t move MX/TXT (SPF/DKIM) to the new DNS. For how mail delivery works, see How Email Reaches the Other Side.
Wrapping up #
Connecting a domain comes down to “which nameserver answers, and what records you write there.” The key is knowing the apex domain’s CNAME restriction and picking the right fix among ALIAS, flattening, and an A record, and lowering the TTL in advance before a move to reduce the propagation gap.
Once the domain is connected, the next step is the HTTPS certificate. How to actually obtain a certificate and renew it automatically continues in HTTPS Certificates in Practice.