An inventory of public hostnames is a list of decisions: for every name, keep it, protect it, redirect it, or retire it. We ran the discovery half against our own domain on 26 September 2026, and the results show why DNS lookups alone cannot produce the list.
Certificate Transparency: every name that ever had a certificate
Publicly trusted CAs log the certificates they issue to Certificate Transparency (CT) logs, which RFC 6962 designs as public, append-only records that anyone can query and monitor. crt.sh indexes those logs. We saved every entry matching %.and.guide as JSON:
curl -s 'https://crt.sh/?q=%25.and.guide&output=json' -o and-guide-ct.json
crt.sh is a free service and can be slow; if a request times out or returns something other than JSON, retry before concluding anything.
Live capture, 26 September 2026. Summarizing that file (fetched at 14:39 UTC) with jq:
$ jq length and-guide-ct.json
1875
$ jq '[.[].serial_number] | unique | length' and-guide-ct.json
967
$ jq -r '.[].name_value' and-guide-ct.json | sort -u | wc -l
113
$ jq -r --arg now 2026-09-26T14:40 '.[] | select(.not_after > $now) | .name_value' and-guide-ct.json | sort -u | wc -l
11
$ jq -r '[.[].not_before] | min, max' and-guide-ct.json
2021-05-02T04:15:44
2026-09-06T14:25:26
$ jq -r 'unique_by(.serial_number) | .[].issuer_name | capture("O=(?<o>\"[^\"]+\"|[^,]+)").o' and-guide-ct.json | sort | uniq -c | sort -rn
872 Let's Encrypt
86 Google Trust Services
3 Sectigo Limited
3 "CLOUDFLARE, INC."
2 SSL Corporation
1 Google Trust Services LLC
$ jq -r '[.[] | {n: (.name_value | split("\n")[]), y: .not_before[:4]}] | group_by(.n) | map(max_by(.y).y) | group_by(.) | map("\(.[0]): \(length) names")[]' and-guide-ct.json
2021: 9 names
2022: 49 names
2023: 5 names
2024: 14 names
2025: 25 names
2026: 11 names
What the numbers say:
- 1,875 rows, 967 certificates. Most certificates appear twice, once as a precertificate logged before issuance and once as the final certificate, so count distinct serial numbers, not rows.
- 113 names, 11 current. Only 11 names appear in a certificate that had not expired on the capture date; 102 exist only in expired certificates. The last list above groups names by the year they were last certified: 49 of them were last seen in 2022.
- Several issuance paths. Let’s Encrypt and Google Trust Services account for almost everything, with a handful from Sectigo and from Cloudflare-branded intermediates. Each issuer points to a path that requested certificates (an edge platform, a hosting product, or a server’s own ACME client), and a CAA policy would have to allow every one still in use.
- The names themselves. The list includes staging and test labels, labels named after tools, names nested two levels deep, and wildcard certificates for whole sub-branches. Adding up the years, 77 of the 113 names were last certified before 2025. We are not reproducing the list here: anyone can pull it from CT, but there is no reason for a guide to spotlight it.
CT is both a discovery source and a leak. Every hostname that ever received its own publicly trusted certificate is listed, and entries cannot be removed, so deleting a DNS record does not unpublish the name. Keep client names, unreleased products, and anything sensitive out of hostnames; a wildcard certificate shows only *.parent. The reverse gap matters too: names that never had a publicly trusted certificate, such as DNS-only records and internal names, never appear in CT at all.
A deliberate wildcard makes every name resolve
Our zone contains a wildcard pointing at our self-hosted deployment server for our own apps. Apps are deployed on subdomains, and the server’s routing table decides which names serve anything.
Live capture, 26 September 2026. The wildcard record itself and an invented label (15:13 UTC):
$ for n in "*" zz-inventory-probe-0926; do dig +nocmd @1.1.1.1 "$n.and.guide" A +noall +answer; done
*.and.guide. 300 IN A 115.68.101.36
zz-inventory-probe-0926.and.guide. 300 IN A 115.68.101.36
$ dig +nocmd @1.1.1.1 and.guide DS +noall +comments | grep -E "status|ANSWER"
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 26998
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1
Under RFC 4592, a name server synthesizes an answer from a wildcard for any name that does not otherwise exist, so our invented label received exactly the same record and TTL as the wildcard. Two historical names from the CT list that we checked earlier the same evening got that identical answer too, and a two-level invented name, zz-a.zz-b.and.guide, resolved the same way. The empty DS answer shows the zone is not DNSSEC-signed, so there are no signatures that could reveal which answers were synthesized.
With a wildcard in place, the real inventory lives in two places: the deployment server’s routing table, which says which names are served, and CT logs, which say which names were ever certified. DNS answers say nothing either way. Two more consequences:
- Only the zone itself (an export or the DNS provider’s API) shows whether a given name is an explicit record or a wildcard answer.
- Deleting an explicit record under a wildcard does not produce
NXDOMAIN. The name stops existing, so the wildcard answers for it instead.
Probe DNS, HTTP, and TLS as separate facts
Live capture, 26 September 2026. HTTP and HTTPS results for the invented name, using curl 8.7.1 (verify is curl’s ssl_verify_result, where 0 means the certificate verified; 15:13 UTC):
$ for n in zz-inventory-probe-0926; do printf "%-34s " "$n.and.guide"; curl -s -o /dev/null --max-time 10 -w "http=%{http_code} " "http://$n.and.guide/"; curl -s -o /dev/null --max-time 10 -w "https=%{http_code} verify=%{ssl_verify_result}\n" "https://$n.and.guide/"; done
zz-inventory-probe-0926.and.guide http=404 https=000 verify=20
Earlier that evening we ran the same probe against two historical names from the CT list, read each certificate with OpenSSL, and looked up their CT history in the file above. We describe them without naming them:
| Name | DNS | HTTP | HTTPS | Certificate presented | CT history |
|---|---|---|---|---|---|
| Invented label | 115.68.101.36 | 404 | TLS verification fails | The server’s self-signed default | None |
| Historical name A | 115.68.101.36 | 404 | TLS verification fails | The server’s self-signed default | 18 entries, January 2023 to May 2024 |
| Historical name B | 115.68.101.36 | 404 | 503 over valid TLS | Let’s Encrypt (YR2), valid until 9 November 2026 | 34 entries, July 2021 to August 2026 |
Identical DNS, three different stories:
- The invented name and name A get the server’s fallback: a plain-text 404 over HTTP, and over HTTPS a self-signed default certificate that fails verification (
verify=20is the OpenSSL-family code for “unable to get local issuer certificate”, the same error curl prints in full when you fetch the invented name directly). Name A stopped receiving certificates in May 2024, which fits a route that was removed. For a retired name this fails closed, although a browser shows a certificate warning rather than a clean 404. - Name B still has a route: the server keeps renewing its certificate (the latest was issued 11 August 2026) and answers 503. A renewing certificate is not evidence of a live service. A name in this state needs a decision: restore the app, or remove the route so renewals stop and the name falls back to the default.
- The names we intend to keep behaved as designed in the same session:
https://www.and.guide/returned301withlocation: https://and.guide/, andhttps://and.guide/returned200.
Record probe outcomes in terms that point to the failing layer:
NXDOMAIN: the name does not exist (names covered by a wildcard never return it).NOERRORwith no answer: the name exists but has no record of that type.2xx: read the body; a template or “not found” page served with200is a soft 404.3xx: confirm the final target is the closest relevant replacement.4xx: separate access control (401,403) from retirement (404,410).5xx: an availability defect, never a removal method.- TLS failure: fix routing or the certificate, unless the failure is the intended fail-closed state.
Build the list from systems of record
Certificate Transparency and probes find candidates. The inventory itself comes from systems you control:
- The DNS zone, exported or listed through the provider’s API, including wildcards and delegations. It is the only source that separates explicit records from wildcard answers.
- Routing tables behind wildcards: the host rules on any server or proxy that the wildcard points at, plus the certificate names its ACME client renews.
- Platform bindings: custom domains in each hosting, CDN, and tunnel account. One of our names, for example, is a CNAME to a Cloudflare Pages project; the zone holds the CNAME, the Pages project holds the binding, and neither alone tells the whole story.
- Infrastructure-as-code and deployment configuration that mentions the domain.
- Certificate Transparency results, as above, for names that none of the systems above remember.
- Request logs and Search Console data for names that still receive traffic or appear in search.
Keep one row per hostname:
| Field | Record |
|---|---|
| Hostname | The exact name, including every label |
| Purpose and owner | What visitors should find, and who can approve changes |
| DNS | Record type, target, proxied or DNS-only, explicit or wildcard |
| Platform or route | Hosting project, origin, or routing rule that serves it |
| HTTP and TLS state | Latest probe results with the date |
| Decision and deadline | Keep, protect, redirect, or retire, and by when |
An entry without an owner is already a cleanup candidate. If the label itself is unclear, check it against the subdomain naming rules before deciding it deserves a permanent place.
Choose the final state
| Decision | What the name should return | Search handling |
|---|---|---|
| Keep public | 200 with real content over valid TLS |
List canonical URLs in the sitemap |
| Keep, out of search | 200 with a crawlable noindex |
Remove from the sitemap, and do not block the URL in robots.txt, or crawlers never see the noindex |
| Protect | Real authentication or network restriction | Nothing public to index |
| Move | 301 or 308 to the closest equivalent URL |
Google treats both as strong redirect signals |
| Retire | 404 or 410 |
Google treats all 4xx codes except 429 the same and drops indexed URLs |
Do not use 5xx as an end state. Google’s crawler documentation says server errors slow crawling while already indexed URLs are kept for a time and only eventually dropped. For urgent cases, Search Console’s Removals tool hides a URL from Google Search for about six months; it is temporary and affects Google only, so pair it with one of the permanent states above. Sitemaps are hints, not commands: list only canonical URLs you want in results, and set lastmod only when it is accurate.
Retire names in an order you can verify
- Freeze new deployments and preview creation for the name.
- Remove internal links, navigation entries, feeds, and sitemap URLs that point to it.
- Put the final response in place (redirect, authentication,
noindex,404, or410) and confirm robots.txt does not hide it. - Leave that response up until crawlers and your own probes have seen it.
- Remove the DNS record first, then the platform binding or server route. In that order, the name never points at a resource another customer could claim (the dangling DNS guide explains the risk), and removing the binding or route stops certificate renewals, so the CT log stops growing for a name you retired.
- Under a wildcard, the name keeps resolving after its record is gone. Remove its route on the server the wildcard points at, and confirm that server fails closed for names it does not serve.
- Probe DNS, HTTP, and TLS again from outside your network and update the row.
Keep the inventory current
Re-run the CT query on a schedule and compare the list of names with the previous run; names you do not recognize are the ones to investigate first. Cloudflare’s Certificate Transparency Monitoring can email you when a new certificate is issued for your domain, and it filters out certificates Cloudflare issues on your behalf, including backup certificates. On a zone like ours, what remains are certificates requested by our own servers or by third parties, which are exactly the ones a dashboard does not show.
Run the full inventory again after migrations, hosting changes, wildcard changes, and changes to how previews are created. A stable namespace is cheaper to check on a schedule than to reconstruct after an abandoned name surfaces again.