DNS Records Setup in Practice — Connecting a Domain to a Server or the Cloud (A, CNAME, apex, TTL)

8 min read

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.com

Right 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.

RecordRoleExample value
Aname → IPv4 address203.0.113.10
AAAAname → IPv6 address2001:db8::1
CNAMEname → another nameschoolofweb.net
MXdesignate mail-receiving server10 mail.example.com
TXTauthentication / ownership notev=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.net

Here @ 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.net

On 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.10

Putting 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): www points 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.com

TTL 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.

  1. A day before the move, lower the record’s TTL to 300 (5 minutes) or less.
  2. Wait until the lowered TTL has propagated (as long as the original TTL).
  3. At the actual move, change the record’s value to the new IP. Now most of it reflects within 5 minutes.
  4. 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: 71

There are two places to read.

  • status: NOERROR means a normal response. NXDOMAIN means the domain itself doesn’t exist, and NOERROR with ANSWER: 0 means the domain exists but has no record of that type.
  • ANSWER SECTION: the actual answer. Each line is in the order name / TTL / class (IN) / type / value; above, 300 is the TTL (seconds) and 203.0.113.10 is the connected IP.

See just the value: +short #

To see the value quickly, add +short.

$ dig +short schoolofweb.net A
203.0.113.10

A 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.10

Query 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.10

If 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.10

287 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.10

From 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.net

Common-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 www works, 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.

X