Create a CSR Using OpenSSL: Keys, SANs, Verification, and Deployment

· Published · 16 min read

A private key remains protected while its certificate request travels to a certificate authority and the signed certificate returns to a TLS server

A certificate signing request is the handoff between a private key you control and a certificate authority that verifies the requested identity. The command is short. The work around it matters more: choosing every required name, protecting the key, checking the request before submission, and proving that the returned certificate belongs to that key.

This guide uses OpenSSL 3 commands and documentation names such as www.example.com. Run the workflow on an approved administrative host, not on a shared shell or an untrusted web form. A public certificate authority receives the CSR. It must never receive the private key.

Understand the four files before creating them

ItemMay be shared?Purpose
Private key, such as www.example.com.keyNoProves control of the certificate's public key and enables the server to establish TLS sessions.
CSR, such as www.example.com.csrYes, with the certificate authorityContains the public key, requested subject information, requested extensions, and a signature made by the private key.
Issued leaf certificateYesBinds the approved names to the public key for a defined validity period.
Intermediate certificate chainYesConnects the leaf certificate to a root trusted by clients. A server normally sends the leaf and intermediate certificates, not the root.

A CSR is not a certificate and has no usable certificate expiry date. Creating one does not prove control of a domain to a public CA, install TLS, or authorize every requested name. Those steps happen in the CA and deployment workflows.

Generate the key where TLS actually terminates

A familiar file path is not automatically the right place for a key. Find the component that presents the certificate to clients. It may be Apache or Nginx, but it may instead be a reverse proxy, hardware appliance, Kubernetes ingress controller, CDN, cloud load balancer, or managed application platform. Creating a key on the web server is pointless when a load balancer owns the TLS session.

Termination modelPreferred key workflowImportant check
Apache or Nginx on a controlled hostGenerate locally or deliver through the approved secrets systemThe root-owned service process can read the key, while application users cannot.
Cloud load balancer or managed certificate serviceUse the platform's certificate request, import, or managed issuance processKnow whether the platform generates a non-exportable key or requires a key and chain import.
Hardware security module or enterprise key managerGenerate the key inside the device and produce the CSR through its provider interfaceDo not create a temporary software key that defeats the non-exportable-key requirement.
Kubernetes ingressUse the approved certificate controller or secrets workflowRestrict secret read access, encryption at rest, backup access, namespace access, and logs.
External CDN or security proxyFollow its edge-certificate workflow and separately protect the origin certificateConfirm both the public edge-to-client certificate and the CDN-to-origin trust path.

Decide whether the key must be exportable before creating it. A non-exportable platform key can reduce theft risk but changes disaster recovery and migration. An exportable key requires a documented secret-storage, backup, access-review, rotation, and destruction process. Record which people and automation identities can retrieve it.

For high-availability servers, do not manually generate unrelated keys on every node unless the certificate design supports that model. The certificate installed on each endpoint must match its local key. Distribute one approved key through a secure secret system or issue separate certificates through controlled automation.

Inventory the names and certificate endpoint

Start from the application and load-balancer configuration. Record the exact DNS names clients use, where TLS terminates, who controls validation, whether a wildcard is justified, and which team owns renewal. Modern hostname matching uses the Subject Alternative Name extension, so put every required hostname in the SAN list.

RequirementExampleDecision
Apex nameexample.comAdd it explicitly. A wildcard does not cover the apex.
Web hostnamewww.example.comAdd it when users or redirects connect to this name.
Single-label wildcard*.example.comUse only when the CA and risk owner approve it. It covers names such as api.example.com, not v2.api.example.com.
Internal-only nameapp.internal.exampleUse an internal PKI or platform certificate workflow that owns this namespace.
IP address192.0.2.10Request it as an IP SAN only when the issuing CA supports the address and use case.

Do not add unrelated production names “for later.” Every SAN expands the certificate's scope and validation burden. Separate certificates can give unrelated services smaller failure and key-compromise boundaries.

Check OpenSSL and create a protected workspace

openssl version -a
openssl req -help 2>&1 | grep -E -- '-addext|-noenc'

sudo install -d -m 0700 -o root -g root \
  /etc/pki/tls/private/www.example.com
cd /etc/pki/tls/private/www.example.com
umask 077
pwd
ls -ld .

The directory and umask protect newly created files from other local users. On a host where a deployment service owns TLS material, replace root:root with the approved account and the narrowest working permissions. Do not make a key world-readable just to solve a service startup error.

Unsafe: generating a new key over an existing filename can break the certificate currently in service. Before every run, confirm the target names are unused or create a dated working directory. Back up an existing key only into an encrypted, access-controlled secret store.

Choose an RSA or ECDSA key deliberately

RSA 2048 remains a broadly interoperable starting point. RSA 3072 provides a larger security margin with more CPU and larger handshakes. ECDSA with the P-256 curve produces smaller keys and signatures, but every client, TLS terminator, certificate authority, and operational tool in the path must support it. Follow the issuing CA and platform policy when it is stricter.

# RSA 2048 private key
openssl genpkey -algorithm RSA \
  -pkeyopt rsa_keygen_bits:2048 \
  -out www.example.com.key

# Alternative: ECDSA P-256 private key
openssl genpkey -algorithm EC \
  -pkeyopt ec_paramgen_curve:prime256v1 \
  -pkeyopt ec_param_enc:named_curve \
  -out www.example.com-ecdsa.key

chmod 0600 www.example.com.key
openssl pkey -in www.example.com.key -check -noout

Use one algorithm for the active workflow, not both commands blindly. The final check parses the private key and verifies its internal consistency. It does not prove that the file has been backed up, belongs to the intended service, or matches a certificate.

Encrypted key for an operator-controlled workflow

openssl genpkey -algorithm RSA \
  -aes-256-cbc \
  -pkeyopt rsa_keygen_bits:2048 \
  -out www.example.com-encrypted.key

chmod 0600 www.example.com-encrypted.key
openssl pkey -in www.example.com-encrypted.key -check -noout

An encrypted key is useful when a person or managed secret mechanism can supply the passphrase. An unattended web server may need a non-interactive key stored behind strict filesystem, host, and backup controls. Never place the passphrase in the command line, shell history, unit file, container image, source repository, or CSR.

Create a CSR with SANs on the command line

For a small, one-time request, -subj and -addext keep the request visible and avoid interactive typing mistakes.

openssl req -new -sha256 \
  -key www.example.com.key \
  -out www.example.com.csr \
  -subj '/C=IN/ST=Maharashtra/L=Mumbai/O=Example Pvt Ltd/OU=Web Operations/CN=www.example.com' \
  -addext 'subjectAltName=DNS:example.com,DNS:www.example.com' \
  -addext 'keyUsage=critical,digitalSignature,keyEncipherment' \
  -addext 'extendedKeyUsage=serverAuth'

chmod 0644 www.example.com.csr

The Common Name is kept for administrative clarity, but the SAN list carries the hostnames. Use organization fields that match the certificate type and CA instructions. Domain-validated certificates may not reproduce all subject fields in the issued certificate. Do not invent legal-entity information.

The RSA example requests keyEncipherment. An ECDSA server request normally uses digitalSignature without keyEncipherment. Some public CAs construct certificate extensions from policy rather than copying every requested extension, so treat the CSR as a request, then inspect the certificate that is actually issued.

Create the key and CSR in one current command

This is convenient for automation that intentionally uses an unencrypted service key. The -noenc option is explicit: the output key has no passphrase and therefore depends entirely on host and secret-storage controls.

umask 077
openssl req -new -newkey rsa:2048 -noenc -sha256 \
  -keyout www.example.com.key \
  -out www.example.com.csr \
  -subj '/C=IN/ST=Maharashtra/L=Mumbai/O=Example Pvt Ltd/OU=Web Operations/CN=www.example.com' \
  -addext 'subjectAltName=DNS:example.com,DNS:www.example.com' \
  -addext 'keyUsage=critical,digitalSignature,keyEncipherment' \
  -addext 'extendedKeyUsage=serverAuth'

chmod 0600 www.example.com.key
chmod 0644 www.example.com.csr

Unsafe if unmanaged: -noenc is useful for a service that must restart unattended, but anyone who obtains the file can use the private key. Restrict the directory, backups, configuration-management artifacts, support bundles, and administrator access. Prefer a platform key store, HSM, KMS-backed integration, or managed certificate service when the endpoint supports it.

Use a configuration file for repeatable SAN lists

A reviewed configuration file is easier to maintain when several names or environments are involved. Create www.example.com.cnf with these contents:

[ req ]
prompt = no
utf8 = yes
default_md = sha256
distinguished_name = subject
req_extensions = request_extensions

[ subject ]
C = IN
ST = Maharashtra
L = Mumbai
O = Example Pvt Ltd
OU = Web Operations
CN = www.example.com

[ request_extensions ]
subjectAltName = @alt_names
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth

[ alt_names ]
DNS.1 = example.com
DNS.2 = www.example.com
# Add only when an approved wildcard is required:
# DNS.3 = *.example.com
# IP.1 = 192.0.2.10
chmod 0644 www.example.com.cnf
openssl req -new -sha256 \
  -key www.example.com.key \
  -out www.example.com.csr \
  -config www.example.com.cnf

Number repeated SAN types as DNS.1, DNS.2, and so on. A repeated unnumbered key in one OpenSSL section can replace the earlier value. Keep production identities outside a public repository when the inventory itself is sensitive.

Use the interactive workflow when policy requires it

The original operational sequence remains valid as a manual workflow: make a protected directory, generate a key, restrict it, and then answer the Distinguished Name prompts.

sudo install -d -m 0700 \
  /etc/httpd/conf/ssl/csr/www.example.com
cd /etc/httpd/conf/ssl/csr/www.example.com
umask 077

openssl genpkey -algorithm RSA \
  -pkeyopt rsa_keygen_bits:2048 \
  -out www.example.com.key
chmod 0600 www.example.com.key

openssl req -new -sha256 \
  -key www.example.com.key \
  -out www.example.com.csr \
  -addext 'subjectAltName=DNS:example.com,DNS:www.example.com'

Enter the approved country, state, locality, organization, organizational unit, and common name when prompted. Leave challenge password and optional company fields empty unless the issuing CA explicitly requires them. A forgotten CSR challenge password can obstruct a CA workflow without adding useful protection to the private key.

Inspect and verify the CSR before submission

openssl req -in www.example.com.csr -noout -verify
openssl req -in www.example.com.csr -noout \
  -subject -nameopt RFC2253
openssl req -in www.example.com.csr -noout -text

Review the subject, public-key algorithm and size, signature algorithm, requested SAN extension, key usage, and extended key usage. The verify command proves that the CSR signature matches its embedded public key. It does not validate the domain or organization.

For a change record, save a public-key fingerprint rather than copying the private key:

openssl req -in www.example.com.csr -pubkey -noout \
  | openssl pkey -pubin -outform DER \
  | openssl dgst -sha256

openssl pkey -in www.example.com.key -pubout -outform DER \
  | openssl dgst -sha256

The two SHA-256 values must be identical. A passphrase-protected key will prompt securely when OpenSSL reads it. Do not automate the prompt by exposing its passphrase in a process argument.

Submit only the CSR

cat www.example.com.csr

Copy the complete PEM block beginning with BEGIN CERTIFICATE REQUEST and ending with END CERTIFICATE REQUEST into the CA's approved portal or enrollment process. Preserve its line breaks. Sharing a CSR is expected, although it can reveal requested names and organization information.

Unsafe: never upload or paste www.example.com.key into a CA portal, ticket, chat, email, paste site, or “CSR decoder.” If a service says it must receive the private key merely to issue a certificate, stop and verify the workflow with the security owner.

Validate the issued certificate and its key

Save the returned leaf certificate as www.example.com.crt and the issuer-provided intermediate chain separately. Inspect what the CA issued rather than assuming it copied the CSR.

openssl x509 -in www.example.com.crt -noout \
  -subject -issuer -serial -dates -fingerprint -sha256
openssl x509 -in www.example.com.crt -noout \
  -ext subjectAltName -ext keyUsage -ext extendedKeyUsage

openssl x509 -in www.example.com.crt -pubkey -noout \
  | openssl pkey -pubin -outform DER \
  | openssl dgst -sha256

openssl pkey -in www.example.com.key -pubout -outform DER \
  | openssl dgst -sha256

The final two fingerprints must match. Confirm every required SAN, the issuer, validity window, key usage, signature algorithm, and certificate policy. Reject an unexpected name or key before deployment.

# Use the root supplied by the CA or your internal PKI for this explicit test.
openssl verify -purpose sslserver \
  -CAfile root-ca.pem \
  -untrusted intermediate-chain.pem \
  www.example.com.crt

For a public certificate, also test from clients that use normal operating-system and browser trust stores. A local root file can prove one chain while missing what actual clients trust.

Convert formats only when the endpoint requires it

PEM is text encoded between boundary lines and is common on Unix-like web servers. DER is a binary representation used by some appliances and APIs. PKCS#12 packages a certificate, private key, and optional chain into one encrypted file for platforms that import a bundle. Conversion does not repair a wrong key, missing SAN, or invalid chain, so perform the matching and verification checks first.

Convert a CSR between PEM and DER

openssl req -in www.example.com.csr \
  -outform DER -out www.example.com.csr.der

openssl req -inform DER -in www.example.com.csr.der \
  -outform PEM -out www.example.com-roundtrip.csr

openssl req -in www.example.com-roundtrip.csr \
  -noout -verify -subject

The DER CSR remains safe to submit, but it is not readable with cat. Name the format clearly in a ticket so an operator does not mistake a binary file for corruption.

Create an encrypted PKCS#12 deployment bundle

umask 077
openssl pkcs12 -export \
  -inkey www.example.com.key \
  -in www.example.com.crt \
  -certfile intermediate-chain.pem \
  -name www.example.com \
  -out www.example.com.p12

chmod 0600 www.example.com.p12
openssl pkcs12 -in www.example.com.p12 -info -noout

OpenSSL prompts for an export password and then prompts again during inspection. Transfer the password through a separate approved secret channel. A PKCS#12 file contains the private key, so protect it exactly like the original key and remove temporary copies after the receiving platform has been verified.

Unsafe: options that place passwords directly in commands can expose them through shell history, process inspection, logs, CI output, or monitoring. Do not use an empty export password merely to make an import convenient. If unattended automation is required, inject the secret through the platform's protected secret mechanism and ensure the command itself is not echoed.

Use self-signed certificates only inside an explicit trust design

A self-signed certificate can prove that a test server loads a key and speaks TLS. It is not a substitute for a publicly trusted certificate, and distributing ad hoc roots to users creates a long-lived trust problem. For an internal service, use an owned internal PKI with issuance policy, short validity, revocation or replacement procedures, protected CA keys, and managed trust distribution.

# Lab-only endpoint certificate, valid for seven days.
openssl req -new -x509 -days 7 -sha256 \
  -key www.example.com.key \
  -out www.example.com-lab.crt \
  -subj '/CN=www.example.com' \
  -addext 'subjectAltName=DNS:www.example.com' \
  -addext 'basicConstraints=critical,CA:FALSE' \
  -addext 'keyUsage=critical,digitalSignature,keyEncipherment' \
  -addext 'extendedKeyUsage=serverAuth'

openssl x509 -in www.example.com-lab.crt -noout \
  -subject -issuer -dates -ext subjectAltName

Unsafe outside the lab: browsers and normal clients will not trust this certificate unless someone installs it as trusted material. Do not disable client verification to hide that failure, and do not mark an endpoint certificate as CA:TRUE. Use the organization's PKI or a public CA for real users.

Install without exposing the key

Build the full chain in the order expected by the server and CA documentation. Do not append the private key or root certificate to the public chain file.

cat www.example.com.crt intermediate-chain.pem \
  > www.example.com-fullchain.pem
chmod 0644 www.example.com.crt www.example.com-fullchain.pem
chmod 0600 www.example.com.key

# Restore distribution security labels when SELinux is in use.
sudo restorecon -Rv /etc/pki/tls/private/www.example.com

Nginx

server {
    listen 443 ssl;
    server_name example.com www.example.com;

    ssl_certificate     /etc/pki/tls/private/www.example.com/www.example.com-fullchain.pem;
    ssl_certificate_key /etc/pki/tls/private/www.example.com/www.example.com.key;
}
sudo nginx -t
sudo systemctl reload nginx

Apache HTTP Server

<VirtualHost *:443>
    ServerName www.example.com
    ServerAlias example.com
    SSLEngine on
    SSLCertificateFile /etc/pki/tls/private/www.example.com/www.example.com-fullchain.pem
    SSLCertificateKeyFile /etc/pki/tls/private/www.example.com/www.example.com.key
</VirtualHost>
sudo apachectl configtest
sudo systemctl reload httpd

Debian-family systems commonly use the apache2 service name. A load balancer, ingress controller, cloud certificate manager, or secrets operator has a different installation workflow; do not copy server files into a container image or source repository.

Test the deployed endpoint

openssl s_client \
  -connect www.example.com:443 \
  -servername www.example.com \
  -verify_hostname www.example.com \
  -verify_return_error \
  -showcerts </dev/null

curl -sS -I https://www.example.com/

Check the verification return code, hostname, leaf certificate, intermediate chain, validity, negotiated protocol, and application response. Repeat for every public hostname in the SAN list and from representative networks. SNI is essential when several certificates share one address.

Unsafe as an acceptance test: openssl s_client without -verify_return_error, or curl -k, can continue despite trust problems. Those modes can isolate a fault during an authorized investigation, but they do not prove a safe deployment.

Renew and rotate without losing rollback

Inventory expiry and renewal ownership before installation. For manually managed certificates, alert well before the CA's renewal window closes. ACME or a managed certificate service is usually safer for repeatable public certificate renewal than a calendar reminder and a copied CSR.

Whether to reuse a private key is a policy decision. A new key reduces the duration of one key's exposure but requires a careful key and certificate swap. If the key may be compromised, generate a new key and follow the issuer's revocation process immediately.

  1. Create the new key and CSR under new filenames.
  2. Verify the CSR, submit it, and validate the returned certificate and chain.
  3. Prove the new certificate matches the new key.
  4. Back up the active configuration and record its certificate fingerprint.
  5. Update configuration atomically, run the server's configuration test, and reload.
  6. Test externally before closing the change.
  7. Retain the prior certificate, key, and configuration in protected storage through the rollback window, then dispose of them under key-retention policy.

Unsafe: deleting or overwriting the active key before the new endpoint passes validation can turn a certificate change into an outage. A rollback needs the matching prior certificate and key, not either file by itself.

Troubleshoot from the exact boundary

SymptomCheckLikely cause
unable to load Private Keyopenssl pkey -in file.key -check -nooutWrong path, permissions, passphrase, format, or damaged file
CSR verification failureopenssl req -in file.csr -noout -verify -textDamaged CSR or invalid signature
SAN is missingInspect Requested Extensions in the CSR-addext, req_extensions, section name, or config file was omitted
Certificate and key do not matchCompare DER public-key SHA-256 fingerprintsWrong key selected or certificate returned for a different request
Browser reports name mismatchInspect issued SANs and the hostname in the URLRequired DNS name absent, wrong certificate served, or SNI routing error
Browser reports incomplete chains_client -showcerts and CA chain instructionsIntermediate missing, wrong order, or unrelated intermediate
Server cannot read a correct keyService logs, ownership, mode, SELinux/AppArmor policyRuntime access control rather than cryptographic failure
Reload succeeds but old certificate remainsResolve DNS, inspect remote address and certificate fingerprintAnother load balancer, proxy, CDN, process, or virtual host terminates TLS

Completion record

  • The TLS termination point, owner, CA, validation method, renewal method, and rollback owner are recorded.
  • Every required apex, host, wildcard, and IP identity has an explicit decision.
  • The private key was generated in a protected location and never left the approved trust boundary.
  • The CSR signature, subject, SANs, algorithm, key size, usage, and public-key fingerprint were checked.
  • Only the CSR was submitted to the CA.
  • The issued certificate's names, issuer, dates, usage, chain, policy, and key match were checked.
  • The server configuration test passed before reload, and the deployed endpoint passed hostname and chain verification.
  • Monitoring, renewal, revocation, key rotation, protected backup, and rollback are owned.

Primary references

Related technical notes

Technical review

Need this checked against your own sending system?

Share the domain, headers, bounces, provider warning, logs, or infrastructure symptom and NitWings will identify the practical next step.

Schedule a Technical Review
Advertisement