This tutorial shows you how to generate a CSR (Certificate Signing Request) for Heroku using OpenSSL and how to upload the issued certificate with the Heroku CLI.
Heroku has no built-in CSR form on the platform itself, so the request and the matching private key are generated off-platform (on your local Linux, macOS, or Windows machine, or in any shell with OpenSSL available). Once the Certificate Authority issues the certificate, you combine it with the intermediate chain and upload it through heroku certs:add.
Do you actually need a CSR on Heroku?
For most Heroku apps, the answer is no. Heroku’s Automated Certificate Management (ACM) provisions and auto-renews a free Let’s Encrypt certificate for every custom domain on the app, with no CSR to generate and no renewal calendar to maintain. ACM is available on Eco, Basic, Standard, and Performance dynos. If ACM fits your use case, enable it with a single CLI command:
heroku certs:auto:enable -a your-app-name
Generate a CSR and use a self-managed (third-party) certificate only when one of the following applies:
- You need a wildcard certificate. ACM issues only single-name Let’s Encrypt certificates per custom domain, not *.example.com.
- You need OV or EV validation. ACM is DV only.
- Your policy or contract requires a specific Certificate Authority other than Let’s Encrypt.
- You already own a valid certificate and want to redeploy it on Heroku without reissuing.
- You need a multi-domain (SAN) certificate covering hostnames that are not all on this Heroku app.
If none of the above is true, skip the CSR work and use ACM. For the install flow itself, see our guide on how to install an SSL certificate on Heroku.
Heroku SSL basics to know before you generate the CSR
A few platform constraints shape how the CSR and key need to look:
- SNI is the default. Every new app uses Heroku SSL, which relies on Server Name Indication, so a single Heroku endpoint can serve multiple HTTPS hostnames with their own certificates. The legacy SSL Endpoint add-on was deprecated in 2021 (new provisioning stopped on May 14, 2021; the product reached end of life on October 18, 2021) and is not available on new apps.
- RSA keys only. Heroku’s SSL stack accepts RSA private keys (2048 bits or larger). ECDSA keys are not supported for manual certificate uploads, so generate the CSR with -newkey rsa:2048 (or rsa:3072 / rsa:4096 if your policy requires a larger key).
- Fullchain PEM is required. Heroku expects a single PEM file with the end-entity certificate first and the intermediate CA bundle concatenated after it. A leaf-only certificate will be rejected during upload.
- Unencrypted private key. The key uploaded with the certificate cannot be passphrase-protected. The OpenSSL command below uses -nodes to write the key in clear PEM.
- Custom domain prerequisite. Heroku will not bind any certificate (ACM or manual) until the custom domain is registered with the app via
heroku domains:addand pointed at the per-domain *.herokudns.com DNS target.
Generate the CSR for Heroku with OpenSSL
If you already generated your CSR and received the signed certificate from your Certificate Authority, skip ahead to Upload the certificate to Heroku. You have two ways to create a CSR for a Heroku deployment:
- Use the SSL Dragon CSR Generator: it produces both the CSR and the matching RSA private key in your browser from a short form, then you paste the CSR during your SSL order.
- Generate the CSR yourself with OpenSSL, either on your local machine or in any shell where OpenSSL is installed. The steps below cover this path.
Step 1: Open a shell with OpenSSL
OpenSSL ships on every recent Linux distribution and on macOS. On Windows, install it (see our guide on installing OpenSSL on Windows) and run the command in PowerShell or Command Prompt. Open a terminal in any folder you can write to: OpenSSL will create the CSR and key files there as plain text, so you can move them off the machine when you are done.
Step 2: Run the OpenSSL command
Run the following command in your shell. Replace yourdomain with your actual domain (for example, example.com):
openssl req -new -newkey rsa:2048 -nodes \
-keyout yourdomain.key -out yourdomain.csr \
-addext "subjectAltName = DNS:yourdomain.com,DNS:www.yourdomain.com"
What each flag does:
- -new creates a new CSR.
- -newkey rsa:2048 generates a new 2048-bit RSA private key alongside the CSR. Use rsa:3072 or rsa:4096 if your policy requires a larger key. Do not switch to ECDSA: Heroku rejects ECC keys on manual uploads.
- -nodes writes the key without a passphrase (on OpenSSL 3.x the equivalent flag is -noenc; both work). Heroku will reject an encrypted private key during
heroku certs:add. - -keyout and -out are the output paths for the key and CSR.
- -addext “subjectAltName=DNS:…” embeds Subject Alternative Names (SANs) directly (requires OpenSSL 1.1.1 or later). Every modern browser and CA requires the SAN extension, even for single-domain certificates, so include both the apex (yourdomain.com) and any www variant you plan to serve on Heroku. For a wildcard, list *.yourdomain.com as well.
Step 3: Fill in the CSR details
OpenSSL prompts you for the certificate’s identity fields. Enter them as follows:
- Country Name: the two-letter ISO code of the country where your organization is legally registered (for example, US).
- State or Province Name: the full name of the state or region (for example, Nevada). Do not abbreviate.
- Locality Name: the city (for example, Las Vegas).
- Organization Name: the legal name of your organization. For a Domain Validation certificate, leave this blank.
- Organizational Unit Name: deprecated by the CA/Browser Forum, so leave it blank.
- Common Name: the fully qualified domain name (FQDN) you want to secure, for example www.yourdomain.com. For a wildcard, enter *.yourdomain.com. The Common Name must also be present in the SAN list.
- Email Address: a valid contact email (or leave blank).
- A challenge password and An optional company name: leave both blank. Press Enter to skip.
OpenSSL writes two files in the current directory:
- yourdomain.csr: the CSR you submit to your Certificate Authority.
- yourdomain.key: the private key. Keep this file private and back it up; you will need it again when you upload the issued certificate to Heroku.
Step 4: Submit the CSR to your Certificate Authority
Open yourdomain.csr in any text editor and copy the whole block, including the —–BEGIN CERTIFICATE REQUEST—– and —–END CERTIFICATE REQUEST—– markers. Paste it into the CSR field during your SSL order.
Before submitting, you can verify the CSR contents with our CSR Decoder: it shows the Common Name, SAN list, key type, and key length so you can catch typos before the CA does.
Complete the validation steps the CA asks for (DNS, file-based, or email). Once the certificate is issued, the CA sends you the signed end-entity certificate (usually a .crt file) and the intermediate CA bundle (often a .ca-bundle file). Continue with the upload below.
Upload the certificate to Heroku
Step 1: Register your custom domain with the app
Heroku will not bind a certificate until the custom domain is registered with the app. From a terminal logged in to the Heroku CLI, run:
heroku domains:add www.example.com -a your-app-name
Replace www.example.com with your domain and your-app-name with your Heroku app. Repeat the command for any additional hostnames (for example a bare root domain or a second subdomain). The command returns a per-domain DNS target such as quiet-fire-1234.herokudns.com: you will point your DNS provider at this value in Step 4.
Step 2: Build the fullchain PEM file
Heroku expects a single PEM file with the end-entity certificate first and the intermediate chain after it. On Linux or macOS, concatenate the files with cat:
cat yourdomain.crt yourdomain.ca-bundle > server.crt
On Windows, open both files in a plain text editor (Notepad++ or VS Code, not Word) and paste the contents of the .ca-bundle below the contents of the .crt, in that order, with no blank line between blocks. Save the combined file as server.crt. If your CA sent the chain inside a single PEM already (with the leaf at the top), you can use that file as-is.
Step 3: Upload the certificate with the Heroku CLI
For a brand-new install, upload the fullchain PEM and the matching private key with certs:add:
heroku certs:add server.crt yourdomain.key -a your-app-name
If you are replacing an existing certificate on the same app (for example during renewal), use certs:update instead so Heroku keeps the same DNS target:
heroku certs:update server.crt yourdomain.key -a your-app-name
Prefer the dashboard? Open the app, go to Settings > Domains and certificates, click Configure SSL, choose Manually, drag the combined server.crt into the certificate slot and the .key file into the private-key slot, then click Next and confirm.
If you see an Internal server error while uploading, the Heroku CLI on your machine is almost always out of date. Run heroku update and try again. If the error persists, confirm the certificate file is a fullchain in PEM format (end-entity first, intermediates after) and that the private key is the RSA key matching the CSR you submitted.
Step 4: Point DNS at the Heroku DNS target
List your domains and copy the DNS target Heroku returned for each:
heroku domains -a your-app-name
At your DNS provider, create one record per domain:
- Subdomain (for example www.example.com): create a CNAME record pointing to the Heroku DNS target.
- Apex / root domain (for example example.com): a CNAME is not allowed on the apex per the DNS spec, so use an ALIAS, ANAME, or flattened-CNAME record (the exact name depends on your DNS provider) pointing to the same Heroku DNS target. If your DNS provider does not support any of these, move DNS to one that does (Cloudflare, DNSimple, Route 53, NS1, easyDNS, and similar).
Do not point DNS at your-app-name.herokuapp.com or at any *.herokussl.com hostname: the manual binding will not route correctly through either of those. Always use the per-domain DNS target Heroku assigned.
Verify the CSR and the deployed certificate
Before submitting the CSR, decode it locally to confirm the Common Name, SAN list, key type, and key length:
openssl req -in yourdomain.csr -noout -text
Or paste the CSR into our CSR Decoder for the same information in your browser.
After uploading, confirm the certificate is installed and serving traffic. From the CLI:
heroku certs:info -a your-app-name
The output lists the certificate, the issuing CA, the expiration date, and the domains it covers. Then open your site over https:// in a browser, check that the padlock is present, and run a deeper external scan with our SSL Checker to confirm that the certificate chain is complete and the protocols are configured correctly.
Save 10% on SSL Certificates when ordering from SSL Dragon today!
Fast issuance, strong encryption, 99.99% browser trust, dedicated support, and 25-day money-back guarantee. Coupon code: SAVE10


