Three openssl commands, and one of them tells you the future
The openssl reference pages list a few hundred invocations and almost nobody needs more than a handful. Three cover the situations that come up when you look after other people's sites, and the third one is the one hardly anybody knows, which is a pity because it is the one that prevents a migration from failing in public.
One: what is this server handing out right now
openssl s_client -connect example.com:443 -servername example.com < /dev/null 2>/dev/null \
| openssl x509 -noout -subject -issuer -dates -ext subjectAltName
Four fields, and each answers a question people usually answer by guessing. Who issued it, so you know which automation owns it. When it starts and ends, in UTC. And the alternative names, which are the names browsers actually check; the subject line has been decorative for years.
On openssl 1.1.1, which is still what you meet on older distributions, -ext may not be available. The fallback works everywhere:
... | openssl x509 -noout -text | grep -A1 'Subject Alternative Name'
For a script, skip the parsing entirely. -checkend takes a number of seconds and sets the exit status, so a cron entry becomes one line:
openssl s_client -connect example.com:443 -servername example.com < /dev/null 2>/dev/null \
| openssl x509 -noout -checkend 1728000 || echo "under 20 days"
Twenty days rather than seven, and the reason is arithmetic rather than caution: automation that renews at thirty days remaining means a certificate below twenty has already been failing for a while. The full version of that argument is in renewal is three operations.
Two: do these files actually belong together
You have been sent a certificate, a private key, and possibly a bundle, by a client, a previous agency, or a certificate authority's web interface. Before you install anything, two checks, offline, in five seconds.
Does the key match the certificate:
openssl x509 -noout -modulus -in cert.pem | openssl sha256
openssl rsa -noout -modulus -in key.pem | openssl sha256
Identical output means they are a pair. Different output means they are not, and installing them will produce a server that refuses to start or, worse, one that starts and serves something unexpected. For an elliptic-curve key the modulus does not exist; compare the public keys instead:
openssl x509 -noout -pubkey -in cert.pem | openssl sha256
openssl pkey -pubout -in key.pem | openssl sha256
And does the chain build, using only the files you were given:
openssl verify -untrusted chain.pem cert.pem
cert.pem: OK means the intermediates are complete. Anything else means you are about to deploy a certificate that works in your browser, because your browser has cached that intermediate from somewhere else, and fails for a fresh client. That asymmetry is the single most confusing TLS fault there is, and it is the missing-intermediate case.
Two file-format annoyances, since they will cost you time otherwise. A key that begins -----BEGIN ENCRYPTED PRIVATE KEY----- has a passphrase, and a server that cannot prompt for it will not start; strip it deliberately rather than discovering it at deploy time. And a file from a Windows tool is often PKCS#12, which is binary and will look like garbage in an editor: openssl pkcs12 -info -in bundle.pfx reads it.
Three: what will this server serve after the cutover
Here is the situation. New server, new stack, certificate provisioned. DNS still points at the old host. You want to know that HTTPS will work at the new address before you move the record, because the alternative is finding out afterwards, in public, with the client watching.
The name does not have to resolve to the address for you to ask the question. SNI is just a string in the handshake, so you connect to the new IP and tell it which site you want:
openssl s_client -connect 203.0.113.10:443 -servername example.com < /dev/null 2>/dev/null \
| openssl x509 -noout -subject -dates -ext subjectAltName
If that returns the right certificate for the right names, HTTPS will work the moment the record changes. If it returns somebody else's certificate, or the server's default, the virtual host is not wired up and you have found it while it costs nothing.
The same trick fetches the actual page, which is the other half of the question:
curl -sSI --resolve example.com:443:203.0.113.10 https://example.com/
Add -k only if you want to see the page despite a certificate problem you have already identified, and never as a habit, because it hides exactly the class of fault you are here to find.
This pair of commands turns a migration from an event into a non-event. Test the new origin under its real hostname, confirm the certificate and the page, then lower the TTL, wait, and change the record. Doing it in that order is the difference between a cutover nobody notices and forty minutes of a client refreshing their homepage.
What openssl will not tell you
It reports on a connection made from where you are, at the moment you ran it. A certificate that is valid from your office may fail from a network whose resolver hands out a different address, and a server that answers correctly now may be serving a stale certificate from memory after a renewal that did not reload it.
Neither of those is visible in a single manual check, which is the argument for having the question asked repeatedly, from outside, per hostname, rather than in a terminal when somebody remembers. The check has to be automatic for the same reason the renewal is automatic: the failures are silent and they are dated in advance.