November 4, 2026 · In Ayotl
Three domains that opened for some and not for others
The server was fine and the health check said "success" all night. Still, for Cloudflare, OpenDNS and Google's checker, mercadito.cx did not exist. The next day it happened to jlptest.org, and by midday it was happening to dailychallenge.click without anyone knowing. It was DNS, all three lived in the same place, and this is what we learned moving them.
What happened
On the night of 3 November, Google Play rejected the Mercadito app because its checker couldn't open the privacy policy URL. The policy was online. Two phones opened the page fine, from cache; Cloudflare, OpenDNS and Google's checker didn't. The server on Railway was fine and the health check on GitHub had said "success" all night. Had that review not been in progress, the partial outage would have gone on until some business said "the menu won't open".
The next morning it was jlptest.org's turn, with the same symptoms. And when the checks were run on the third domain of the family, dailychallenge.click was failing at that very moment: Hostinger's two name servers returned SERVFAIL on seven of every eight queries for the A record at the apex; Cloudflare, Google and OpenDNS no longer resolved it, and only Quad9 was still answering from its cache. No complaints, no warning. The only trace was that the morning's automatic post had gone out on Facebook and not on Instagram: Instagram fetches the image from the domain, and couldn't resolve it.
By 12:40 on 4 November all three domains were on Cloudflare and resolved on every public resolver; three minutes later, the .org and .click registries already pointed at the new name servers.
Why
All three domains pointed at Railway with an ALIAS record at the apex, in Hostinger's DNS. Railway gives you a name, not an IP; on a subdomain that resolves with a normal CNAME, but the DNS standard doesn't allow a CNAME at the apex, so some providers offer an "ALIAS" that resolves the name behind the scenes and returns the IP every time someone asks. Hostinger offers it, and Railway documents that it doesn't work reliably there. That resolution is what broke, on all three, a day apart.
The failure was silent and partial. Hostinger's servers kept answering the SOA, the TXT and the NS records; only the A record at the apex returned SERVFAIL, and not always: one query in eight came back fine. Since the big resolvers have several points of presence and keep caches, some kept giving the IP and others didn't. Nobody got a warning, not from Hostinger, not from Railway, not from the health check, because the server was fine and the check was asking a resolver that still had the answer cached. From the outside, a DNS failure looks like anything else: like "invalid privacy policy", or like a reel that doesn't show up on Instagram.
How it gets fixed
In two steps, in this order. First the patch: replace the ALIAS with an A record holding the IP the Railway name returns at that moment, with a five-minute TTL. It works within minutes, but it's fragile, because Railway doesn't promise that IP stays fixed: in fact, between the morning and midday the name of one of the domains was already returning a different one. It keeps the domain up while the real fix is done, and gives an answer to the resolvers that keep asking the old provider during the move.
Then the fix: move DNS to Cloudflare, which does flatten the CNAME at the apex and which Railway supports explicitly. It's free and doesn't move the domain away from the registrar: only the name servers change. What we learned doing it three times in one day:
- Cloudflare's automatic scan is not an inventory. Of Daily Challenge's nine records it found four: the www and the TXT records at the apex. It didn't see the ALIAS (it can't), nor the CNAME of Kazan's subdomain, nor the TXT records Railway uses to verify each domain. Open the registrar's zone and compare it record by record before changing anything.
- Every custom domain has its own target on Railway. The apex's isn't the www's nor the subdomain's: they're three different up.railway.app names, and the apex has to go to its own. Cloudflare accepts the CNAME at the apex and flattens it by itself.
- Everything with the grey cloud, "DNS only". With the proxy on, Cloudflare would try to serve the certificate and Railway could no longer renew its own.
- Railway's verification TXT records (_railway-verify and the ones for each subdomain) get copied too. They cost nothing and save having to verify the domain again.
- Before changing the name servers, ask Cloudflare's server directly for each record (dig @alec.ns.cloudflare.com …). If it answers correctly there, the move can't go wrong; if it doesn't, nothing is broken yet.
- With the patch in place at the old provider, the name-server change has no outage window. For .org and .click the registry updated within minutes; Cloudflare emails when the zone goes active.
- If the domain sends or receives email, the mail records go on the same list. jlptest.org sends its sign-in emails through Resend and had four (SPF, DKIM, DMARC and the bounce MX) that the scan wouldn't have found in full either; they were copied and checked one by one on the new server. A domain that resolves but no longer signs its email is the same silent failure in a different disguise.
What to do differently
- Before pointing an apex at a PaaS (Railway, Render, Fly, Vercel…), read its domains page and the list of DNS providers that don't support flattening or ALIAS. If the registrar is on the list, don't use its DNS: Cloudflare, in "DNS only", from day one, or put the site on www and redirect the apex. Hostinger, GoDaddy, Route 53, Azure DNS and Squarespace were on Railway's list.
- Registrar and DNS are two different things. Buy the domain wherever you like, but take the DNS to a provider built for it.
- Never a fixed A record to a PaaS, except as a patch with a short TTL, noted down so it gets removed.
- When one domain in the family fails, check its siblings that same hour and move all of them, not just the one that broke. Daily Challenge had been half down for hours and nobody knew; it was found because someone looked.
- Watch the DNS, not just the server. An external check that resolves each domain from several resolvers (1.1.1.1, 8.8.8.8, 9.9.9.9) and opens the URL every few minutes would have warned before Google did. There are free services; one per project is enough.
- When something fails "halfway", for some and not for others, suspect DNS first.
- When a store, Google or a customer says "it won't open", don't settle for their diagnosis. "Invalid policy" was a symptom; the problem wasn't in the policy.
The commands
# ¿contesta el servidor que manda? (SERVFAIL = la falla)
dig @atlas.dns-parking.com dailychallenge.click A
# ¿coinciden los resolvedores públicos?
dig @1.1.1.1 dailychallenge.click A
dig @8.8.8.8 dailychallenge.click A
# ¿el servidor sirve si lo alcanzas directo, sin DNS?
curl --resolve dailychallenge.click:443:<IP> https://dailychallenge.click/# los hermanos, de un tirón: un SERVFAIL en cualquiera es la falla
for d in mercadito.cx jlptest.org dailychallenge.click; do
for r in 1.1.1.1 8.8.8.8 9.9.9.9; do
echo "$d @$r: $(dig @$r $d A +time=3 +tries=1 | grep -o 'status: [A-Z]*')"
done
done
# antes de cambiar los servidores de nombres: ¿la zona nueva contesta bien?
dig @alec.ns.cloudflare.com dailychallenge.click A
dig @alec.ns.cloudflare.com kazan.dailychallenge.click CNAME
dig @alec.ns.cloudflare.com _railway-verify.dailychallenge.click TXT
# después: ¿ya cambió en el registro?
dig +short NS dailychallenge.click @8.8.8.8And a lesson of another kind that showed up along the way: what isn't looked at doesn't get updated. Mercadito's site manifest and its privacy policy were still describing home delivery two and a half months after it was removed. Every time a product changes its model, it pays to keep a short list of "texts outside the app" (policy, stores, manifest, metadata, automatic emails) and review them the same day.