01TLS certificates in 60 seconds
A private key stays secret on the device; its matching public key is shared. A CSR (certificate signing request) packages that public key with an identity (hostname/SAN) and is sent to a CA to be signed. The CA returns a certificate plus any intermediate certs — together the chain that clients validate up to a trusted root. File formats you'll meet:
- PEM — base64 text (
-----BEGIN…); the usual.key,.csr,.crt/.pem. - DER — the same data in binary; some appliances want it.
- PKCS#12 — a single password-protected
.pfx/.p12that bundles the key + cert (+ chain); common on Windows and many network devices.
PEM = base64(DER) + BEGIN/END header lines
key pair = private key + public key · public key = f(private key)
02Generate a private key (on Linux)
Start with the key. RSA 2048 is the safe default; EC (P-256) is smaller and faster. Lock it down.
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out switch01.key # RSA 2048 # or an elliptic-curve key (smaller, fast): openssl ecparam -name prime256v1 -genkey -noout -out switch01.key # EC P-256 chmod 600 switch01.key # only you can read the private key openssl pkey -in switch01.key -pubout -out switch01.pub # extract the public key (rarely needed)
03Create the CSR (with SAN)
A certificate authority won't just sign a name for you — it needs your public key bound to that identity, plus proof you hold the matching private key. That is what a CSR is: OpenSSL packages your public key with the identity you claim (hostname + SAN) and signs the request with your private key to prove possession, then discards that signature. The CA verifies it, confirms you control the name, and issues the certificate. The point is that your private key never leaves the host — only the CSR (safe to share) travels. The CSR is also where you state exactly what you want in the cert: SAN, key usage, and so on. Modern clients ignore the CN and require a Subject Alternative Name, so always set SAN (add an IP only if you'll browse by IP).
openssl req -new -key switch01.key -out switch01.csr \ -subj "/C=DE/O=Example/CN=switch01.example.com" \ -addext "subjectAltName=DNS:switch01.example.com,IP:10.0.0.10" openssl req -in switch01.csr -noout -text # confirm the SAN is present before sending it
Certificate Request:
Data:
Subject: C = DE, O = Example, CN = switch01.example.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Requested Extensions:
X509v3 Subject Alternative Name:
DNS:switch01.example.com, IP Address:10.0.0.10
Signature Algorithm: sha256WithRSAEncryption
CSR = public key + identity (CN + SAN) + signature(private key)
Best practice — let the device generate its own key + CSR. Where a switch or firewall supports it (e.g. FortiGate's Generate CSR), have the appliance create its key and CSR on-box: the private key is generated there and never exists anywhere else, which is the most secure option. You just sign the returned CSR with your CA and upload the certificate back. Use the OpenSSL workflow above for Linux servers, for devices that can't self-generate, or when a central team issues certs on your behalf.
Do you always need a separate CSR? No — the step can also be skipped or delegated. What really changes is who generates the CSR and who holds the private key:
- Self-signed, one step — make the key and a self-signed cert directly, with no
.csrfile on disk (a CSR is still built internally). Fine for labs and internal endpoints:
openssl req -x509 -newkey rsa:2048 -nodes -keyout switch01.key -out switch01.crt \ -days 397 -subj "/CN=switch01.example.com" \ -addext "subjectAltName=DNS:switch01.example.com" # key + self-signed cert, no CSR file
- Let tooling make it (ACME / certbot) — Let's Encrypt or an internal ACME client generates the key and CSR for you and proves domain control automatically; best for public-facing HTTPS with auto-renewal.
- Let the CA / platform generate everything — some internal CAs and cloud services (AWS ACM, Azure Key Vault) mint the key and cert and hand back a bundle. Convenient, but the issuer holds your private key — a deliberate trade-off.
Bottom line: keep the private key wherever it is created. For a switch or firewall that means preferring on-device key + CSR generation; reach for the Linux/OpenSSL flow above for servers and anything that can't self-generate. The CSR itself never really goes away — the choice is just who creates it.
04Get the certificate — three paths
Send the CSR (never the key) to whoever will sign it. Pick one:
# (a) Enterprise / public CA — upload switch01.csr in their portal; they return # switch01.crt plus an intermediate/chain file. Nothing else to do here. # (b) Sign with your own INTERNAL CA (create it once): openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:4096 -out ca.key openssl req -x509 -new -key ca.key -days 3650 -subj "/CN=Example Internal CA" -out ca.crt openssl x509 -req -in switch01.csr -CA ca.crt -CAkey ca.key -CAcreateserial \ -days 397 -copy_extensions copyall -out switch01.crt # copyall keeps the SAN # (c) Self-signed (labs / quick tests only): openssl x509 -req -in switch01.csr -signkey switch01.key -days 397 \ -copy_extensions copyall -out switch01.crt
Certificate request self-signature ok subject=C = DE, O = Example, CN = switch01.example.com
Heads-up — you normally don't run these signing commands yourself. In practice you use path (a): hand the CSR to your enterprise or public CA and get the signed certificate back. Paths (b) and (c) show what a Linux box acting as the CA does under the hood — they're here so you understand the process and can stand up your own lab or internal CA, not steps you run against a real CA. Keep validity short either way — public CAs cap leaf certs at ~398 days, and short-lived certs limit exposure.
certificate = public key + identity + validity + signature(CA)
05Assemble & convert the files · optional
Only if a device needs it. If your target takes a plain key + PEM certificate, you can skip straight to installing them. Do this step when a device wants the full chain, a PKCS#12 bundle, or DER — and verify before you deploy either way.
cat switch01.crt ca.crt > fullchain.pem # server cert first, then intermediate(s) openssl pkcs12 -export -inkey switch01.key -in switch01.crt -certfile ca.crt \ -out switch01.pfx # key + cert + chain, one password-protected file openssl x509 -in switch01.crt -outform der -out switch01.der # PEM -> DER (if a device wants binary) openssl verify -CAfile ca.crt switch01.crt # does the chain validate? openssl x509 -in switch01.crt -noout -subject -dates -ext subjectAltName # inspect it
switch01.crt: OK
subject=C = DE, O = Example, CN = switch01.example.com
notBefore=Jul 28 10:00:00 2026 GMT
notAfter=Aug 30 10:00:00 2027 GMT
X509v3 Subject Alternative Name:
DNS:switch01.example.com, IP Address:10.0.0.10
What the PKCS#12 (.pfx/.p12) actually is, and why. It is a
single, password-protected binary container that bundles the private key together
with its certificate and any chain certs. The
openssl pkcs12 -export command above builds it from three inputs —
-inkey (the private key), -in (the leaf certificate), and
-certfile (the CA / intermediates) — and prompts for an export password that
encrypts the private key inside the file. Its purpose: many appliances and platforms
(Windows, Java keystores, FortiGate, load balancers) expect one file that carries the key
and cert together rather than separate PEM .key/.crt files — so
you upload a single portable bundle and import it in one step. Treat that password like the key
itself: anyone who has both has your private key.
fullchain.pem = server cert + intermediate cert(s)
PKCS#12 (.pfx) = password + private key + certificate + chain
06Where to install / upload each element
Now the part that trips people up: the same files land in different places per device.
Linux server (nginx / Apache)
Copy the private key (chmod 600) and the fullchain to
the box, then point the web server at them and reload.
# nginx ssl_certificate /etc/ssl/switch01/fullchain.pem; # cert + intermediates ssl_certificate_key /etc/ssl/switch01/switch01.key; # the private key # Apache: SSLCertificateFile (cert), SSLCertificateKeyFile (key), SSLCertificateChainFile (CA) sudo nginx -t && sudo systemctl reload nginx # test config, then reload
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
Firewall (FortiGate example)
GUI: System → Certificates → Import → Certificate — upload the
certificate (.crt) and the
key (.key), or a single PKCS#12 (.pfx)
with its password. Import the issuing CA under Import → CA Certificate.
Then bind the cert to the admin GUI (HTTPS) or SSL-VPN.
# CLI equivalent (import a local cert from key + cert):
config vpn certificate local
edit "switch01"
set private-key "-----BEGIN PRIVATE KEY----- ... -----END PRIVATE KEY-----"
set certificate "-----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----"
next
end
# then: config system global -> set admin-server-cert "switch01"
Switch (Cisco IOS / Aruba example)
Import the key + cert into a trustpoint, then enable the secure web/management service. Exact syntax varies by platform and version.
# Cisco IOS — paste PEM key then cert into a trustpoint: crypto pki import SWITCH01-TP pem terminal ip http secure-server # enable HTTPS management using the trustpoint # Aruba: upload via WebUI (Configuration -> System -> Certificates), or: crypto pki-import pem CERT switch01 ... # then bind under the management profile
Which file goes where — quick recap:
Private key (switch01.key) | Install on the target only (server key store, or imported into the firewall/switch). Never share or email it. |
|---|---|
Certificate (switch01.crt) | The device's own cert — install alongside the key on every target. |
Chain / CA (ca.crt, fullchain.pem) | Serve the intermediate(s) with the cert; import the CA on the device and distribute the CA cert to clients (for internal CAs). |
PKCS#12 (switch01.pfx) | Use instead of separate key+cert on appliances/Windows that want one bundled, password-protected file. |
07Best practices
- Guard the private key. Generate it on a secure host,
chmod 600, never email it, and don't reuse one key across devices. - Always set SAN (DNS, plus IP only if you browse by IP) — CN alone is ignored.
- Strong algorithms — RSA 2048+ or EC P-256, SHA-256 signatures.
- Short validity + automated renewal (ACME/internal CA tooling); track expiry so nothing lapses silently.
- Install the full chain in order (leaf → intermediates) and never ship the CA private key to a device.
- Prefer an internal CA and distribute its CA cert to clients over scattering self-signed certs.
- Keep keys/passphrases out of scripts — use env or a vault (see the secrets guide).
08Verify the deployment
After installing, confirm what the device actually serves — the cert, its dates, and its SAN.
openssl s_client -connect switch01.example.com:443 -servername switch01.example.com </dev/null \ | openssl x509 -noout -subject -dates -ext subjectAltName # Expect: your subject, valid dates, and the SAN you set. A browser padlock is the final check.
subject=C = DE, O = Example, CN = switch01.example.com
notBefore=Jul 28 10:00:00 2026 GMT
notAfter=Aug 30 10:00:00 2027 GMT
X509v3 Subject Alternative Name:
DNS:switch01.example.com, IP Address:10.0.0.10
09Where to go next
Once the workflow is muscle memory, script it and pull the key/passphrase from a vault — see the shell & environment guide and the Linux commands guide. Back to the Knowledge Base.