What nginx -t Actually Validates

nginx -t parses the configuration, loads the certificate and private key, and compares their moduli to confirm they match — so a certificate paired with the wrong key genuinely is caught, which is stricter than many expect.

That's where its scope ends. It doesn't know which domains your certificate covers, doesn't check whether the chain is complete, and certainly doesn't simulate a real connection to see what a user ends up with. It validates that the configuration can load, not what the configuration will produce.

What you see What was actually verified What isn't covered
nginx -t reports successful Valid syntax; certificate and key pair correctly Chain completeness and domain coverage
The certificate file is already new The file on disk was indeed updated Until reload, the old certificate in memory is served
server_name is configured correctly Requests for that domain hit this block Non-matching requests fall to the default server
Certificate and intermediate share one file The contents are all present Wrong order makes Nginx pick the wrong one
Four configurations that look correct while users can still hit errors.

The table lists four situations that look fine alongside what they actually cover. The second row is the most common of them.

Three Mechanisms That Decouple Config From Reality

In all three the configuration is entirely correct and users still get errors:

  1. The certificate lives in memory, not in the file Nginx reads certificates into memory at start or reload and keeps using that copy. Renewal replacing the file changes nothing for the running process — a reload signal is required. This is the most common cause of "the certificate was renewed but it still warns about expiry", and it's hard to spot because the service itself is perfectly healthy.
  2. The TLS handshake happens before Nginx knows the domain The documentation is direct about this: the SSL connection is established before the browser sends an HTTP request, so Nginx doesn't yet know which server name was requested and can only offer the default server's certificate. SNI fixes that by carrying the name in the handshake — but a request matching no server_name still lands on the default server and receives that block's certificate.
  3. Nginx treats only the first certificate in the file as the server certificate The file named by ssl_certificate may hold several certificates, but the server certificate must come first, followed by intermediates. The documentation requires that order explicitly. Concatenate them the other way round and Nginx tries to pair the intermediate with your private key, then fails to start with a key values mismatch — an error pointing at the key when the real problem is ordering.

Why the Default Server Bites

On a given listening address, if no server block is marked default_server, the first block automatically becomes the default. So the order of blocks in your configuration directly decides whose certificate users see when nothing matches.

The resulting symptom misleads easily: a domain configured perfectly well, and users receiving a warning that the certificate belongs to some other domain. Typical causes are a newly added domain whose DNS already points here while server_name isn't right yet, or someone connecting by IP address — both land on the default server.

Also note SNI isn't universal. TLS 1.3 makes it mandatory to implement and modern browsers all send it, but some older clients — and anything connecting by IP address — do not. For those, the default server's certificate is the only thing they will ever receive.

Confirming What Users Actually Receive

The principle is the same throughout: don't read the config, look at what the server sends. openssl s_client -connect domain:443 -servername domain performs a real handshake and prints the certificate, and the -servername flag is what sends SNI. Don't omit it — without it you're testing what a client with no SNI receives, which is the default server's certificate.

To verify a reload took effect, compare the certificate's notBefore date. If what's served still carries the old start date, the process hasn't reloaded. That's more reliable than checking file modification times, since the file was updated long before.

Three Levels of Configuration Check

In ascending order of reliability:

1. Treat nginx -t as the first gate only

It catches syntax errors and mismatched key pairs, and is worth running after every change. But passing means the configuration can load, not that it's correct. Necessary, not sufficient. Worth clearing out alongside it is configuration that no longer does anything — OCSP stapling being the common case.

2. Always reload after changing certificates, then confirm

nginx -s reload or the equivalent service command. What matters is connecting afterwards to confirm — a reload can fail on a configuration error while the old process keeps serving quite happily, showing nothing unusual from outside.

3. Declare default_server and audit coverage

List every domain that resolves to this machine, confirm each has a matching server_name, and designate a dedicated default_server for the rest. Uncovered domains don't disappear — they quietly receive someone else's certificate.

Three Things to Establish While Diagnosing

When a certificate problem is reported, these narrow it down fast:

  1. Whether it's simply a missing reload Compare the served certificate's notBefore against the file's. A mismatch means it hasn't loaded, which accounts for the overwhelming majority of "renewed but not in effect".
  2. Whether the requested domain has a matching block If the error says the certificate belongs to another domain, check server_name coverage before suspecting the certificate. That "someone else's certificate" is usually the default server's.
  3. The order of certificates in the file If Nginx fails to start with a key values mismatch, check ordering before suspecting the key — the server certificate must come first. That error message sends people looking in the wrong place.

In Summary

nginx -t passing is necessary, not sufficient. It validates whether the configuration loads, while certificates living in memory, a handshake that precedes knowing the domain, and file order deciding which certificate is the server's all happen outside what it examines.

None of these mechanisms is wrong in itself; the trouble is the false confidence a correct-looking config creates. If you'd rather not verify each of these on every deployment, our SSL automation platform pushes complete chains to each node on issuance, removing the manual config editing step.

Sources