| nginx | Two PEM files: ssl_certificate is your certificate followed by the intermediates; ssl_certificate_key is the private key, without a password. |
|---|---|
| Apache httpd 2.4.8+ | Same as nginx: SSLCertificateFile holds the certificate and intermediates, SSLCertificateKeyFile the key. |
| HAProxy | One PEM file with the certificate, the intermediates and the private key, given to crt. |
| Kubernetes | PEM files: kubectl create secret tls NAME --cert=fullchain.pem --key=key.pem |
| AWS Certificate Manager | PEM certificate, PEM chain and a PEM private key that has no password. |
| IIS and Windows Server | A PFX with the private key. Windows Server 2016 and older need the Compatible (3DES) PFX. |
| Azure App Service | A password-protected PFX with the full chain. Microsoft's docs show the 3DES options for OpenSSL 3. |
| Tomcat and Java apps | A PFX (PKCS#12) keystore. JKS still works. Tomcat 8.5+ can also read PEM files. |
OpenSSL runs on Linux, macOS and Windows (it comes with Git for Windows). Commands that ask for a password prompt for it, so it doesn't end up in your shell history.
PEM is Base64 text between -----BEGIN CERTIFICATE----- lines. DER is the same certificate as raw binary. Windows and Java often want DER in a .cer file.
OpenSSL
openssl x509 -in cert.pem -outform der -out cert.der
Windows
certutil -decode cert.pem cert.der
Turns a binary certificate into the text form that nginx, Apache, HAProxy and most Linux software read.
OpenSSL
openssl x509 -in cert.der -inform der -out cert.pem
Windows
certutil -encode cert.der cert.pem
.cer or .crt file can be either kind. If it starts with -----BEGIN CERTIFICATE----- it is already PEM: just rename it.openssl x509 -in cert.cer -noout -subject. If that fails, add -inform der.A .p7b or .p7c file is a bundle of certificates, often what a CA or Windows sends. It never contains a private key.
Text (PEM) P7B
openssl pkcs7 -print_certs -in certs.p7b -out certs.pem
Binary (DER) P7B
openssl pkcs7 -print_certs -inform der -in certs.p7b -out certs.pem
subject= and issuer= lines above each certificate. Servers ignore them, so you can leave them in.Bundles your certificate and its chain into one .p7b file, which Windows and some Java tools import in one step.
Text (PEM) P7B
openssl crl2pkcs7 -nocrl -certfile fullchain.pem -out certs.p7b
Binary (DER) P7B
openssl crl2pkcs7 -nocrl -certfile fullchain.pem -outform der -out certs.p7b
The server must send your certificate plus the intermediate certificates. Put them in one PEM file, in order: your certificate first, then the intermediate that signed it, then the next one up. Leave the root out; clients already have it.
Join
cat cert.pem intermediate.pem > fullchain.pem
Check the order
openssl crl2pkcs7 -nocrl -certfile fullchain.pem | openssl pkcs7 -print_certs -noout
Check it verifies
openssl verify -untrusted intermediate.pem cert.pem
issuer= should match the subject= of the next certificate.key values mismatch, your certificate usually isn't first in the file, or the key belongs to another certificate.A .pfx or .p12 file holds a certificate, its private key and often the chain, all protected by one password. Each command asks for that password.
Everything in one file
openssl pkcs12 -in site.pfx -out site.pem -nodes
Certificate only
openssl pkcs12 -in site.pfx -clcerts -nokeys -out cert.pem
Chain only
openssl pkcs12 -in site.pfx -cacerts -nokeys -out chain.pem
Private key only
openssl pkcs12 -in site.pfx -nocerts -nodes -out key.pem
-nodes writes the key without a password, which is what nginx and Apache expect. Leave it out to keep the key encrypted.Bag Attributes lines above each block. They are harmless.chmod 600 key.pem.OpenSSL 3 no longer reads the old RC2 encryption by default, so an older PFX fails with error:0308010C:digital envelope routines::unsupported and RC2-40-CBC. The password is fine.
Read it anyway
openssl pkcs12 -legacy -in old.pfx -out site.pem -nodes
Save a modern copy
openssl pkcs12 -export -in site.pem -out new.pfx
Combines your certificate, its chain and the private key into one password-protected file.
OpenSSL
openssl pkcs12 -export -out site.pfx -inkey key.pem -in cert.pem -certfile chain.pem -name "www.example.com"
-name becomes the friendly name Windows shows.No certificate matches private key, the key belongs to a different certificate.OpenSSL 3 encrypts PFX files with AES-256. Windows 11 and Windows Server 2019 and later read that, but older Windows can't, and wrongly says the password is incorrect. Use the older 3DES encryption instead.
OpenSSL 3
openssl pkcs12 -export -out site.pfx -inkey key.pem -in cert.pem -certfile chain.pem -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES -macalg sha1
Shows how the file is encrypted and lists the certificates, without writing the key anywhere.
Encryption and contents
openssl pkcs12 -in site.pfx -info -noout
Certificates (Linux and macOS)
openssl pkcs12 -in site.pfx -nokeys | openssl crl2pkcs7 -nocrl -certfile /dev/stdin | openssl pkcs7 -print_certs -noout
Windows
certutil -dump site.pfx
Same key, different wrapper. BEGIN RSA PRIVATE KEY (PKCS#1) and BEGIN EC PRIVATE KEY (SEC1) are the older forms; BEGIN PRIVATE KEY (PKCS#8) works for every key type. Most software reads both, but some older libraries want one or the other.
To PKCS#8
openssl pkey -in old.key -out new.key
To RSA (PKCS#1), OpenSSL 3
openssl rsa -in key.pem -traditional -out rsa.key
To RSA (PKCS#1), OpenSSL 1.1
openssl rsa -in key.pem -out rsa.key
To EC (SEC1)
openssl ec -in key.pem -out ec.key
nginx and Apache read a key without a password at start-up. With a password they stop and ask for it, which breaks unattended restarts.
Remove the password
openssl pkey -in encrypted.key -out plain.key
Add a password
openssl pkey -in plain.key -aes256 -out encrypted.key
chmod 600 plain.key.Some Java and embedded tools want the key as binary DER.
PEM to DER
openssl pkey -in key.pem -outform der -out key.der
DER to PEM
openssl pkey -in key.der -inform der -out key.pem
A certificate only works with the key it was issued for. If these hashes are the same, they match.
Certificate
openssl x509 -in cert.pem -noout -pubkey | openssl sha256
Private key
openssl pkey -in key.pem -pubout | openssl sha256
CSR
openssl req -in request.csr -noout -pubkey | openssl sha256
SSH keys use their own formats. Convert them with the SSH tools, not OpenSSL.
OpenSSH key to PEM (rewrites the file, so copy it first)
cp id_rsa id_rsa.pem && ssh-keygen -p -m PEM -f id_rsa.pem
OpenSSH public key to PEM
ssh-keygen -e -m PKCS8 -f id_rsa.pub > id_rsa.pub.pem
PuTTY .ppk to OpenSSH
puttygen key.ppk -O private-openssh -o id_rsa
Java's own .jks format can't be opened in a browser. Turn it into a PFX with keytool, then into PEM if you need to.
JKS to PFX
keytool -importkeystore -srckeystore keystore.jks -destkeystore keystore.p12 -deststoretype pkcs12
Then to PEM
openssl pkcs12 -in keystore.p12 -out keystore.pem -nodes
-srcalias NAME. keytool -list -keystore keystore.jks shows the names.Java 9 and later use PKCS#12 as their default keystore type, so Tomcat and most Java apps can use your .pfx directly. Convert only if something insists on JKS.
PFX to JKS
keytool -importkeystore -srckeystore site.pfx -srcstoretype pkcs12 -destkeystore keystore.jks -deststoretype jks
Algorithm HmacPBESHA256 not available. Make the PFX with 3DES instead (see the Windows entry above).For when Java says PKIX path building failed because it doesn't trust your internal CA.
Your own truststore
keytool -importcert -alias my-ca -file ca.pem -keystore truststore.jks
Java's built-in cacerts (Java 9 and later)
sudo keytool -importcert -cacerts -alias my-ca -file ca.pem
changeit unless someone changed it.For servers where you manage certificates in the Windows certificate store, as IIS does.
Import a PFX
Import-PfxCertificate -FilePath .\site.pfx -CertStoreLocation Cert:\LocalMachine\My -Password (Read-Host -AsSecureString -Prompt 'PFX password')
Export a PFX
$pw = Read-Host -AsSecureString -Prompt 'New PFX password'
Get-ChildItem Cert:\LocalMachine\My | Where-Object Subject -like '*example.com*' |
Export-PfxCertificate -FilePath .\site.pfx -Password $pw -ChainOption BuildChainExport the certificate only (.cer)
Get-ChildItem Cert:\LocalMachine\My | Where-Object Subject -like '*example.com*' |
Export-Certificate -FilePath .\site.cerExport-Certificate writes DER. Convert it to PEM with certutil -encode site.cer site.pem.