RE:NODE

Web hosting13 min read

Point a domain at your server and get an SSL certificate

The A record, the wait, and the certificate that is issued once the name resolves. What each step does, and the six reasons issuance actually fails.

Updated

0 readers

Three steps, and only one of them is interesting. Add the hostname to the proxy slot on your server, create an A record at your DNS provider pointing at the address the slot shows, and wait for the name to resolve. The certificate is issued automatically once it does, and renewed automatically inside the last 21 days of its life, so there is nothing to do annually.

The interesting step is the waiting, because that is where every failure lives. Certificate issuance checks that the name really points at the server asking for it, which means a certificate cannot be obtained for a name that is still resolving to your old host, that is parked at your registrar, that has a CAA record naming a different authority, or that is hidden behind a CDN whose origin is unreachable. This post is what each record does, how to check what the rest of the world sees rather than what your own machine has cached, and the six things that stop a certificate being issued.

What the proxy slot does#

App and web plans include a reverse-proxy slot. That slot is what turns https://app.example.com into a connection to your container: it accepts the request on the public address, terminates TLS there, and forwards a plain HTTP request to the single port your application is listening on.

name to addressTCP 443X-Forwarded-ForVisitorapp.example.comDNSyour A recordProxy slotTLS ends hereYour appone port, plain HTTP
How a request reaches your app by name

Two consequences of that shape matter for the rest of the post.

Your application never sees TLS. It receives ordinary HTTP on its own port. This is why an app configured to redirect every non-HTTPS request to HTTPS ends up in an infinite loop behind a proxy, and why the client's real address arrives in the X-Forwarded-For header rather than in the connection itself. What a reverse proxy does covers the general case.

It is HTTP, not everything. The proxy slot handles web traffic. A game server is not reached this way: a Minecraft or Valheim server needs the name pointed straight at the server address with an A record, and the players connect to the game port directly. Connecting a domain to a game server covers that, and SRV records for Minecraft covers hiding a non-standard port from players.

We do not run DNS or sell domains here, so the records below are created wherever your domain's DNS lives - the registrar you bought it from, or a DNS provider you moved it to. If you are not sure which one is authoritative for your domain, nameservers vs DNS records is the distinction to read first, because editing records in the wrong control panel is a genuinely common way to spend an afternoon.

The records you need#

For a subdomain, one record. For a whole domain, usually two.

NameTypeValueNote
appAThe address on the proxy slotThe normal case
@AThe address on the proxy slotThe apex, written @ or blank
wwwCNAMEexample.comOr a second A record with the same address
@AAAA-Only if you were given an IPv6 address

Points that catch people:

The apex cannot be a CNAME. The DNS specification does not allow a CNAME to coexist with the other records a domain apex must have. Many providers offer ALIAS, ANAME or CNAME flattening to work around it, which is fine; if yours does not, use an A record at the apex and a CNAME on www.

Pick one canonical host. Serve the site on either example.com or www.example.com and redirect the other to it. Both working independently splits your search results and your cookies. www vs apex domain and redirects has the reasoning and the redirect rules.

Add both names to the proxy slot if both should work. A certificate covers the names it was issued for, and a request for www.example.com arriving at a slot that only knows example.com fails before any redirect can help.

Do not publish an AAAA record you cannot serve. If your server has no IPv6 address, an AAAA record left over from a previous host is worse than useless: browsers and the certificate authority will try it first and fail. Delete it. IPv6 and game servers covers when you do want one.

A subdomain per service is cheap. app.example.com, api.example.com, status.example.com all cost one record each and keep the certificates and the routing separate. See subdomains for servers.

Lower the TTL before you move anything#

Every DNS record has a TTL - the number of seconds a resolver is allowed to cache the answer. The default at most providers is 3600 or 14400, which means up to one or four hours where some resolvers still hand out the old address after you change it.

The fix is to plan one step ahead. At least a day before you intend to change a record, set its TTL to 300. Every resolver that refreshes in the meantime picks up the short value, and when you make the real change the world follows within five minutes instead of four hours. Put it back to 3600 a day after the move.

This is the difference between a cutover that takes minutes and one where a third of your visitors see the old site for the rest of the afternoon. It is also the single most useful thing in this post if you are moving a live site, and it has to be done in advance - lowering the TTL at the moment of the change does nothing, because the old TTL is what is already cached.

Checking what the world sees#

Your own machine is the worst place to test this. It has a resolver cache, possibly a browser cache on top, and sometimes a hosts file entry you added six months ago. Query a public resolver directly instead.

bash
# What the record is, from a resolver that is not yours$ dig +short app.example.com A @1.1.1.1203.0.113.10# Follow the delegation from the root, which shows the authoritative answer$ dig +trace app.example.com# Is anything restricting which authority may issue certificates?$ dig +short example.com CAA0 issue "letsencrypt.org"

On Windows without dig, nslookup app.example.com 1.1.1.1 does the first of those. Online "DNS checker" sites that query twenty resolvers around the world are useful for confirming that a change has spread, and useless for anything else.

What to look for:

  • The answer matches the address on the proxy slot exactly.
  • No stale AAAA record alongside it.
  • No CNAME pointing at your old host that you forgot about.
  • The TTL in the full dig output, which tells you how long the current cached answer has left.

If dig +trace gives a different answer from dig @1.1.1.1, the change is authoritative and simply has not aged out of the public resolver yet. That is normal and it is a matter of waiting.

How the certificate is issued#

Certificates are issued by an authority that first checks you control the name. The common method for a host like this is HTTP validation: the authority asks for a specific file under /.well-known/acme-challenge/ on port 80 for that hostname, and the proxy answers it. If the answer comes back correctly, the certificate is issued, usually within seconds.

That single sentence explains almost everything about the failures. The check happens over the public internet, using public DNS, to port 80. So the name must resolve here, port 80 must reach the proxy, and no redirect may send the authority somewhere that cannot answer. Redirects themselves are followed, so an existing HTTP-to-HTTPS rule is not automatically a problem - the request just has to end up back at this server.

Renewal runs automatically inside the last 21 days of the certificate's validity, which gives several weeks of retries before anything expires. The practical effect is that a domain which stops resolving here will not fail on the day it breaks; it fails three weeks later when renewal has run out of runway, which is a confusing symptom if you do not know to look for it.

Two limits worth knowing before you start retrying in a loop. Certificate authorities rate-limit issuance per domain and per identical set of names, and repeatedly failing validation counts against a separate limit - so twenty attempts in an hour can lock you out for longer than simply fixing the DNS would have taken. Let's Encrypt publishes the current figures at letsencrypt.org/docs/rate-limits, and they do change. Fix the cause, then try once.

Wildcards are the other thing people ask about. A wildcard certificate requires DNS validation rather than HTTP validation, which means the authority needs a TXT record created on demand at your DNS provider. Since the records here live at your provider and not in our panel, the practical answer is to add the specific names you use to the slot. Three subdomains is three names and no extra work. HTTPS and Let's Encrypt explained goes through the validation methods properly.

Why issuance failed#

In the order they actually occur:

1. The name does not resolve here yet. The most common by a distance. Check with dig @1.1.1.1 rather than your browser. If the record is right and the answer is wrong, you are inside the old TTL and the answer is to wait.

2. It resolves somewhere else. You moved from another host and the old A record is still in place, or there are two A records for the same name and the resolver is happily returning the wrong one. A certificate cannot be issued for a name that points at somebody else's server. Delete the old record rather than adding a second one.

3. A CAA record forbids it. A CAA record lists the authorities permitted to issue for your domain. If one exists and does not include the authority being used, every request is refused, cleanly and confusingly. Check with dig +short example.com CAA. Either remove it or add the right authority. This is rare but it is invisible until you look for it.

4. A CDN is in front, in the wrong mode. If your domain is proxied by Cloudflare or similar, the origin still has to be reachable for validation. The usual fix is to turn the proxy off for that record - the grey cloud - get the certificate issued, then turn it back on and set the CDN's origin mode to full or strict. Doing it in the other order produces a redirect loop or a 526. Cloudflare for websites and game servers covers what the orange cloud does and does not do.

5. An AAAA record points at nothing. Both browsers and validation servers prefer IPv6 when an AAAA record exists. If it points at an address that is not yours or not listening, the attempt fails before IPv4 is tried. Remove it.

6. The name on the slot does not match the name in the record. A typo, a trailing dot, or app.example.com.example.com because the DNS provider appends the zone name to whatever you type in the name field. Check the record as the provider displays it after saving, not as you typed it.

After HTTPS works: redirects, headers and the real client IP#

The certificate is not the finish line. Four things to set in the application behind the proxy.

Trust the proxy. Until you do, every request appears to come from the proxy's own address, which breaks rate limiting, abuse blocking, analytics and your access logs. In Express that is app.set("trust proxy", 1); Django uses SECURE_PROXY_SSL_HEADER; Laravel has a TrustProxies middleware; WordPress behind a proxy usually needs a few lines in wp-config.php that read X-Forwarded-Proto. Deploy a Node.js app from GitHub has the Node version in context.

Do not force HTTPS inside the app. The proxy speaks plain HTTP to your container, so an application that checks "is this request secure" and redirects if not will redirect forever. Check X-Forwarded-Proto instead, or leave the redirect to the proxy.

Fix mixed content. A page served over HTTPS that loads a script or image over HTTP is blocked by the browser, and the symptom is a half-rendered page rather than an error you notice. For a CMS this is usually old absolute URLs stored in the database; a search-and-replace across the content is the fix, and migrate WordPress to a new host covers doing it safely.

Be careful with HSTS. The Strict-Transport-Security header tells browsers never to use HTTP for your domain again, for as long as max-age says. That is good once everything is stable and painful while you are still moving things, because a browser that has cached it will not let you fall back. Start at max-age=300, raise it to a year when you are confident, and leave the preload list alone until you are certain you will never serve that domain over HTTP.

Moving a live site without a gap#

The sequence that keeps the old site serving until the new one is ready:

  1. A day ahead, lower the TTL on the records you are going to change to 300.
  2. Build the site on the new server and test it before any DNS changes, using an entry in your own machine's hosts file that maps the domain to the new address. You will see the new site while everybody else still sees the old one.
  3. Copy the data last. Files, then database, then whatever changed in between. Freeze writes on the old site for the final sync if you can - an hour of read-only beats a day of lost orders.
  4. Change the A record. Watch with dig @1.1.1.1 until the new address comes back.
  5. Wait for the certificate. It cannot be issued before the name points here, so there is a window of a minute or two after the DNS change where visitors may see a warning. Doing the cutover at a quiet hour makes that window free.
  6. Leave the old host running for a week. Resolvers with long-cached answers, corporate DNS and a few stubborn devices will keep arriving there. It costs one more month of hosting and saves the argument about who lost the orders.
  7. Put the TTL back to 3600 once you are settled.

FAQ#

How long does DNS take to update?

Up to the TTL of the record you changed, as cached by each resolver - so an hour with a default TTL of 3600, four hours with 14400, and about five minutes if you lowered it to 300 a day in advance. A brand new name that nobody has looked up before resolves immediately, because there is nothing cached to expire.

Why is my certificate not being issued?

Almost always because the name does not resolve to this server yet, or resolves to your previous host. Check with dig +short yourname @1.1.1.1 from outside your own network. After that, look for a CAA record restricting the authority, a stale AAAA record, a CDN proxy hiding the origin, and a typo in the record name. Fix the cause and try once rather than retrying repeatedly, because failed validations are rate-limited.

Do I need to renew the certificate every year?

No. Renewal runs automatically inside the last 21 days of validity. The only thing that stops it is the name ceasing to resolve here, and because of the long renewal window that failure shows up weeks after the DNS change that caused it.

Can I use a domain with a game server?

Yes, but through a plain A record pointing at the server address, not through the proxy slot - game traffic is not HTTP. Players then connect to the name and the game port. For Minecraft, an SRV record additionally lets players omit the port entirely.

Can I buy a domain here?

No. We do not register domains or run a DNS zone editor, so your domain stays with your registrar or DNS provider and you create the records there. All you need from us is the address shown on the proxy slot.

What about www and the apex - do I need two certificates?

One certificate can cover both names, but both have to be added to the slot and both have to resolve here. Add them, then redirect one to the other in your application or CMS so that only one is canonical, which keeps your analytics and your search results from splitting in two.


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