How to Generate a CSR (Certificate Signing Request) the Right Way

I’ve gone through the CSR generation process dozens of times across different servers, operating systems, and environments. And every time I thought it was straightforward, I ran into some edge case that tripped me up — a wrong key size, a missing SAN field, a passphrase that caused issues with the web server. So here’s everything I’ve learned, laid out in a practical way.

What a CSR Actually Is

A Certificate Signing Request is a block of encoded text you send to a Certificate Authority (CA) so they can issue an SSL/TLS certificate for you. It contains your public key and identity information — domain name, organization, country, and so on. The CA verifies this information, signs your public key with their private key, and hands you back a certificate.

The CSR itself doesn’t need to be kept secret. Your private key, on the other hand, absolutely does. If your private key leaks, you need to revoke the certificate and start over.

Generating a CSR with OpenSSL

OpenSSL is the standard tool for this on Linux. Here’s the most basic version:

openssl req -new -newkey rsa:2048 -nodes -keyout example.com.key -out example.com.csr

This does a few things at once: generates a new 2048-bit RSA private key (-newkey rsa:2048), skips the passphrase on the key (-nodes), writes the private key to example.com.key, and writes the CSR to example.com.csr.

You’ll be prompted to fill in the Distinguished Name (DN) fields — country, state, organization, and the Common Name (CN), which should be your domain name.

Why I skip the passphrase

-nodes means “no DES encryption” — it generates the private key without a passphrase. Some people argue you should always protect your keys with a passphrase, and that’s technically correct. But in practice, if your web server (Nginx, Apache) needs to read the key on startup, it’ll prompt for the passphrase every time the server restarts unless you set it up to cache the password somewhere. That becomes a hassle during automated deployments and reboots. I typically protect keys at the filesystem level (correct permissions, ideally a hardware key store) rather than with a passphrase.

Including Subject Alternative Names

Here’s where most tutorials skip an important detail. Since 2017, the Common Name field in a certificate is largely ignored by browsers — they look at the Subject Alternative Names (SAN) extension instead. If your CSR doesn’t include SANs, your certificate will work for the exact domain you specified, but you’ll have no way to add www or additional subdomains without a new cert.

To include SANs in your CSR, create a config file first:

[req]
default_bits       = 2048
prompt             = no
default_md         = sha256
distinguished_name = dn
req_extensions     = req_ext

[dn]

C = US ST = California L = San Francisco O = My Company Inc CN = example.com

[req_ext]

subjectAltName = @alt_names

[alt_names]

DNS.1 = example.com DNS.2 = www.example.com DNS.3 = api.example.com

Then generate the CSR referencing this config:

openssl req -new -newkey rsa:2048 -nodes \
  -keyout example.com.key \
  -out example.com.csr \
  -config csr.conf

This is the version I use by default now. The first time I submitted a CSR without SANs to a commercial CA, I got back a certificate that didn’t cover www.example.com — I had to reissue it. Lesson learned.

Generating a CSR from an Existing Private Key

If you already have a private key and just need a new CSR (for example, when renewing a certificate), you don’t need to generate a new key:

openssl req -new -key existing.key -out renewed.csr

Or with a config file:

openssl req -new -key existing.key -out renewed.csr -config csr.conf

Reusing an existing key is perfectly fine for renewals and can actually simplify certificate pinning scenarios.

RSA vs ECDSA Keys

I used to generate RSA-2048 keys by default. These days I often prefer ECDSA (Elliptic Curve) keys because they’re smaller and faster at the TLS handshake.

To generate an ECDSA CSR:

# Generate the private key
openssl ecparam -name prime256v1 -genkey -noout -out ec.key

# Generate the CSR
openssl req -new -key ec.key -out ec.csr -config csr.conf

prime256v1 is the P-256 curve, which is widely supported. You can also use secp384r1 for P-384 if you need extra security margin.

A word of caution: some older systems and enterprise CA portals still expect RSA keys. If you’re submitting to an internal corporate CA, check what key types they accept before using ECDSA.

Verifying Your CSR Before Submission

Before sending your CSR to a CA, always verify it:

openssl req -text -noout -verify -in example.com.csr

This outputs all the fields and verifies that the CSR’s signature matches the private key. Check:

  • The Common Name is correct
  • The SANs are listed under X509v3 Subject Alternative Name
  • The key size is what you intended

I’ve caught typos in the domain name this way more than once. It’s much better to catch them before paying for a certificate.

On Windows with IIS

The Windows way is different. IIS has a built-in CSR generation wizard under Server Manager → IIS → Server Certificates → Create Certificate Request. It works fine for basic cases, but I’ve found it doesn’t easily support SANs in the CSR. For multi-domain certificates on Windows, I often just install OpenSSL for Windows and use the same commands above. See also: Installing SSL Certificates on Windows Server IIS.

What Happens to Your CSR After Submission

Once you submit the CSR to a CA, they extract your public key and identity information from it. They verify domain ownership (through email, HTTP file, or DNS challenge). Then they create a certificate containing your public key, signed with their private CA key. They send back the certificate (and usually an intermediate chain) for you to install.

Your private key never leaves your server. The CA never sees it. That’s the whole point of public-key cryptography.

A Few Things to Double-Check

Before you submit, run through this quick list:

  • Private key permissions are 600 (readable only by root or the web server user)
  • The CSR includes all the domains you need as SANs
  • You’ve stored the private key somewhere safe — if you lose it, you’ll need to reissue
  • If this is a wildcard cert (*.example.com), the CN and SAN should both say *.example.com — see Wildcard SSL vs Multi-Domain Certificates for when to choose each

One last thing: the CSR file itself is just a PEM-encoded block. You can paste it into a CA’s web form or provide it as a file. Either way works.


If you’re managing multiple certificates across many servers, keeping track of CSRs, keys, and expiry dates manually gets painful fast. Tools like crtmgr.com can help you generate and manage your certificates in one place without losing track of what’s installed where.

Scroll to Top