How to Use OpenSSL: Generate Keys, Certificates, and Test TLS

By 

Published on

8 min read

Generating keys and certificates with OpenSSL in a Linux terminal

Sooner or later, working with web servers, mail servers, or APIs means dealing with TLS certificates. You may need a private key for a new service, a certificate signing request to send to a certificate authority, a quick self-signed certificate for a test environment, or a way to confirm what a remote server is actually presenting. OpenSSL covers all of this from a single command-line tool.

OpenSSL is the de facto toolkit for the TLS and SSL protocols on Linux. It ships with almost every distribution and exposes dozens of subcommands for key generation, certificate handling, encoding conversions, and connection testing.

This guide explains how to use openssl to generate keys, create and inspect certificates, convert between formats, and test live TLS connections.

Syntax

OpenSSL works through subcommands, each with its own options:

txt
openssl command [ command_options ] [ arguments ]

For example, openssl genrsa generates an RSA key, while openssl x509 works with X.509 certificates. You can list every available subcommand with:

Terminal
openssl help

Check which version is installed before you start, since option defaults change between major releases:

Terminal
openssl version
output
OpenSSL 3.5.5 27 Jan 2026

OpenSSL 3.x is the current series on modern distributions. The examples below work on the 3.x line.

Generate a Private Key

Most certificate work starts with a private key. To create a 2048-bit RSA key, run:

Terminal
openssl genrsa -out private.key 2048

This writes an unencrypted key to private.key. A 2048-bit key is the practical minimum today; use 4096 bits when you want a wider safety margin and do not mind the small performance cost.

To protect the key with a passphrase, add a cipher option such as -aes256:

Terminal
openssl genrsa -aes256 -out private.key 2048

OpenSSL prompts you for the passphrase and encrypts the key on disk. The service that uses the key will then ask for that passphrase on startup.

Elliptic-curve keys are smaller and faster than RSA at equivalent security. To generate one on the widely supported prime256v1 curve:

Terminal
openssl ecparam -name prime256v1 -genkey -noout -out ec-private.key
Warning
A private key is a secret. Keep its permissions tight (chmod 600 private.key), never commit it to version control, and add key files to your .gitignore. Anyone who has the key can impersonate your service.

Create a Certificate Signing Request

A certificate signing request (CSR) bundles your public key and identifying details so a certificate authority can issue a signed certificate. Generate a key and CSR together:

Terminal
openssl req -new -newkey rsa:2048 -noenc -keyout domain.key -out domain.csr

OpenSSL prompts for the subject fields. The Common Name (CN) should match the primary domain you are securing, for example example.com. The -noenc option leaves the key unencrypted so a service can read it without a passphrase prompt.

To skip the interactive prompts, pass the subject inline and add Subject Alternative Name (SAN) entries for each hostname the certificate should cover:

Terminal
openssl req -new -newkey rsa:2048 -noenc \
  -keyout domain.key -out domain.csr \
  -subj "/C=US/ST=California/L=San Francisco/O=Example Inc/CN=example.com" \
  -addext "subjectAltName=DNS:example.com,DNS:www.example.com"

Inspect the finished CSR to confirm the details before sending it off:

Terminal
openssl req -in domain.csr -noout -text

The output lists the subject, public key, and any requested extensions.

Create a Self-Signed Certificate

For local development, internal tools, or testing, a self-signed certificate avoids the need for a CA. Generate a key and certificate valid for one year in a single command:

Terminal
openssl req -x509 -newkey rsa:2048 -noenc \
  -keyout selfsigned.key -out selfsigned.crt \
  -days 365 \
  -subj "/CN=localhost" \
  -addext "subjectAltName=DNS:localhost,IP:127.0.0.1"

The -x509 option tells req to output a certificate instead of a request, and -days 365 sets the validity period. Browsers will warn that the certificate is not trusted, which is expected for self-signed certificates. For a fuller walkthrough, see our guide on creating a self-signed SSL certificate .

When you need a browser-trusted certificate for a public site, use a CA such as Let’s Encrypt instead.

Inspect a Certificate

To read the contents of a certificate in human-readable form:

Terminal
openssl x509 -in selfsigned.crt -noout -text

This prints the issuer, subject, validity dates, public key, and extensions. When you only need specific fields, target them directly. To see just the validity window:

Terminal
openssl x509 -in selfsigned.crt -noout -dates
output
notBefore=Jan  1 08:00:00 2026 GMT
notAfter=Jan  1 08:00:00 2027 GMT

To print the subject and issuer:

Terminal
openssl x509 -in selfsigned.crt -noout -subject -issuer

For a self-signed certificate, the subject and issuer are the same.

Verify Key, Certificate, and CSR Match

When deploying a certificate, the private key, certificate, and CSR must all share the same public key. A mismatch is a common cause of services that refuse to start. Compare their modulus hashes:

Terminal
openssl rsa -in domain.key -noout -modulus | openssl md5
openssl x509 -in domain.crt -noout -modulus | openssl md5
openssl req -in domain.csr -noout -modulus | openssl md5

All three commands must print the same hash. If one differs, the files do not belong together.

Convert Certificate Formats

Different platforms expect different encodings. OpenSSL converts between them.

Convert a PEM certificate to DER (binary), often required by Java or Windows tools:

Terminal
openssl x509 -in cert.pem -outform der -out cert.der

Convert DER back to PEM:

Terminal
openssl x509 -in cert.der -inform der -outform pem -out cert.pem

Bundle a certificate and private key into a PKCS#12 file (.pfx or .p12), the format many Windows services and load balancers expect:

Terminal
openssl pkcs12 -export -out bundle.pfx -inkey domain.key -in domain.crt

OpenSSL asks for an export password that protects the bundle.

Test a TLS Connection

The s_client subcommand opens a TLS connection to a server and reports what it negotiated. This is the fastest way to debug a certificate that does not seem to work:

Terminal
openssl s_client -connect example.com:443

The output shows the certificate chain, the negotiated protocol and cipher, and the verification result. Press Ctrl+C or type Q to close the session.

When a server hosts several names on one IP, send the hostname with Server Name Indication so you get the right certificate:

Terminal
openssl s_client -connect example.com:443 -servername example.com

To check when a live certificate expires without scrolling through the full chain, pipe the output into x509:

Terminal
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
  | openssl x509 -noout -dates

The echo closes the connection immediately so the command returns instead of waiting for input. This is handy for verifying renewals after a certificate is reissued. If a hostname is not resolving as expected during testing, the dig command helps confirm the DNS records first.

Generate Random Data and Hashes

OpenSSL also doubles as a general crypto utility. Generate a random, URL-safe token:

Terminal
openssl rand -base64 32

Hash a file with SHA-256:

Terminal
openssl dgst -sha256 file.iso

These small helpers are useful for generating secrets or verifying downloads when no dedicated tool is at hand.

Quick Reference

For a printable quick reference, see the OpenSSL cheatsheet .

TaskCommand
Show versionopenssl version
Generate RSA keyopenssl genrsa -out private.key 2048
Generate EC keyopenssl ecparam -name prime256v1 -genkey -noout -out ec.key
Create CSRopenssl req -new -newkey rsa:2048 -noenc -keyout d.key -out d.csr
Self-signed certopenssl req -x509 -newkey rsa:2048 -noenc -keyout d.key -out d.crt -days 365
Inspect certopenssl x509 -in cert.crt -noout -text
Check expiry datesopenssl x509 -in cert.crt -noout -dates
PEM to DERopenssl x509 -in cert.pem -outform der -out cert.der
Export PKCS#12openssl pkcs12 -export -out b.pfx -inkey d.key -in d.crt
Test TLSopenssl s_client -connect host:443 -servername host

Troubleshooting

unable to load Private Key
The key file is encrypted and OpenSSL expected an unencrypted one, or the file is corrupt. Add the passphrase when prompted, or regenerate the key with -noenc if the service cannot supply a passphrase.

verify error:num=18:self signed certificate
s_client is reporting that the chain ends in a self-signed certificate. This is normal for self-signed certificates and for testing. For a public site, install the full chain issued by your CA.

verify error:num=20:unable to get local issuer certificate
The server did not send the intermediate certificate. Concatenate your certificate and the CA intermediate into one file and serve that combined file.

Key and certificate modulus do not match
The certificate was not issued for this key. Re-check that you generated the CSR from the same key the CA signed, then compare modulus hashes as shown above.

FAQ

What is the difference between a CSR and a certificate?
A CSR contains your public key and identity details and is sent to a certificate authority. The CA returns a signed certificate. The CSR is the request; the certificate is the issued result.

Should I use RSA or elliptic-curve keys?
Elliptic-curve keys (such as prime256v1) are smaller and faster at equivalent security and are well supported. RSA 2048 remains a safe, widely compatible default. Either is fine for most servers.

How do I remove a passphrase from a key?
Run openssl rsa -in encrypted.key -out plain.key. OpenSSL prompts for the current passphrase and writes an unencrypted copy. Protect that file carefully, since it is no longer passphrase-protected.

Why does my self-signed certificate trigger browser warnings?
Browsers only trust certificates signed by a recognized authority. Self-signed certificates are not in that trust store, so the warning is expected. Use Let’s Encrypt for public sites.

Conclusion

OpenSSL handles the full lifecycle of TLS material: keys, requests, certificates, format conversions, and live connection testing. When you move from generating certificates to serving them, use a trusted CA and keep renewal on a schedule so certificates do not expire unnoticed.

Linuxize Weekly Newsletter

A quick weekly roundup of new tutorials, news, and tips.

About the authors

Dejan Panovski

Dejan Panovski

Dejan Panovski is the founder of Linuxize, an RHCSA-certified Linux system administrator and DevOps engineer based in Skopje, Macedonia. Author of 800+ Linux tutorials with 20+ years of experience turning complex Linux tasks into clear, reliable guides.

View author page