Create and Check a Subject Alternative Name CSR with openssl req
You will generate a PKCS#10 certificate signing request (CSR) containing two DNS names, keep its private key separate, and verify the request before sending it to a certificate authority. The examples use OpenSSL 3.0.13 from the installed openssl package. Allow about fifteen minutes if you already know the names the certificate must cover.
The route
Jump straight to the step you need, or tick off Done means at the end.
You need a shell, the openssl package, and a directory where the private key can be protected. This workflow does not need sudo. A CSR is not a certificate and does not make a service trusted by itself.
1. Choose the names and output files
Write down every DNS name that the eventual certificate must cover. Put those names in the Subject Alternative Name (SAN) extension. Modern TLS clients check SAN rather than relying on the Common Name alone.
Use a new working directory and restrictive permissions. Do not put the private key in a shared temporary directory or a source-control checkout.
$ umask 077
$ mkdir -p ~/private/example-csr
$ cd ~/private/example-csr
Checkpoint: pwd should show the directory where you intend to keep the key and CSR. The private key will be written to api.example.test.key; the request will be written to api.example.test.csr.
2. Generate the key and CSR
Run this as one command. It creates a 2048-bit RSA key, prompts for a passphrase for that key, and adds both DNS names to the request.
$ openssl req -new -newkey rsa:2048 \
-keyout api.example.test.key \
-out api.example.test.csr \
-subj '/C=GB/O=Example Operations/CN=api.example.test' \
-addext 'subjectAltName = DNS:api.example.test,DNS:api.internal.example.test'
During key generation, OpenSSL asks for a PEM passphrase. Choose one that is not reused elsewhere and store it in your normal password-management system. The CSR itself is normally shareable, but the key is not. If a CA or service specifically requires an unencrypted key, use -noenc deliberately and protect the file with filesystem permissions; do not use the deprecated -nodes spelling on OpenSSL 3.
The -subj value uses slash-separated attributes. It is only the subject name. The -addext option is repeated when you need more extensions and takes the same key-value form used in an OpenSSL configuration file. The SAN value above is an extension in the CSR, not a promise that a CA will issue those names.
Checkpoint: both files should exist, and the key should be readable only by you.
$ ls -l api.example.test.key api.example.test.csr
-rw------- 1 you you ... api.example.test.csr
-rw------- 1 you you ... api.example.test.key
The exact sizes and owner names vary. If the command failed, do not send an incomplete CSR to a CA. Read the first error, check the working directory, and rerun with a new output name if either file may have been overwritten.
3. Verify the CSR signature
A CSR is self-signed with the private key corresponding to the public key it contains. Verify that signature before submitting it:
$ openssl req -in api.example.test.csr -noout -verify
Certificate request self-signature verify OK
The command exits successfully when the request signature verifies. This proves that the CSR is internally consistent. It does not prove that you control either DNS name or that a CA will approve the request.
Checkpoint: if verification fails, stop. Keep the original key and CSR for investigation, then generate a fresh pair rather than trying to repair the request as text.
4. Inspect the subject and SAN values
Print the fields that matter to a normal TLS request without dumping the encoded request:
$ openssl req -in api.example.test.csr -noout -subject
subject=C=GB, O=Example Operations, CN=api.example.test
$ openssl req -in api.example.test.csr -noout -text \
| grep -A2 -E 'Subject Alternative Name|Public Key Algorithm'
Public Key Algorithm: rsaEncryption
X509v3 Subject Alternative Name:
DNS:api.example.test, DNS:api.internal.example.test
On this OpenSSL build, the text output labels the extension X509v3 Subject Alternative Name. Check every name character by character. A typo in a SAN is an issuance or deployment problem, not something TLS will silently correct.
If you use a different shell or a system without grep, omit the pipe and inspect the complete output:
$ openssl req -in api.example.test.csr -noout -text
5. Submit only the CSR
Send api.example.test.csr through the CA's documented enrolment process. Never send api.example.test.key. The CA may ask you to prove control of the SAN names by DNS or HTTP; complete that challenge through the CA, not by adding private material to the request.
If the CA returns a certificate, inspect that certificate separately. A CA can reject an extension, issue a different validity period, or return a certificate with names that do not match your request. Compare the issued certificate's SAN extension with the request before installing it.
6. Use a configuration file when the request is repeatable
Command-line -subj and -addext are convenient for one request. For a repeatable process, put the distinguished name and extensions in a file that is reviewed and kept with the process documentation.
[ req ]
prompt = no
distinguished_name = request_dn
req_extensions = request_extensions
[ request_dn ]
C = GB
O = Example Operations
CN = api.example.test
[ request_extensions ]
subjectAltName = DNS:api.example.test,DNS:api.internal.example.test
Save it as request.cnf, then generate the request with:
$ openssl req -new -newkey rsa:2048 \
-config request.cnf \
-keyout api.example.test.key \
-out api.example.test.csr
By default, openssl req uses the req section. Use -section NAME when the file contains another request section. Keep the configuration file free of private-key passwords. If you must automate a password, use the passphrase-source options documented for your deployment rather than placing a secret directly in a command line or checked-in file.
Common traps and recovery
- The command asks questions unexpectedly: add
-subj, useprompt = noin the configuration, or add-batchfor a deliberately non-interactive run. Do not answer prompts with guessed values. - The SAN is missing: inspect with
-text. A Common Name does not replace SAN. Add-addextor areq_extensionssection, then regenerate the CSR. - The key was printed on screen: this can happen when a new key is generated without
-keyout. Treat the displayed key as exposed, do not use it, and generate a replacement with an explicit private output path. - You need to undo a test request: delete the CSR and key only after checking that no CA application or service still needs them. Deleting the key is irreversible for that key pair and may make an issued certificate unusable.
Done means
- The CSR contains the intended subject and every required SAN.
openssl req -noout -verifyreports that the self-signature verifies.- The private key is encrypted or has an explicitly chosen, restrictive protection model.
- Only the CSR was submitted to the CA; the private key remains private.
- The issued certificate, when returned, has been inspected rather than assumed to match the request.