<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Romail Shah</title>
    <description>The latest articles on DEV Community by Romail Shah (@romailshah).</description>
    <link>https://dev.to/romailshah</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4203113%2F9f2d6985-8027-4d22-9146-1f60fd6c2fec.png</url>
      <title>DEV Community: Romail Shah</title>
      <link>https://dev.to/romailshah</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/romailshah"/>
    <language>en</language>
    <item>
      <title>DNS propagation: how long it really takes</title>
      <dc:creator>Romail Shah</dc:creator>
      <pubDate>Wed, 28 Oct 2026 00:04:16 +0000</pubDate>
      <link>https://dev.to/romailshah/dns-propagation-how-long-it-really-takes-4nal</link>
      <guid>https://dev.to/romailshah/dns-propagation-how-long-it-really-takes-4nal</guid>
      <description>&lt;p&gt;DNS propagation is the delay between changing a DNS record and everyone being able to see the change. The name's a bit misleading, because nothing actually propagates.&lt;/p&gt;

&lt;p&gt;Most people want the short answer, so here it is. If you lowered the TTL on the record to 60 seconds a day beforehand, the change reaches most people within a minute or two. If the record was sitting on a default TTL of 3600, expect roughly an hour. The 24 to 48 hours your hosting company quotes is a safety margin to cover the slowest cache in the chain. You aren't waiting in some queue.&lt;/p&gt;

&lt;p&gt;The longer answer is worth reading, though, because it tells you which part of that delay you can control and which part you can't.&lt;/p&gt;

&lt;h2&gt;
  
  
  What DNS propagation actually is
&lt;/h2&gt;

&lt;p&gt;There's no central registry pushing your A record out to the world's resolvers, and no batch job at 4am updating the internet's address book. DNS is pull based. Nothing gets sent anywhere.&lt;/p&gt;

&lt;p&gt;Someone finds out about your record change because something on their end asks for it: their browser, their operating system, or their ISP's resolver. When that question gets asked depends on whether anything along the way still holds a cached answer, and how long it was told to keep it.&lt;/p&gt;

&lt;p&gt;That instruction is the TTL, a number of seconds attached to the record by whoever runs the DNS zone. A resolver that fetched your record with a TTL of 3600 will keep handing out the old answer for up to an hour, whatever you've changed since, and however badly you need it gone.&lt;/p&gt;

&lt;p&gt;So what people call propagation is thousands of separate caches spread across resolvers and devices, each expiring at a slightly different moment depending on when it first cached the record and what TTL it was given. There's never a clean cutover. Two visitors arriving five minutes after your change can land on two different servers, and both of their setups are behaving exactly as designed.&lt;/p&gt;

&lt;h2&gt;
  
  
  How long does DNS propagation take?
&lt;/h2&gt;

&lt;p&gt;That comes down almost entirely to the TTL that was on the record &lt;em&gt;before&lt;/em&gt; you changed it. The one you set afterwards barely matters. By the time you make the change, every cache already holding your record is counting down on the old value.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;TTL before the change&lt;/th&gt;
&lt;th&gt;Most visitors see the new record within&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;60 seconds&lt;/td&gt;
&lt;td&gt;1 to 2 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;300 seconds&lt;/td&gt;
&lt;td&gt;About 5 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3600 seconds (common default)&lt;/td&gt;
&lt;td&gt;About 1 hour&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;14400 seconds&lt;/td&gt;
&lt;td&gt;About 4 hours&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;86400 seconds (old default)&lt;/td&gt;
&lt;td&gt;Up to 24 hours&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Those figures cover most of your traffic, though there's always a tail: a corporate resolver with a hard minimum TTL, an ISP that caps everything at four hours, a phone that hasn't switched networks in a week. That tail is why the 24 to 48 hour advice sticks around, even though it has nothing to do with how DNS actually works.&lt;/p&gt;

&lt;p&gt;In practice, the most important step happens a day before the migration. Lower the TTL to 60 seconds at least 24 hours ahead, and every cache upstream spends that day refreshing on a short clock. Then when you flip the record, they come back for the new answer within about a minute.&lt;/p&gt;

&lt;p&gt;Miss that step and you're stuck with whatever the old TTL was, and there's no way to shorten it after the fact.&lt;/p&gt;

&lt;h2&gt;
  
  
  How DNS actually resolves a domain
&lt;/h2&gt;

&lt;p&gt;A single lookup passes through a chain of stops, and there's a cache at each one.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Browser DNS cache.&lt;/strong&gt; Chrome's lasts roughly a minute by default. Firefox respects published TTLs more closely. Native mobile apps often keep their own caches that bypass the operating system altogether.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;OS DNS cache.&lt;/strong&gt; macOS uses &lt;code&gt;mDNSResponder&lt;/code&gt;, modern Linux usually uses &lt;code&gt;systemd-resolved&lt;/code&gt;, and Windows uses the DNS Client service. These respect the TTL on the answers they get, though some enforce a minimum.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Local network resolver.&lt;/strong&gt; This is usually whatever your network handed you: your home router, your office gateway or your ISP. It has its own cache and doesn't always respect the published TTL. Some ISPs cap TTLs at four hours regardless of what the record says, and corporate networks running BIND, Unbound, pfSense or Pi-hole all make their own decisions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Recursive resolution up the tree.&lt;/strong&gt; With nothing cached, the resolver works its way up: root server, then the TLD server for &lt;code&gt;.com&lt;/code&gt; or &lt;code&gt;.io&lt;/code&gt;, then your authoritative nameserver, and back down. That walk takes milliseconds, and the answer gets cached for whatever TTL it came with.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;DoH and DoT resolvers.&lt;/strong&gt; Browsers using DNS over HTTPS skip your local resolver completely. Firefox uses Cloudflare by default, and Chrome on Android often uses Google. These run their own caches, shared across millions of devices.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So the 24 to 48 hour figure is really just how long the slowest link in that chain takes to let go of its copy. That's usually a third party resolver capping TTL at a day, or a corporate resolver set up years ago by someone who's since left.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the 24 to 48 hour number stuck
&lt;/h2&gt;

&lt;p&gt;The number's an oversimplification more than an outright error, and there are a few reasons it's survived this long.&lt;/p&gt;

&lt;p&gt;Old TTL defaults are the main one. Back in the 1990s and early 2000s, common TTLs were 86400 or 172800 seconds, and anyone who learned DNS then took those numbers as the window. Actively managed records now usually sit between 60 and 3600, but the advice never caught up.&lt;/p&gt;

&lt;p&gt;Some ISPs also used to flush their caches in a daily batch. Change your record just before one and it felt instant. Change it just after and it felt like a full day. From the outside, the delay looked completely random.&lt;/p&gt;

&lt;p&gt;It also closes support tickets. If a customer changes DNS and complains straight away, the cheapest answer is to tell them to wait 24 to 48 hours. By then the problem has usually fixed itself or stopped mattering, and as support economics go, that's hard to beat.&lt;/p&gt;

&lt;p&gt;And the long tail is real. Even with sensible TTLs, there's always one cache somewhere that won't update for a day, and the polite fiction covers that without anyone having to explain it.&lt;/p&gt;

&lt;p&gt;So it's a load bearing approximation. The trouble starts when you take it literally and plan your migration around waiting it out.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually controls when your change is visible
&lt;/h2&gt;

&lt;p&gt;There are five layers, ordered from the one you control to the ones you really don't.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layer 1: TTL on your record (you control this)
&lt;/h3&gt;

&lt;p&gt;This is the only dial you can actually turn. Set it to 60 seconds at least 24 hours before the change, flip the record, then raise it back to 3600 or higher once the new server has been stable for a couple of days. Leaving it on 60 forever just adds unnecessary query load and latency.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layer 2: Your authoritative nameservers (mostly out of your control)
&lt;/h3&gt;

&lt;p&gt;Your DNS provider might not push changes across its own servers instantly. Cloudflare and Route 53 are effectively immediate, but some smaller registrars take one to five minutes for a change made in the admin panel to show up on all their nameservers. Give it two minutes, then check with &lt;code&gt;dig +trace example.com&lt;/code&gt; before you go looking for a bigger problem.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layer 3: ISP and public resolver caches (out of your control)
&lt;/h3&gt;

&lt;p&gt;The big public resolvers, Cloudflare on 1.1.1.1, Google on 8.8.8.8 and Quad9 on 9.9.9.9, respect TTLs well. ISP resolvers are more of a mixed bag. Some respect the published value, some cap it, and some have quirks you'll only find written up in an old forum thread. Corporate resolvers do whatever their IT team set up, which often isn't what the record asked for.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layer 4: Browser DNS caches (out of your control)
&lt;/h3&gt;

&lt;p&gt;Chrome's lasts about a minute, Safari's is similar, and Firefox respects TTLs more closely. It's a small layer but the most noticeable one: "it works on my phone but not in this tab" is nearly always a stale browser cache. Clearing it at &lt;code&gt;chrome://net-internals/#dns&lt;/code&gt; fixes it for that person, in that browser, one time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layer 5: DNS over HTTPS providers (out of your control)
&lt;/h3&gt;

&lt;p&gt;A browser using DoH goes around both the ISP resolver and the corporate one, talking straight to a third party. That's why asking a client's IT team to flush their cache sometimes changes nothing at all. They control the corporate resolver, but the browser is talking to Cloudflare, and nobody at the company knows.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to check DNS propagation
&lt;/h2&gt;

&lt;p&gt;Don't test by loading the site in your browser. That adds two more caches, your browser's and your operating system's, on top of the resolver you're actually trying to look at. Query resolvers directly instead.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Ask two large public resolvers what they currently hold&lt;/span&gt;
dig @1.1.1.1 example.com +short
dig @8.8.8.8 example.com +short

&lt;span class="c"&gt;# Watch the full walk from the root servers down&lt;/span&gt;
dig +trace example.com

&lt;span class="c"&gt;# Ask your authoritative nameserver directly, bypassing every cache&lt;/span&gt;
dig @ns1.yourprovider.com example.com +short
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're on Windows without &lt;code&gt;dig&lt;/code&gt;, &lt;code&gt;nslookup example.com 1.1.1.1&lt;/code&gt; will get you most of the way.&lt;/p&gt;

&lt;p&gt;That last command is the one that matters most during a migration. Your authoritative nameserver is the source of truth, so if it returns the new IP, your change is live and everything after that is just caching. For a worldwide picture, &lt;a href="https://www.whatsmydns.net" rel="noopener noreferrer"&gt;whatsmydns.net&lt;/a&gt; queries 20 to 50 resolvers at once.&lt;/p&gt;

&lt;p&gt;Expect them to disagree for a while. Mixed results are completely normal partway through a TTL window.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can you speed up DNS propagation?
&lt;/h2&gt;

&lt;p&gt;Once the change is made, no, and no tool can either. You can't reach into someone else's resolver and expire their cache. Anything promising to force global propagation is really just a checker with a refresh button.&lt;/p&gt;

&lt;p&gt;What does work is preparation. Lowering the TTL 24 hours ahead is really the whole game, and it's the difference between a one minute cutover and an all day one.&lt;/p&gt;

&lt;p&gt;The only caches you can actually flush are your own:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Windows:&lt;/strong&gt; &lt;code&gt;ipconfig /flushdns&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;macOS:&lt;/strong&gt; &lt;code&gt;sudo dscacheutil -flushcache&lt;/code&gt; then &lt;code&gt;sudo killall -HUP mDNSResponder&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Linux (systemd):&lt;/strong&gt; &lt;code&gt;sudo resolvectl flush-caches&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chrome:&lt;/strong&gt; visit &lt;code&gt;chrome://net-internals/#dns&lt;/code&gt; and clear the host cache&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's useful for checking your own work, and no help at all for the client whose office resolver is the actual problem. The full set of commands, including Firefox, iPhone and Android, is in &lt;a href="https://dnspreviewer.com/blog/how-to-flush-dns" rel="noopener noreferrer"&gt;how to flush DNS&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to do instead of waiting
&lt;/h2&gt;

&lt;p&gt;Once you accept that the delay is just caches expiring, your migration process changes. You stop waiting, and you test the new server while DNS still points at the old one.&lt;/p&gt;

&lt;p&gt;I should be upfront about a conflict of interest here: I built a free tool for this. &lt;a href="https://dnspreviewer.com" rel="noopener noreferrer"&gt;DNS Previewer&lt;/a&gt; creates a temporary subdomain that proxies your new server using the correct Host header and TLS SNI for your real domain, so the server responds exactly as it will after the change. You can open it on any device before touching a record. &lt;a href="https://skipdns.link" rel="noopener noreferrer"&gt;SkipDNS&lt;/a&gt; is the established paid tool that does the same job, and I keep an &lt;a href="https://dnspreviewer.com/vs-skipdns" rel="noopener noreferrer"&gt;honest comparison of the two&lt;/a&gt;, including the parts where theirs is better. Editing your hosts file works too, with &lt;a href="https://dnspreviewer.com/blog/preview-website-new-server-without-hosts-file" rel="noopener noreferrer"&gt;limitations worth knowing&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here's the process itself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lower the TTL to 60 seconds at least 24 hours before the migration. It's the most important thing you control, and the only one you can't fix later.&lt;/li&gt;
&lt;li&gt;Test the new server under your real domain before changing any records, so vhost and certificate problems turn up before your visitors find them. Certificates are the awkward one here, because most authorities want the hostname pointing at the new machine before they will issue one, which is the &lt;a href="https://dnspreviewer.com/blog/err-ssl-protocol-error" rel="noopener noreferrer"&gt;deadlock behind ERR_SSL_PROTOCOL_ERROR&lt;/a&gt; on a fresh server.&lt;/li&gt;
&lt;li&gt;Flip the record once the new server responds correctly. The cutover itself should feel boring.&lt;/li&gt;
&lt;li&gt;Don't rely on a single checker. Test from the client's actual network too, since that's where stale cache problems tend to hide.&lt;/li&gt;
&lt;li&gt;Raise the TTL back to 3600 or higher after 48 stable hours.&lt;/li&gt;
&lt;li&gt;Write down the old IP and test your rollback before you need it at 4am.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Waiting to see what happens is how you end up with the 3am phone call. Testing before you flip catches the same problems without any of your visitors being involved.&lt;/p&gt;

&lt;h2&gt;
  
  
  The short version
&lt;/h2&gt;

&lt;p&gt;There's no single process running somewhere that you can check the status of. DNS propagation is the sum of every cache between your record and your visitor, each expiring on its own clock, with TTL as the only input you control.&lt;/p&gt;

&lt;p&gt;Set a low TTL a day in advance, check the new server before you change anything, query resolvers directly instead of reloading a browser tab, and accept that the long tail of stale caches is nobody's fault. That's simply how the protocol was designed to work.&lt;/p&gt;

&lt;p&gt;Once you understand what's actually going on, you stop waiting for it.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://dnspreviewer.com/blog/dns-propagation-time-what-actually-happens" rel="noopener noreferrer"&gt;DNS Previewer blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>dns</category>
      <category>devops</category>
      <category>webdev</category>
      <category>sysadmin</category>
    </item>
    <item>
      <title>ERR_SSL_PROTOCOL_ERROR: what it means and how to fix it</title>
      <dc:creator>Romail Shah</dc:creator>
      <pubDate>Wed, 28 Oct 2026 00:03:08 +0000</pubDate>
      <link>https://dev.to/romailshah/errsslprotocolerror-what-it-means-and-how-to-fix-it-24i3</link>
      <guid>https://dev.to/romailshah/errsslprotocolerror-what-it-means-and-how-to-fix-it-24i3</guid>
      <description>&lt;p&gt;You typed an address, the page never appeared, and Chrome replaced it with "This site can't provide a secure connection" and the line &lt;code&gt;ERR_SSL_PROTOCOL_ERROR&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Nothing loaded because nothing was ever sent. HTTPS starts with a handshake: your browser and the server agree which version of TLS they'll speak, pick a cipher, and the server proves its identity with a certificate. Only after all that does a single byte of the page move. This error means the handshake fell over.&lt;/p&gt;

&lt;p&gt;There's a quick way to tell whose problem it is. Open two or three other HTTPS sites. If they load, the fault is with the site you're trying to reach, and no setting on your computer will fix it. If they all fail the same way, it's your side, and the section below will sort it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the error actually says
&lt;/h2&gt;

&lt;p&gt;Chrome keeps a list of network error codes, and this one is &lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:net/base/net_error_list.h" rel="noopener noreferrer"&gt;defined as&lt;/a&gt; "An SSL protocol error occurred", numbered -107. On screen it comes out as the site name followed by "sent an invalid response."&lt;/p&gt;

&lt;p&gt;There's a close relative worth knowing, because the fix is different. &lt;a href="https://dnspreviewer.com/blog/err-ssl-version-or-cipher-mismatch" rel="noopener noreferrer"&gt;&lt;code&gt;ERR_SSL_VERSION_OR_CIPHER_MISMATCH&lt;/code&gt;&lt;/a&gt; is defined as "The client and server don't support a common SSL protocol version or cipher suite", and its page says the site "uses an unsupported protocol." That one is nearly always an old server offering only old TLS. If that's what you're seeing, skip to cause 2.&lt;/p&gt;

&lt;p&gt;Other browsers describe the same failure in their own words. Safari says it can't establish a secure connection, Firefox talks about a secure connection failing. It's the same handshake, failing the same way.&lt;/p&gt;

&lt;h2&gt;
  
  
  If you're the visitor
&lt;/h2&gt;

&lt;p&gt;Four things are worth doing, roughly in this order.&lt;/p&gt;

&lt;p&gt;Check your clock. Certificates are only valid between two dates, so a machine with the wrong date rejects good certificates. Chrome says this itself on its error pages: to establish a secure connection, your clock needs to be set correctly. Turn on automatic time in your system settings, especially on a computer that's been switched off for months.&lt;/p&gt;

&lt;p&gt;Turn off HTTPS scanning in your antivirus for a moment. Security suites often inspect encrypted traffic by sitting in the middle of it, and when that goes wrong it breaks handshakes exactly like this. Look for a setting called HTTPS scanning, SSL scanning or encrypted connection scanning. If the site loads with it off, you've found your culprit and the vendor's support is the next stop.&lt;/p&gt;

&lt;p&gt;Try a different network. Work wifi, a VPN or a captive portal in a hotel can all intercept traffic. Loading the site on your phone over mobile data takes thirty seconds and tells you whether the network is at fault.&lt;/p&gt;

&lt;p&gt;Try another browser. If Chrome fails and Firefox works, the problem is local to Chrome's setup, and a new profile or a reset usually clears it.&lt;/p&gt;

&lt;p&gt;One thing you cannot do is click through. A certificate warning offers an Advanced link because the connection worked and only the identity is questionable. Here there's no connection to continue into. Some sites will still load if you type &lt;code&gt;http://&lt;/code&gt; in front, which proves the server is alive and its HTTPS is broken, but don't log in or type anything private into a page loaded that way.&lt;/p&gt;

&lt;h2&gt;
  
  
  If the site is yours
&lt;/h2&gt;

&lt;p&gt;Everything below happens on the server, and in my experience it's nearly always one of five things.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cause 1: no certificate for that hostname yet
&lt;/h3&gt;

&lt;p&gt;This is the one that catches migrations. Certificates don't travel with your files. Copy a site to a new server and that machine has no certificate for your domain, so it either serves nothing on 443 or falls back to a default certificate for its own hostname.&lt;/p&gt;

&lt;p&gt;The same thing happens on a server hosting several sites. Because one IP address can hold many sites, the browser has to say which hostname it wants during the handshake, using SNI. If the server has no certificate matching that name, the handshake fails. nginx's documentation is blunt about the limits here: for maximum interoperability with clients that don't use SNI, virtual servers with different certificates should listen on different IP addresses.&lt;/p&gt;

&lt;p&gt;Check what the server actually presents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;openssl s_client &lt;span class="nt"&gt;-connect&lt;/span&gt; example.com:443 &lt;span class="nt"&gt;-servername&lt;/span&gt; example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;-servername&lt;/code&gt; option &lt;a href="https://docs.openssl.org/master/man1/openssl-s_client/" rel="noopener noreferrer"&gt;sets the SNI value&lt;/a&gt; in the request, which is how you test one specific site on a shared IP. Look at the subject and issuer that come back. If they name a different host, or you get no certificate at all, that's your answer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cause 2: the server only speaks old TLS
&lt;/h3&gt;

&lt;p&gt;TLS 1.0 and 1.1 are no longer acceptable. &lt;a href="https://www.rfc-editor.org/rfc/rfc8996.html" rel="noopener noreferrer"&gt;RFC 8996&lt;/a&gt;, published in March 2021, is unambiguous: "TLS 1.0 MUST NOT be used" and "TLS 1.1 MUST NOT be used". Browsers followed, so a server still offering only those versions now fails the handshake, usually with the mismatch error rather than this one.&lt;/p&gt;

&lt;p&gt;Both major web servers already default to something sane. nginx's &lt;a href="https://nginx.org/en/docs/http/ngx_http_ssl_module.html" rel="noopener noreferrer"&gt;&lt;code&gt;ssl_protocols&lt;/code&gt;&lt;/a&gt; defaults to &lt;code&gt;TLSv1.2 TLSv1.3&lt;/code&gt;, and Apache's &lt;a href="https://httpd.apache.org/docs/2.4/mod/mod_ssl.html" rel="noopener noreferrer"&gt;&lt;code&gt;SSLProtocol&lt;/code&gt;&lt;/a&gt; defaults to &lt;code&gt;all -SSLv3&lt;/code&gt;. The trouble comes from old config files copied forward from a server built years ago, where someone pinned an explicit list. Find the line and make it current:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;ssl_protocols&lt;/span&gt; &lt;span class="s"&gt;TLSv1.2&lt;/span&gt; &lt;span class="s"&gt;TLSv1.3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can prove which versions a server accepts by asking for one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;openssl s_client &lt;span class="nt"&gt;-connect&lt;/span&gt; example.com:443 &lt;span class="nt"&gt;-tls1_2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If that succeeds and the browser still fails, the version isn't your problem.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cause 3: nothing is serving HTTPS on port 443
&lt;/h3&gt;

&lt;p&gt;Obvious once you see it, invisible until you check. The web server may only be listening on port 80, or a firewall may be blocking 443, or the service crashed and only the HTTP one came back.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-vI&lt;/span&gt; https://example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://dnspreviewer.com/blog/err-connection-refused" rel="noopener noreferrer"&gt;A connection refused&lt;/a&gt; means nothing is listening. A timeout usually means a firewall is swallowing the packets. Getting as far as a TLS error means the port is open and the problem is in the handshake itself, which sends you back to causes 1 and 2.&lt;/p&gt;

&lt;p&gt;There's a stranger version of this: plain HTTP being served on port 443. The browser starts a TLS handshake, receives what looks like an HTTP response instead, and gives up. That happens when a &lt;code&gt;listen 443&lt;/code&gt; block is missing the &lt;code&gt;ssl&lt;/code&gt; flag.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cause 4: Cloudflare set to the wrong SSL mode
&lt;/h3&gt;

&lt;p&gt;If Cloudflare sits in front of your site, its encryption mode has to match what your origin server can actually do. Cloudflare's &lt;a href="https://developers.cloudflare.com/ssl/origin-configuration/ssl-modes/" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; describes Full mode as Cloudflare matching the visitor's protocol when it connects to the origin, using HTTPS without validating the origin's certificate, while Full (strict) adds validation of that certificate.&lt;/p&gt;

&lt;p&gt;So a mode set to Full or Full (strict) against an origin with no working HTTPS produces errors, and Flexible exists for origins that can't do TLS at all. After a migration, the mode that suited the old server often doesn't suit the new one. Check the origin directly, bypassing Cloudflare, before changing the mode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-vI&lt;/span&gt; https://203.0.113.42 &lt;span class="nt"&gt;--resolve&lt;/span&gt; example.com:443:203.0.113.42
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Cause 5: a broken or incomplete certificate chain
&lt;/h3&gt;

&lt;p&gt;Your certificate is usually signed by an intermediate, which is signed by a root the browser trusts. Leave the intermediate out and some clients can't connect the two.&lt;/p&gt;

&lt;p&gt;nginx expects them in one file, in a specific order, and says so plainly: if intermediate certificates should be specified in addition to a primary certificate, they should be specified in the same file, with the primary certificate first. Get the order wrong, or paste only the leaf, and you'll see failures that come and go depending on what each client already has cached.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;openssl s_client &lt;span class="nt"&gt;-connect&lt;/span&gt; example.com:443 &lt;span class="nt"&gt;-servername&lt;/span&gt; example.com &lt;span class="nt"&gt;-showcerts&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That prints the full list the server sends, which is exactly what you need to compare against what your certificate authority gave you.&lt;/p&gt;

&lt;h2&gt;
  
  
  When it started right after a move
&lt;/h2&gt;

&lt;p&gt;Then it's almost certainly cause 1, and the timing is the giveaway.&lt;/p&gt;

&lt;p&gt;The certificate on the old server covers your domain. The new server has nothing, and it usually can't get anything, because most certificate authorities want to see the hostname pointing at the machine before they'll issue one. So you're stuck between two steps: DNS can't move until the site works, and the certificate can't be issued until DNS moves.&lt;/p&gt;

&lt;p&gt;There are two honest ways out. Use a DNS-based validation challenge, which proves you own the domain without pointing traffic anywhere, so the certificate can be issued before the move. Or check the site over a preview link while the certificate question is still open.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dnspreviewer.com/" rel="noopener noreferrer"&gt;DNS Previewer&lt;/a&gt; is the second one. It loads your site from the new server under its real domain name, and you can tell it to connect to your server over HTTP, HTTPS, or to fall back automatically, which is what you want while the new machine has no valid certificate yet. So you can confirm the site itself works, sort the certificate out, then change DNS. The &lt;a href="https://dnspreviewer.com/blog/wordpress-migration-checklist-test-before-dns" rel="noopener noreferrer"&gt;WordPress migration checklist&lt;/a&gt; has the rest of the pre-flight list, and checking the certificate covers the real domain is item one on it for this exact reason.&lt;/p&gt;

&lt;p&gt;Two related errors turn up in the same week as this one. A &lt;a href="https://dnspreviewer.com/blog/502-bad-gateway" rel="noopener noreferrer"&gt;502 Bad Gateway&lt;/a&gt; means the handshake worked and the thing behind your web server didn't answer. An &lt;a href="https://dnspreviewer.com/blog/error-establishing-a-database-connection" rel="noopener noreferrer"&gt;error establishing a database connection&lt;/a&gt; means the site is serving fine and the database details are stale. Different layers, different fixes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The order I'd work through it
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Does any other HTTPS site load? If yes, stop looking at your computer.&lt;/li&gt;
&lt;li&gt;If nothing loads: clock, antivirus HTTPS scanning, then a different network.&lt;/li&gt;
&lt;li&gt;If the site is yours, run &lt;code&gt;openssl s_client -connect yourdomain.com:443 -servername yourdomain.com&lt;/code&gt; and read the certificate it returns.&lt;/li&gt;
&lt;li&gt;Wrong name on the certificate, or no certificate: issue one that covers the hostname.&lt;/li&gt;
&lt;li&gt;Nothing listening at all: check the web server is up, &lt;code&gt;listen 443 ssl&lt;/code&gt; is present, and the firewall allows it.&lt;/li&gt;
&lt;li&gt;Mismatch error rather than this one: raise the TLS versions to 1.2 and 1.3.&lt;/li&gt;
&lt;li&gt;Cloudflare in front: compare its SSL mode against what the origin can really do.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Most of the time it's a certificate that doesn't cover the name being asked for, and it takes longer to read the error than to fix it.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://dnspreviewer.com/blog/err-ssl-protocol-error" rel="noopener noreferrer"&gt;DNS Previewer blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ssl</category>
      <category>webdev</category>
      <category>nginx</category>
      <category>devops</category>
    </item>
    <item>
      <title>How to preview a site on a new server without editing the hosts file</title>
      <dc:creator>Romail Shah</dc:creator>
      <pubDate>Fri, 23 Oct 2026 23:50:16 +0000</pubDate>
      <link>https://dev.to/romailshah/how-to-preview-a-site-on-a-new-server-without-editing-the-hosts-file-4nlj</link>
      <guid>https://dev.to/romailshah/how-to-preview-a-site-on-a-new-server-without-editing-the-hosts-file-4nlj</guid>
      <description>&lt;p&gt;Every migration ends up in the same spot. The files are on the new server, the database is imported, and now you've got to work out whether it actually works before you point DNS at it and find out in public.&lt;/p&gt;

&lt;p&gt;The usual answer is to edit your hosts file. It's a good answer. It's also older than DNS itself, and it has limits that are easy to forget until they bite.&lt;/p&gt;

&lt;h2&gt;
  
  
  What editing the hosts file actually does
&lt;/h2&gt;

&lt;p&gt;Before your computer asks a DNS server where &lt;code&gt;example.com&lt;/code&gt; lives, it checks a plain text file on disk. If that file has a line for the hostname, the lookup stops right there and nothing goes out over the network.&lt;/p&gt;

&lt;p&gt;You'll find it here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Windows:&lt;/strong&gt; &lt;code&gt;C:\Windows\System32\drivers\etc\hosts&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;macOS and Linux:&lt;/strong&gt; &lt;code&gt;/etc/hosts&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both are protected system files. On Windows you need to run your editor as administrator, and on macOS or Linux you need &lt;code&gt;sudo&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It's one mapping per line, with the IP address first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;203.0.113.42    example.com
203.0.113.42    www.example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The reason this trick works at all comes down to what your browser sends. It still sends &lt;code&gt;Host: example.com&lt;/code&gt; in the request, and the TLS handshake still carries &lt;code&gt;example.com&lt;/code&gt; as the SNI value. So the new server sees the real domain name, picks the right virtual host and serves the right certificate, exactly as it would after a real DNS change.&lt;/p&gt;

&lt;p&gt;That's why editing the hosts file beats typing the server's IP address into the address bar. If you visit &lt;code&gt;http://203.0.113.42&lt;/code&gt; directly, the browser sends &lt;code&gt;Host: 203.0.113.42&lt;/code&gt;, and the server has no idea which site you're after. You get the default virtual host, which is usually an Apache welcome page, a 404, or someone else's website on the same box. People see that and assume the migration failed. It didn't. They just asked the wrong question.&lt;/p&gt;

&lt;p&gt;So the hosts file gets the technical part right. Its problems are all practical ones.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the hosts file runs out of road
&lt;/h2&gt;

&lt;h3&gt;
  
  
  It only works on the machine you edited
&lt;/h3&gt;

&lt;p&gt;This is the biggest problem by far. A hosts entry is local. Your client can't see what you see, your colleague can't either, and there's no way to email it to anyone.&lt;/p&gt;

&lt;p&gt;To bring even one other person along, you'd have to walk them through opening a protected system file with administrator rights on their own computer. On a managed work laptop that's often blocked by policy, so no amount of patience on the call is going to get you there.&lt;/p&gt;

&lt;h3&gt;
  
  
  There are no wildcards
&lt;/h3&gt;

&lt;p&gt;The hosts file matches exact hostnames, and there's no syntax for &lt;code&gt;*.example.com&lt;/code&gt;. If you're migrating a WordPress multisite, or anything with &lt;code&gt;blog.&lt;/code&gt;, &lt;code&gt;shop.&lt;/code&gt;, &lt;code&gt;app.&lt;/code&gt; and a few others, you need a line for every single one, and you need the full list before you start.&lt;/p&gt;

&lt;p&gt;Miss one and you get a confusing, half-broken result, where some of the site comes from the new server and some quietly comes from the old one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Phones and tablets are out
&lt;/h3&gt;

&lt;p&gt;There's no supported way to edit the hosts file on a stock iPhone or Android device. Unless you root or jailbreak it, you simply can't test on mobile this way.&lt;/p&gt;

&lt;p&gt;That hurts more than it sounds, because mobile is where layouts break, where buttons end up too close together, and where a slow new server is most obvious.&lt;/p&gt;

&lt;h3&gt;
  
  
  Firefox may ignore it completely
&lt;/h3&gt;

&lt;p&gt;Firefox enables DNS over HTTPS, which looks names up inside the browser over an encrypted connection to a DNS provider. When that's on, the lookup never reaches your operating system, so your hosts file gets skipped entirely. Your entry can be correct and saved and still be completely ignored.&lt;/p&gt;

&lt;p&gt;Mozilla has been tracking support for local address overrides under DoH in &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1453207" rel="noopener noreferrer"&gt;bug 1453207&lt;/a&gt; for years. Chrome behaves differently here and generally still honours the file, because it checks the system resolver for local entries. That's why the same test can pass in one browser and fail in another on the same machine.&lt;/p&gt;

&lt;p&gt;If you're relying on the hosts file, check whether DoH is switched on before you draw any conclusions about the server.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caches will lie to you for a while
&lt;/h3&gt;

&lt;p&gt;Editing the file doesn't clear what your system already remembers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Windows:&lt;/strong&gt; &lt;code&gt;ipconfig /flushdns&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;macOS:&lt;/strong&gt; &lt;code&gt;sudo dscacheutil -flushcache&lt;/code&gt; then &lt;code&gt;sudo killall -HUP mDNSResponder&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chrome, separately:&lt;/strong&gt; visit &lt;code&gt;chrome://net-internals/#dns&lt;/code&gt; and clear the host cache&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Skip this and you can easily lose twenty minutes debugging a server that was fine all along. The commands for Linux, Firefox and phones are in &lt;a href="https://dnspreviewer.com/blog/how-to-flush-dns" rel="noopener noreferrer"&gt;how to flush DNS&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  You have to remember to take it out
&lt;/h3&gt;

&lt;p&gt;A forgotten hosts entry makes for a really nasty bug. You finish the migration, DNS changes properly, everyone moves on, and your own machine keeps pointing at the old IP because the line never got removed.&lt;/p&gt;

&lt;p&gt;Weeks later the site looks frozen or broken, but only for you, and nobody else can reproduce it. It's the kind of problem that can swallow a whole afternoon before anyone thinks to check.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to preview a site on a new server without touching the hosts file
&lt;/h2&gt;

&lt;p&gt;The alternative is to take the same trick off your machine and put it behind a URL.&lt;/p&gt;

&lt;p&gt;A preview link works as a reverse proxy. You give it your domain and the new server's IP address, and it hands you back a link on a subdomain, something like &lt;code&gt;x7k3p.dnspreviewer.com&lt;/code&gt;. When you open that link, the proxy connects to your new server and sends &lt;code&gt;Host: example.com&lt;/code&gt; along with it, plus the matching SNI on the TLS connection.&lt;/p&gt;

&lt;p&gt;So the new server sees the same request it would after a real DNS change. You get the right virtual host and the right certificate behaviour, which is the whole point of the hosts file trick, only now it's a link.&lt;/p&gt;

&lt;p&gt;That one change fixes most of the list above in one go. You can send a link to a client. It works on a phone without any setup. It doesn't need administrator rights, it doesn't matter whether someone's using Firefox with DoH, and there's nothing left behind on anyone's machine to forget about.&lt;/p&gt;

&lt;p&gt;Wildcards stop being a problem too, because the proxy can cover a whole domain and all its subdomains, so you're not listing them out by hand.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dnspreviewer.com/" rel="noopener noreferrer"&gt;DNS Previewer&lt;/a&gt; does this for free, wildcards included. You can also choose whether the connection to your server uses HTTPS, HTTP or falls back automatically, which helps when the new server doesn't have a valid certificate for the domain yet. With a free account you can also put a password on a link, so it isn't open to anyone who gets hold of the URL, and create links that never expire. That HTTP fallback matters more than it sounds, because a new server without a certificate for your domain yet will otherwise greet you with &lt;a href="https://dnspreviewer.com/blog/err-ssl-protocol-error" rel="noopener noreferrer"&gt;ERR_SSL_PROTOCOL_ERROR&lt;/a&gt;. If you've come across SkipDNS, the paid tool that does the same job, here's &lt;a href="https://dnspreviewer.com/vs-skipdns" rel="noopener noreferrer"&gt;how DNS Previewer compares with SkipDNS&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The honest limitations
&lt;/h3&gt;

&lt;p&gt;A preview link is a proxy, so your traffic passes through a third party. If you work under rules that forbid that, or you're testing something involving genuinely sensitive data, the hosts file keeps everything on your own machine, and that's a real advantage.&lt;/p&gt;

&lt;p&gt;One more thing, and it applies to both approaches equally. If your domain normally sits behind a CDN like Cloudflare, pointing either a hosts entry or a preview link at your origin server only tests the origin. The edge isn't involved, so page rules, caching behaviour and edge redirects aren't being tested. Plan a separate check for those once you've cut over. The &lt;a href="https://dnspreviewer.com/blog/wordpress-migration-checklist-test-before-dns" rel="noopener noreferrer"&gt;WordPress migration checklist&lt;/a&gt; covers the CDN and everything else worth checking around the switch.&lt;/p&gt;

&lt;h2&gt;
  
  
  When the hosts file is still the right tool
&lt;/h2&gt;

&lt;p&gt;It hasn't been made obsolete. It's still the right choice when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need a quick check on one machine, for one hostname, and nobody else needs to see it&lt;/li&gt;
&lt;li&gt;You're working somewhere that won't allow traffic through an outside service&lt;/li&gt;
&lt;li&gt;You need to test something that isn't plain HTTP, like a mail server or a service on an unusual port, where a web proxy can't help&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For everything else, and especially anything a client has to sign off on, the real sticking point is who can see it. The hosts file can't leave your laptop, and a migration is rarely something you approve on your own.&lt;/p&gt;

&lt;h2&gt;
  
  
  The short version
&lt;/h2&gt;

&lt;p&gt;Editing the hosts file sends the right &lt;code&gt;Host&lt;/code&gt; header and the right SNI, so it genuinely tests the new server under your real domain. That part's correct and always has been.&lt;/p&gt;

&lt;p&gt;What it can't do is travel. One machine, admin rights needed, exact hostnames only, no phones, and Firefox might skip it. If you're the only person who needs to see the new server, it's fine. The moment someone else needs to look, you want a link.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://dnspreviewer.com/blog/preview-website-new-server-without-hosts-file" rel="noopener noreferrer"&gt;DNS Previewer blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>dns</category>
      <category>webdev</category>
      <category>wordpress</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
