Certificate files cause more confusion than the cryptography ever does. You are handed a zip containing example.com.crt, ca-bundle.crt and perhaps a .p7b; your server asks for a "PEM chain" or a "PFX"; and the extensions mean different things depending on who made the file.
The underlying data is the same in almost every case: a certificate, perhaps some intermediates, and a private key. What differs is the wrapper: text or binary, one item or several, with or without a password. Same underlying data, different wrappers. Most confusion comes from the file extensions, which are used inconsistently.
This guide shows how to identify what you have, how the pieces fit together, where each server wants them, and the OpenSSL commands that convert between forms. Nothing here needs more than a terminal and a few minutes.
The pieces: certificate, chain, key, request
Four things get mixed up. The private key is generated on your server (or by you) and never leaves it. The CSR, a certificate signing request, is built from the key and sent to the authority. The certificate comes back, signed, tying your public key to your names. The intermediates are the certificates of the authority's own signing keys, which link yours to a root that browsers already trust.
Only the key is secret. Everything else is public and can be pasted into support tickets without harm. The key is the one file you should not email, upload to a chat, or commit to a repository.
How to tell what you have
Open the file in a text editor. If it starts with -----BEGIN CERTIFICATE-----, it is PEM, whatever its extension says. If it is unreadable binary, it is probably DER or PFX. Extensions like .crt and .cer are used loosely by different vendors, so the contents matter more than the name.
The header line tells you what kind of item is inside:
BEGIN CERTIFICATE: a certificate (yours or an intermediate)BEGIN PRIVATE KEY,BEGIN RSA PRIVATE KEYorBEGIN EC PRIVATE KEY: a private key, so handle it carefullyBEGIN ENCRYPTED PRIVATE KEY: a key protected with a passphraseBEGIN CERTIFICATE REQUEST: a CSRBEGIN PKCS7: a bundle in PKCS#7 form, normally certificates only
A single PEM file can hold several blocks one after another. That is how a chain file works: it is just certificates concatenated. For binary files, ask OpenSSL. This tries the likely formats in turn and tells you which one parses:
openssl x509 -in file -noout -subject -dates # PEM certificate
openssl x509 -inform der -in file -noout -subject -dates # DER certificate
openssl pkcs12 -in file -info -noout # PFX / PKCS#12
The common formats side by side
| Name | Looks like | Usually contains | Typical extensions | Used by |
|---|---|---|---|---|
| PEM | Text with BEGIN and END lines | One or more certificates or keys | .pem .crt .cer .key | Apache, Nginx, most Linux tools |
| DER | Binary | A single certificate | .der .cer | Java, some appliances |
| PKCS#12 / PFX | Binary, usually password protected | Certificate, chain and key together | .pfx .p12 | Windows, IIS, many import dialogs |
| PKCS#7 | Text or binary | Certificates only, no key | .p7b .p7c | Windows, Tomcat |
The order matters
When a server needs a chain file, certificates go in order: yours first, then the intermediate that signed it, then any further intermediates. The root is normally omitted, since clients already have it. Putting them in the wrong order is a common reason a certificate appears to install but fails verification on some devices. Desktop browsers often forgive it or fetch a missing intermediate on their own; older phones, command line tools and API clients do not.
If your authority gives you the pieces separately, build the chain file yourself and check it:
cat example.com.crt intermediate.crt > fullchain.pem
openssl crl2pkcs7 -nocrl -certfile fullchain.pem | openssl pkcs7 -print_certs -noout
The second command lists the subject and issuer of every certificate in order. Each certificate's issuer should be the subject of the next one down.
Apache
Apache uses three settings: SSLCertificateFile for your certificate, SSLCertificateKeyFile for the private key, and SSLCertificateChainFile (or the chain included in the main file in newer versions) for intermediates. In Apache 2.4.8 and later you can put your certificate and the intermediates together in the file named by SSLCertificateFile, and the separate chain directive is deprecated.
<VirtualHost *:443>
ServerName example.com
SSLEngine on
SSLCertificateFile /etc/ssl/example.com/fullchain.pem
SSLCertificateKeyFile /etc/ssl/example.com/privkey.pem
</VirtualHost>
Test the configuration with apachectl configtest before reloading, so a typo in a path does not take every site on the machine down.
Nginx
Nginx wants one file containing your certificate followed by the intermediates, referenced by ssl_certificate, and the key in ssl_certificate_key.
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/ssl/example.com/fullchain.pem;
ssl_certificate_key /etc/ssl/example.com/privkey.pem;
}
Run nginx -t and then reload. A frequent mistake is pointing ssl_certificate at the lone certificate file, which works in some browsers and fails in others, because the intermediate is not sent.
Windows and IIS
These generally use PFX files. You import it into the certificate store and bind it to the site. The wrapper holds the key, so the file needs a password when you create it, and you will be asked for that password at import. Mark the key as non-exportable if you can, so it cannot later be copied off the machine. If you are given a certificate and a key as separate PEM files, build a PFX with the command in the next section first.
On shared hosting you rarely handle any of this: the control panel has a form where you paste the certificate, the key and the chain into separate boxes, in PEM form. The panel then writes the right files for the underlying server.
Handy conversions with OpenSSL
PEM to DER: openssl x509 -in cert.pem -outform der -out cert.der DER to PEM: openssl x509 -inform der -in cert.der -out cert.pem PFX to PEM: openssl pkcs12 -in cert.pfx -out all.pem -nodes PEM to PFX: openssl pkcs12 -export -out cert.pfx -inkey key.pem -in cert.pem -certfile chain.pem P7B to PEM: openssl pkcs7 -print_certs -in bundle.p7b -out certs.pem Check a pair: compare the output of 'openssl x509 -noout -modulus -in cert.pem' with 'openssl rsa -noout -modulus -in key.pem'
The pair check is worth knowing. Both commands print a long hexadecimal value; pipe each through openssl md5 and compare the short hashes. If they differ, the certificate and key are not a pair. For elliptic curve keys, which have no modulus, compare the public key instead with openssl x509 -noout -pubkey and openssl pkey -pubout.
Note that -nodes writes the private key out unencrypted. Use it only to a location you control, and delete the file afterwards.
Worked example: a zip from the authority, a server that wants one file
Say the authority sends example.com.crt, intermediate.crt and root.crt, and you generated the key and CSR on the server last week as example.com.key. You run Nginx. The steps:
- Confirm the files are PEM with
head -1on each. All three should start with-----BEGIN CERTIFICATE-----. - Confirm the pair: the md5 of the modulus from
example.com.crtand fromexample.com.keymust be identical. - Build the chain:
cat example.com.crt intermediate.crt > fullchain.pem. Leaveroot.crtout. - Copy
fullchain.pemand the key to/etc/ssl/example.com/, then set the key to mode 600, owned by root. - Edit the two Nginx directives, run
nginx -t, thensystemctl reload nginx. - From another machine, run
openssl s_client -connect example.com:443 -servername example.comand look forVerify return code: 0 (ok)at the end.
If the last line says return code 21 or 20, an intermediate is missing; if it says 10, the certificate has expired. Go back to step 3 and look at the order. The whole job takes about ten minutes, and the check in the last step is the one people skip. It takes ten seconds once you have done it once, and the unsatisfying truth is that most of the delay is waiting for the file to arrive.
Common errors
"Key values mismatch" means the certificate and private key are not a pair. This usually follows a reissue, when the new certificate belongs to a new key you generated and then lost, or a CSR was made on another machine. "Unable to get local issuer certificate" means the intermediate is missing. "Certificate has expired" is exactly what it sounds like, and it is worth checking whether the server is still presenting an older certificate than the one you just installed. A web server often needs a reload, not just a file replacement, to start serving the new one.
Two more that appear regularly: "PEM routines: no start line", which means the file is not PEM or has stray characters at the top (copy-paste from email often adds them), and "bad decrypt" or "mac verify failure", which means a wrong PFX password.
Questions that come up
Is .crt different from .pem?
Not by itself. It is only a name. Both are usually PEM text; look at the first line to be sure.
Do I need the root certificate?
Normally no. Clients already hold the roots they trust, and sending one wastes bytes without helping validation.
Why does my certificate work in Chrome but fail in curl?
Browsers can fetch a missing intermediate on their own. Tools like curl and many API clients cannot, so the chain file is incomplete. See the certificate types guide for background on what the authority signs.
Can I put the key and certificate in one file?
Some servers accept a combined PEM, and PFX always combines them. For Apache and Nginx, keep them separate; it makes permissions simpler.