Troubleshooting guide

Custom domain SSL not working but the default URL loads

The app works on the host's default address, such as your-app.vercel.app or your-site.netlify.app. Your own domain gives TLS errors, redirect loops or half-loaded pages, or its certificate never renews. This pattern appears in 20 verified builder reports in our data. Usually no code has changed. The custom domain adds DNS, proxy and certificate layers that the default address skips.

20 verified cases8 min read Updated 27 Sep 2026How we collect cases

What you'll see

  • The platform subdomain loads fully, but the custom domain fails with ERR_SSL_PROTOCOL_ERROR or a TLS handshake reset, even though the dashboard shows the certificate as valid.
  • The browser stops with ERR_TOO_MANY_REDIRECTS after you put a CDN or proxy such as Cloudflare in front of the host.
  • On the custom domain, HTML is cut off partway, images stall or the host returns 500s, while the same page on the default address loads in full.
  • A certificate renewal sits in pending validation for days while the expiry date approaches.
  • The site goes offline after a wildcard certificate expires, and renewal attempts fail with a rate-limit error.
  • The site works on some devices or networks and fails with SSL errors on others.

Why it happens

Cause 1

Stale or leftover DNS records

Records from a previous host still answer for your domain. A leftover AAAA record is a common case. Netlify's load balancer does not support IPv6 and Vercel does not support IPv6 yet, so devices that prefer IPv6 reach the old server while other devices work. Old _acme-challenge TXT records from a previous provider can also misdirect DNS-01 validation, and issuance or renewal stalls.

Cause 2

A proxy or CDN sits in the validation path

HTTP-01 validation fetches http://<domain>/.well-known/acme-challenge/<token> on port 80. If a proxy in front of the host caches that path, redirects it, puts it behind authentication or answers it itself, the host's certificate authority never sees the token. The renewal then waits in pending validation until the certificate expires. The same proxy can also cause redirect loops. In Cloudflare's Flexible mode, Cloudflare sends plain HTTP to the origin, and an origin that redirects every HTTP request to HTTPS sends it straight back.

Cause 3

Wildcard renewals that fail until the rate limit locks you out

Wildcard certificates can only be issued with DNS-01, so the host must create a TXT record at _acme-challenge.<domain> for every renewal. If the nameservers or the challenge delegation changed, the host cannot create it and every renewal fails. Let's Encrypt allows 5 authorization failures per hostname per account per hour and 5 certificates for the same exact set of names every 7 days. Repeated retries can lock you out while the old certificate expires.

Cause 4

The domain is claimed elsewhere, or CAA excludes the CA

On Vercel, a domain can belong to only one personal account or team at a time. A domain still attached to an old project or account will not verify on the new one until you move it or prove ownership with a TXT record. Separately, a CAA record that does not include your host's certificate authority blocks issuance outright.

Cause 5

A fault at the host's edge for your hostname only

Traffic for the default address and for your custom domain can take different paths through the host, each with its own certificate and routing. If DNS is correct and the certificate is valid, but the custom domain still truncates responses or resets handshakes while the default address works, the fault is on the host's side. Only the host can fix it.

How to fix it

  1. Compare the custom domain with the default address

    Request the same path on both and compare the status code and the byte count. If only the custom domain returns a different size or fails the handshake, the problem is in DNS, the proxy, the certificate or the host's edge, not in your code.

    curl -sS -o /dev/null -w '%{http_code} %{size_download} bytes\n' https://your-app.vercel.app/
    curl -sS -o /dev/null -w '%{http_code} %{size_download} bytes\n' https://example.com/
  2. Audit every DNS record for the hostname

    Compare the answers with the exact records listed in your host's domain settings. Remove A and AAAA records that point at a previous host. Before you delete an _acme-challenge record, find out which provider it belongs to. Keep any NS records your current host asked you to add to delegate validation.

    dig NS example.com +short
    dig A example.com +short
    dig AAAA example.com +short
    dig CNAME www.example.com +short
    dig TXT _acme-challenge.example.com +short
  3. Let the validation request reach the host

    A made-up token should return a plain 404 from your host, not a redirect, a login page or a cached page from the proxy. Route /.well-known/acme-challenge/* to the host on port 80 without caching, authentication or proxy-level redirects, or set the Cloudflare record to DNS only. If you keep Cloudflare proxying and the origin already forces HTTPS, set the SSL/TLS encryption mode to Full or Full (strict), not Flexible.

    curl -sS -D - -o /dev/null http://example.com/.well-known/acme-challenge/test-token
  4. Stop retrying a rate-limited renewal

    Each failed attempt counts against the authorization-failure limit. Fix the DNS or proxy path first, test it with Let's Debug (letsdebug.net), then trigger one renewal. For wildcards, use the host's nameservers or delegate _acme-challenge to the host so it can complete DNS-01 on its own.

  5. Detach the domain from old projects and check CAA

    Remove the domain from any old project, team or host before you add it to the new one, and complete any TXT ownership check you are asked for. If a CAA policy exists at the hostname or a parent domain, it must allow your host's certificate authority. Vercel and Netlify issue certificates through Let's Encrypt.

    dig CAA example.com +noall +answer
    # if a policy exists, it must include:
    # example.com. CAA 0 issue "letsencrypt.org"
  6. Monitor the custom domain and alert on expiry

    Point uptime checks and smoke tests at the custom domain, not the platform URL. Add an expiry check that fails when the certificate has fewer than 14 days left, so a stuck renewal pages you while there is still time to fix it.

    echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
      | openssl x509 -noout -enddate -checkend 1209600
  7. Escalate edge faults early, with evidence

    If DNS and the certificate are correct and the default address works where the custom domain does not, open a support ticket. Include the hostname, timestamps, the browser error, your dig output and the curl comparison. Strip cookies and Authorization headers from anything you paste.

Check it's fixed

  • The curl comparison returns the same status code and byte count on the custom domain as on the default address, and curl -sIL --max-redirs 5 https://example.com/ ends in a 200 rather than a loop.
  • openssl s_client with -servername example.com shows a certificate that covers your hostname, and -checkend 1209600 reports that it will not expire within 14 days.
  • dig returns only the records your host specifies: no leftover AAAA, no stale _acme-challenge TXT and no CAA policy that excludes your host's certificate authority.
  • The site loads over HTTPS from a second network, such as a phone on mobile data, and your uptime monitor on the custom domain stays green.

Questions

Why does my vercel.app or netlify.app address work but my own domain does not?

The default address uses the host's own DNS and certificate. Your domain depends on your DNS records, any proxy in front of the host and a certificate issued for your hostname. If the default address works, check the custom hostname's DNS, certificate and proxy configuration before you change any code.


Can I keep Cloudflare's proxy in front of my host?

Yes, if /.well-known/acme-challenge/* reaches the host on port 80 without caching, redirects or authentication, and the SSL/TLS mode is Full or Full (strict) when the origin forces HTTPS. Vercel's guidance is to set records that point at Vercel to DNS only if you do not need the proxy.


How long should I wait after changing DNS?

Changes to A, CNAME and TXT records usually take effect once the old record's TTL runs out. Nameserver changes can take 24 to 48 hours. Lower the TTL before a planned move so you can roll back quickly.


Why does renewing again make things worse?

Let's Encrypt allows 5 authorization failures per hostname per account per hour and 5 certificates for the same set of names every 7 days. Retrying a broken validation uses up those limits, so fix the validation path before you retry.


Do I need a CAA record?

No. A missing CAA record does not block issuance. If you have one, at the hostname or a parent domain, it must allow your host's certificate authority, for example 0 issue "letsencrypt.org".


Sources

← Back to the full report