# Generate a CSR with OpenSSL (RSA and ECDSA, with SANs)

> Create a private key and CSR with one OpenSSL command, add subjectAltName entries, choose RSA 2048 or ECDSA P-256, and verify the request.

Source: https://ssl.sh/guides/generate-csr-openssl/
Last updated: 2026-11-10

One `openssl req -new -newkey` command creates both the private key and the certificate signing request (CSR), with the names in `-addext "subjectAltName=..."`. Check the CSR with `openssl req -verify`, then paste it into the CA's order form.

The commands apply to OpenSSL 3.x on Linux, macOS and Windows; notes cover OpenSSL 1.1.1 where options differ.

## Prerequisites

You need OpenSSL and the exact host names the certificate must cover.

- OpenSSL 3.x (`openssl version`). OpenSSL 1.1.1 works with `-nodes` instead of `-noenc`; 1.0.2 lacks `-addext` and should be upgraded.
- The list of names: every host name visitors use, for example `example.com` and `www.example.com`.
- A secure place to keep the private key; generate it on the server that will use it when you can.

## Step 1: Generate an ECDSA key and CSR

This command writes an unencrypted P-256 key and a CSR for `example.com` and `www.example.com`:

```bash
openssl req -new -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -noenc \
  -keyout example.com.key -out example.com.csr \
  -subj "/CN=example.com" \
  -addext "subjectAltName=DNS:example.com,DNS:www.example.com"
chmod 600 example.com.key
```

## Step 2 (alternative): Generate an RSA key and CSR

An RSA request uses the same command with an `rsa:2048` key instead of the EC options:

```bash
openssl req -new -newkey rsa:2048 -noenc \
  -keyout example.com.key -out example.com.csr \
  -subj "/CN=example.com" \
  -addext "subjectAltName=DNS:example.com,DNS:www.example.com"
chmod 600 example.com.key
```

Use `rsa:3072` if your policy requires it. For a wildcard, list `DNS:*.example.com,DNS:example.com`.

## Step 3: Use a config file for many names

A config file keeps long SAN lists and repeatable requests out of the command line:

```ini
# example.com.cnf
[req]
prompt = no
distinguished_name = dn
req_extensions = ext

[dn]
CN = example.com

[ext]
subjectAltName = DNS:example.com,DNS:www.example.com,DNS:api.example.com
```

```bash
openssl req -new -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -noenc \
  -keyout example.com.key -out example.com.csr -config example.com.cnf
```

## Step 4: Submit the CSR

Copy the whole file, including the `-----BEGIN CERTIFICATE REQUEST-----` and `-----END CERTIFICATE REQUEST-----` lines, into your CA's order form:

```bash
cat example.com.csr
```

Keep `example.com.key` on the server. The CA never needs it. If you prefer a form, the [CSR generator](https://ssl.sh/tools/csr-generator/) creates the key and CSR in your browser without uploading the key.

## Verify

A valid CSR passes the signature check and lists every name you need under Subject Alternative Name. Check the signature, subject and SANs:

```bash
openssl req -in example.com.csr -noout -verify -subject
openssl req -in example.com.csr -noout -text | grep -A1 "Subject Alternative Name"
```

Confirm the key and CSR belong together (the two hashes must match):

```bash
openssl pkey -in example.com.key -pubout | openssl sha256
openssl req -in example.com.csr -noout -pubkey | openssl sha256
```

The [CSR decoder](https://ssl.sh/tools/csr-decoder/) and [key matcher](https://ssl.sh/tools/key-matcher/) do the same checks in the browser. Once the certificate is installed, verify the live site with the [SSL checker](https://ssl.sh/tools/ssl-checker/) or `curl ssl.sh/example.com`.

## Automatic renewal

A CSR is a one-off artefact; renewal means a new CSR. Public certificates are limited to 200 days since March 15, 2026, 100 days from March 15, 2027 and 47 days from March 15, 2029, so a manual "generate CSR, paste, wait, install" cycle will soon run every few weeks. Where possible, let an ACME client generate keys and CSRs for you: Certbot, acme.sh and lego create a fresh key on every renewal, and many commercial CAs accept ACME with External Account Binding. If you must stay manual, script Steps 1 to 4 and add the host to [ssl.sh monitoring](https://ssl.sh/monitor/) (in development).

## Troubleshooting

- **req: Unknown option or cipher: noenc**: you are on OpenSSL 1.1.1; use `-nodes`.
- **CA says the CSR has no SAN or the wrong names**: the `-addext` was dropped or mistyped; decode the CSR and regenerate.
- **Browser reports a name mismatch after install**: a host name was missing from the SAN list; see [NET::ERR_CERT_COMMON_NAME_INVALID](https://ssl.sh/errors/net-err-cert-common-name-invalid/).
- **Server reports key values mismatch**: the certificate was issued for a different CSR/key; see [nginx key values mismatch](https://ssl.sh/errors/nginx-key-values-mismatch/).
- **CA rejects the key**: RSA keys below 2048 bits and unsupported curves are refused; use P-256 or RSA 2048+.
