Quick take: openssl handles everything SSL/TLS from the command line — generate RSA or EC keys, create CSRs, self-sign certificates, inspect certificate files, test TLS handshakes, convert between PEM and DER formats, and generate cryptographically random secrets.
Introduction
SSL/TLS certificate management is one of those areas where infrastructure engineers either have a clear mental model of the toolchain or they do not — and the difference shows immediately when something breaks. A certificate expired last night and the site is down. A new service needs a self-signed cert for local development. A client's load balancer is rejecting your certificate and you need to verify the chain. A third-party API is presenting a cert you do not trust and you need to see what it actually contains. All of these situations end up at the same tool: openssl.
OpenSSL is the open-source implementation of the SSL and TLS protocols, and the openssl command is its command-line interface. It handles the full lifecycle of certificates: key generation, certificate signing requests, self-signed certificates, certificate inspection, TLS connection testing, format conversion, and symmetric file encryption. On every Linux server I manage, openssl is one of the first tools I reach for when anything involving HTTPS, certificates, or secure communication needs investigating.
This guide focuses on the practical subcommands you will use regularly as a server administrator or DevOps engineer, rather than trying to cover every option in the manual. Each section includes the exact commands I use in real deployments.
Syntax and Subcommands
openssl is a toolkit rather than a single command. You call it with a subcommand that selects which operation to perform:
openssl SUBCOMMAND [OPTIONS]The main subcommands you will use most often are: genrsa and genpkey for generating private keys, req for certificate signing requests and self-signed certificates, x509 for inspecting and manipulating certificates, s_client for testing TLS connections, verify for validating certificate chains, pkcs12 for converting between formats, enc for symmetric encryption, and rand for generating random bytes.
Generating Private Keys
The private key is the foundation of every certificate. You generate it first, then create a certificate signing request from it, then get the certificate signed. Keep the private key secure — it never leaves the server and should never appear in logs or version control.
# Generate a 4096-bit RSA private key
openssl genrsa -out private.key 4096
# Generate a 2048-bit RSA key (minimum for modern use, 4096 preferred for CAs)
openssl genrsa -out private.key 2048
# Generate an EC key using the P-256 curve (faster than RSA, equally secure)
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out ec.key
# Generate an RSA key with AES encryption (prompts for passphrase)
openssl genrsa -aes256 -out protected.key 4096
# View information about an existing private key
openssl rsa -in private.key -text -nooutEC (Elliptic Curve) keys are worth knowing about. A P-256 EC key provides equivalent security to a 3072-bit RSA key but is much smaller and faster for both signing and verification. For new deployments, especially when configuring nginx or Apache with TLS, EC keys with the P-256 curve are an excellent choice. Most major certificate authorities issue certificates for EC keys, and all modern clients support them.
For keys that will be on production servers, I do not use passphrases on the key file. A passphrase means the web server cannot start without a human entering the password — which is a problem during automatic restarts, disaster recovery, and deployments. Instead, protect the key file with strict permissions (chmod 600 private.key) and restrict who has read access to the server.
Creating Certificate Signing Requests
A CSR (Certificate Signing Request) is what you send to a Certificate Authority (CA) to get a signed certificate. It contains your public key plus information about your organisation and the domain name the certificate should cover.
# Interactive: generates a key and CSR together
openssl req -newkey rsa:4096 -keyout private.key -out request.csr -nodes
# Non-interactive: use -subj to skip the prompts
openssl req -newkey rsa:4096 -keyout private.key -out request.csr -nodes \
-subj "/C=SA/ST=Riyadh/L=Riyadh/O=MyCompany/CN=api.mycompany.com"
# Create CSR from an existing private key
openssl req -new -key private.key -out request.csr
# Create CSR with Subject Alternative Names (SANs) — required for multi-domain certs
openssl req -new -key private.key -out request.csr \
-subj "/CN=mycompany.com" \
-addext "subjectAltName=DNS:mycompany.com,DNS:www.mycompany.com,DNS:api.mycompany.com"
# View a CSR to confirm what you are sending to the CA
openssl req -in request.csr -text -nooutThe -nodes flag means "no DES" — it generates the key without a passphrase, which is what you want for server certificates. The -subj fields are: C = country code (SA for Saudi Arabia, US for United States, GB for UK), ST = state or province, L = city, O = organisation name, CN = Common Name (the primary domain).
Subject Alternative Names (SANs) are essential for modern certificates. Browsers now require SANs and ignore the CN field for domain validation. If your certificate needs to cover multiple hostnames — the bare domain and www, or multiple subdomains — list them all in the SAN extension. A certificate without SANs will cause browser security warnings on most modern clients.
Self-Signed Certificates
Self-signed certificates are perfect for internal services, local development, and testing environments where you control all the clients and do not need a trusted CA. They use the same key pair mechanism as CA-signed certificates but are signed by the key itself rather than a trusted third party.
# Generate a self-signed certificate in one command (key + cert together)
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes \
-subj "/CN=localhost"
# Self-signed certificate with SANs for local development
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes \
-subj "/CN=myapp.local" \
-addext "subjectAltName=DNS:myapp.local,DNS:localhost,IP:127.0.0.1"
# Sign a CSR with your own CA to create an internally-trusted cert
openssl x509 -req -in request.csr -CA ca.crt -CAkey ca.key \
-CAcreateserial -out signed.crt -days 365 -sha256For internal infrastructure, creating your own CA and signing certificates with it is better than using self-signed certs everywhere. You install the CA certificate into your browser and operating system's trust store once, and then every certificate signed by that CA is trusted automatically. This mirrors how a real CA works, without the cost. Tools like step-ca or cfssl make running an internal CA easier, but you can do everything with plain openssl.
Inspecting Certificates and Keys
When a certificate causes problems — TLS errors, hostname mismatch, unexpected CA, wrong SANs — the first step is always to read what is actually in the certificate file or what the server is presenting.
# Read a PEM certificate file in human-readable form
openssl x509 -in cert.pem -text -noout
# Show only the expiry dates
openssl x509 -in cert.pem -noout -dates
# Show only the subject (who the cert is for)
openssl x509 -in cert.pem -noout -subject
# Show only the issuer (which CA signed it)
openssl x509 -in cert.pem -noout -issuer
# Show the SANs (Subject Alternative Names) — what domains it covers
openssl x509 -in cert.pem -noout -ext subjectAltName
# Show the serial number
openssl x509 -in cert.pem -noout -serial
# Show the fingerprint (useful for comparing certs)
openssl x509 -in cert.pem -noout -fingerprint -sha256
# Verify that a private key matches a certificate
openssl rsa -noout -modulus -in private.key | openssl md5
openssl x509 -noout -modulus -in cert.pem | openssl md5
# The two MD5 values must matchThe key-certificate match check (comparing modulus MD5 hashes) is one I run every time I install a new certificate on a server. If the private key and certificate do not match, the web server will either fail to start or will serve the wrong certificate. It takes three seconds to verify and saves the confusion of diagnosing a live outage.
Testing TLS Connections
openssl s_client is a TLS client built into openssl. You can use it to connect to any TLS-enabled service and see the full handshake, the server's certificate, and whether the connection succeeds. It is the go-to tool for diagnosing SSL/TLS problems on live servers.
# Connect to a web server and show the TLS handshake
openssl s_client -connect example.com:443
# Show only the certificate, not the full handshake detail
echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -text -noout
# Check certificate expiry on a live server
echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -dates
# Test with a specific SNI hostname (important for virtual hosting)
openssl s_client -connect 10.0.0.5:443 -servername api.example.com
# Test a specific TLS version
openssl s_client -connect example.com:443 -tls1_3
openssl s_client -connect example.com:443 -tls1_2
# Test SMTP with STARTTLS
openssl s_client -connect mail.example.com:587 -starttls smtp
# Test with a custom CA certificate
openssl s_client -connect internal.company.com:443 -CAfile /path/to/internal-ca.crtThe -servername flag is important when one IP address serves multiple domains using SNI (Server Name Indication). Without it, the server may present a default certificate that is not the one you are testing. Always use -servername when the IP does not map one-to-one to the domain name.
For automated expiry monitoring in scripts, the pattern with echo | piped through s_client and then x509 -noout -dates is widely used. It connects, immediately sends an empty line (which causes s_client to exit), and pipes the certificate to x509 for date extraction — all without any interactive input.
Checking Certificate Chains
A complete certificate chain includes your server certificate plus all intermediate CA certificates. Missing intermediate certs are a very common cause of TLS errors — the browser cannot verify the chain back to a trusted root because an intermediate is absent.
# Verify a certificate against a CA bundle
openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt cert.pem
# Verify the chain from a file you assembled yourself
openssl verify -CAfile ca.crt -untrusted intermediate.crt server.crt
# Check the chain the server actually presents
openssl s_client -connect example.com:443 -showcerts
# Count certificates in the chain (each PEM block is one cert)
grep -c 'BEGIN CERTIFICATE' chain.pemWhen assembling a chain file manually for nginx or Apache, the order matters: your server certificate first, then the intermediate CA, then (optionally) the root CA. Most CAs provide a bundle file in the correct order — use it rather than assembling manually if possible.
Practical Examples
Commands from real infrastructure work:
# Check all certs in a directory for expiry within 30 days
for cert in /etc/ssl/certs/*.pem; do
expiry=$(openssl x509 -enddate -noout -in "$cert" | cut -d= -f2)
echo "$cert: $expiry"
done
# Quickly check if a domain's cert is expiring soon
echo | openssl s_client -connect learnwithirfan.com:443 2>/dev/null \
| openssl x509 -noout -checkend 2592000 \
&& echo "OK: not expiring within 30 days" \
|| echo "WARNING: expiring within 30 days"
# Extract the public key from a certificate
openssl x509 -in cert.pem -pubkey -noout > public.key
# Convert a PKCS#12 (.p12 / .pfx) file to PEM (what nginx/Apache use)
openssl pkcs12 -in certificate.p12 -out certificate.pem -nodes
# Bundle a key and cert into a PKCS#12 for Java or Windows
openssl pkcs12 -export -in cert.pem -inkey private.key -out certificate.p12
# Test a specific cipher suite is supported
openssl s_client -connect example.com:443 -cipher AES256-GCM-SHA384Converting Certificate Formats
Certificates come in multiple formats. PEM is the most common on Linux (base64-encoded with BEGIN/END headers), DER is binary, and PKCS#12 bundles the key and certificate together. Different applications expect different formats:
# PEM to DER (binary format used by some Java and Windows tools)
openssl x509 -in cert.pem -out cert.der -outform DER
# DER to PEM
openssl x509 -in cert.der -out cert.pem -inform DER -outform PEM
# PEM private key to DER
openssl rsa -in private.key -out private.der -outform DER
# Bundle key + cert + chain into PKCS#12 (for Java keystores, IIS, Cloudflare)
openssl pkcs12 -export -in cert.pem -inkey private.key -certfile chain.pem \
-out bundle.p12 -name "myapp"
# Extract just the certificate from a PKCS#12
openssl pkcs12 -in bundle.p12 -nokeys -out cert.pem
# Extract just the private key from a PKCS#12
openssl pkcs12 -in bundle.p12 -nocerts -nodes -out private.keyEncrypting and Decrypting Files
openssl can symmetrically encrypt files using AES. This is useful for protecting backup files, sensitive configuration, or any file that needs to be stored or transmitted securely:
# Encrypt a file with AES-256-CBC (prompts for password)
openssl enc -aes-256-cbc -pbkdf2 -salt -in secrets.txt -out secrets.enc
# Decrypt the file
openssl enc -aes-256-cbc -pbkdf2 -d -in secrets.enc -out secrets.txt
# Encrypt with a password provided on the command line (avoid on shared systems)
openssl enc -aes-256-cbc -pbkdf2 -salt -k "mypassphrase" -in file.txt -out file.enc
# Generate a SHA-256 hash of a file
openssl dgst -sha256 file.txt
# Generate HMAC-SHA256 of a file with a key
openssl dgst -sha256 -hmac "secretkey" file.txtAlways use -pbkdf2 with openssl enc. Without it, openssl uses a legacy key derivation function that is weak by modern standards. The -pbkdf2 flag uses PBKDF2 with a high iteration count, making brute-force attacks against the passphrase much harder.
Generating Random Values
openssl's rand subcommand generates cryptographically secure random bytes. This is the right tool when you need a random API key, session secret, or password — not /dev/urandom directly (though it reads from the same source) because openssl's output formatting options make it easier to use in scripts:
# 32 random bytes in base64 (~44 characters, suitable for secrets)
openssl rand -base64 32
# 32 random bytes in hex (64 characters)
openssl rand -hex 32
# Generate a random 20-character alphanumeric password
openssl rand -base64 20 | tr -d '+/=' | cut -c1-20
# Generate a random database password
openssl rand -base64 24 | tr -d '+/='I use openssl rand -hex 32 constantly — for Django SECRET_KEY, for API keys, for IndexNow keys, for any situation where I need a random secret that I can type into a configuration file. It is faster and more readable than using Python's secrets module from the command line, and it is available on every server without requiring Python.
Common Mistakes
The most common mistake is forgetting the -noout flag when reading a certificate. Without it, openssl outputs the certificate in PEM format after the text output, which can be confusing or cause issues if you are piping the output somewhere. Always add -noout unless you specifically want the PEM output.
A second frequent error is mismatching the private key and certificate. After generating a key and getting a certificate signed, always verify that the modulus (or public key hash) matches between the key file and the certificate file before installing them on a server. If they do not match, nginx and Apache will fail to start with a cryptic SSL error.
When testing TLS connections with s_client, be aware that the tool does not exit on its own — it waits for input after connecting. Pipe echo into it or use echo | openssl s_client ... to make it connect and exit immediately, which is what you want for scripted certificate checks.
Tips and Best Practices
- Always run
openssl verifyon newly issued certificates before deploying them to production. A verification failure means the chain is incomplete or the CA is not trusted. - Keep your private keys at
chmod 600(readable only by root or the web server user) and never commit them to version control, ever. - Set up monitoring for certificate expiry. A script that runs
openssl s_clientandx509 -checkendweekly is enough to catch expiring certs before they cause outages. - For Let's Encrypt and other ACME-based certificates, use Certbot or acme.sh rather than managing certificates manually with openssl.
- When generating CSRs for production, use a key length of at least 4096 bits for RSA or P-256 for EC.
- Use
-addext "subjectAltName=..."when creating CSRs rather than relying on the CN field. Modern browsers require SANs. - For internal services that do not have public DNS, create an internal CA, install its root certificate in all internal browsers and OS trust stores, and sign certs with it. This gives you proper TLS on internal services without self-signed cert warnings.
Final Thoughts
openssl is a dense toolkit that does far more than most people use it for. But the commands that matter in daily infrastructure work are a manageable set: generate a key with genrsa or genpkey, create a CSR with req -new, inspect a certificate with x509 -text -noout, test a live server with s_client -connect, verify the chain with verify, and generate secrets with rand. These six capabilities cover the vast majority of certificate-related work a server administrator encounters.
The investment in learning openssl pays off every time a TLS error appears and you can diagnose it in two minutes rather than spending an hour guessing. Certificate problems are a regular part of managing infrastructure — expired certs, mismatched keys, incomplete chains, wrong SANs — and being fluent with openssl means none of these are mysterious.
FAQ: openssl Command in Linux
How do I check an SSL certificate expiry date with openssl?+
Run: echo | openssl s_client -connect domain.com:443 2>/dev/null | openssl x509 -noout -dates. This connects to the live server and prints the notBefore and notAfter dates of the certificate it presents.
How do I generate a self-signed certificate with openssl?+
Run: openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes -subj '/CN=localhost'. This generates a key and self-signed certificate valid for 365 days with no passphrase on the key.
How do I test if a TLS connection is working with openssl?+
Use openssl s_client -connect hostname:port. For HTTPS: openssl s_client -connect example.com:443. This shows the full TLS handshake, the certificate chain, and whether the connection succeeded.
How do I view the contents of a certificate file with openssl?+
Run: openssl x509 -in cert.pem -text -noout. This prints the full certificate in human-readable form: subject, issuer, validity dates, Subject Alternative Names, public key, and signature algorithm.
How do I generate a random password or secret with openssl?+
Run openssl rand -base64 32 for a 32-byte random value in base64 (about 44 characters), or openssl rand -hex 32 for 64 hex characters. Both are cryptographically random and suitable for passwords, API keys, or session secrets.
Need help with Linux servers or infrastructure?
Work directly with Muhammad Irfan Aslam for Linux, Ubuntu, Docker, DevOps, cloud, CI/CD, or infrastructure support.
Hire Me for Support