Heroku SSL
Last updated February 08, 2024
Table of Contents
SSL is a cryptographic protocol that provides end-to-end encryption and integrity for all web requests. Enable SSL on apps that transmit sensitive data to ensure all information is transmitted securely.
Heroku SSL is a combination of features that enables SSL for all Heroku apps. Heroku SSL uses Server Name Indication (SNI), an extension of the widely supported TLS protocol.
Certificate Options
Apps can use the provided *.herokuapp.com
certificate, Automated Certificate Management (ACM), or manually uploaded certificates.
Manually Upload Certificates
Use the certs:add
Heroku CLI command to add a certificate and private key. It prompts for the custom domain with which to associate the certificate-key pair.
$ heroku certs:add server.crt server.key
Adding SSL to example... done
exampleapp now served by exemplary-sushi-4gr7rb6h8djkvo9j5zf16mfp.herokudns.com.
Certificate details:
Expires At: 2022-08-18 21:53:18 GMT
Issuer: C=US; ST=CA; L=SF; O=Heroku; CN=www.example.com
Starts At: 2021-08-18 21:53:18 GMT
...
If you require intermediate certificates, refer to this article on merging certificates to get a complete chain.
After successfully adding the certificate, verify that the application serves it by grabbing the DNS target from the command output:
$ openssl s_client -connect <dns target>:443 -servername <domain>
For example:
openssl s_client -connect exemplary-sushi-4gr7rb6h8djkvo9j5zf16mfp.herokudns.com:443 -servername www.example.com
After a successful verification, update the DNS settings for each domain on the app. Run heroku domains at any time for a list of DNS targets assigned to the custom domains associated with the app. After adding the certificate, the DNS target has the pattern <adjective>-<noun>-<random>.herokudns.com
. The target for the previous example is exemplary-sushi-4gr7rb6h8djkvo9j5zf16mfp.herokudns.com
. Run heroku domains
at any time for a list of DNS targets assigned to the custom domains associated with the app.
If needed elsewhere, keep a copy of uploaded private keys safe at all times. Heroku doesn’t allow extracting private keys out of its systems.
View SSL Certificate Details
A single app can accept multiple unique certificates. Use the certs
command to list out certificates for an app:
$ heroku certs
Name Common Name(s) Expires Trusted Type Domains
──────────────────── ─────────────────────── ──────────────────── ─────── ──── ───────
mamenchisaurus-65072 kapow.herokudev.frsm.us 2022-02-03 19:53 UTC False SNI 0
oviraptor-60827 bar.herokudev.frsm.us 2022-02-03 19:40 UTC False SNI 1
To get detailed information about a certificate, use certs:info
.
$ heroku certs:info --name=mamenchisaurus-65072
Fetching SSL mamenchisaurus-65072 info for exampleapp... done
Certificate details:
Expires At: 2012-10-31 21:53:18 GMT
Issuer: C=US; ST=CA; L=SF; O=Heroku; CN=www.example.com
Starts At: 2011-11-01 21:53:18 GMT
Subject: C=US; ST=CA; L=SF; O=Heroku; CN=www.example.com
...
Update Certificate and Domain Mappings
The heroku certs:info --show-domains
command displays the domains associated with a certificate.
To associate a certificate with a domain, or to update the mapping between certificates and custom domains, use the heroku domains:update
command:
$ heroku domains:update www.example.com --cert mycert
Updating www.example.com to use mycert certificate... done
Verify SSL is Set Up Correctly
Use a command-line utility like curl to test that the domain is configured correctly.
$ curl -vI https://www.example.com
* About to connect() to www.example.com port 443 (#0)
* Trying 50.16.234.21... connected
* Connected to www.example.com (50.16.234.21) port 443 (#0)
* SSLv3, TLS handshake, Client hello (1):
* SSLv3, TLS handshake, Server hello (2):
* SSLv3, TLS handshake, CERT (11):
* SSLv3, TLS handshake, Server finished (14):
* SSLv3, TLS handshake, Client key exchange (16):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
* SSL connection using AES256-SHA
* Server certificate:
* subject: C=US; ST=CA; L=SF; O=SFDC; OU=Heroku; CN=www.example.com
* start date: 2011-11-01 17:18:11 GMT
* expire date: 2012-10-31 17:18:11 GMT
* common name: www.example.com (matched)
* issuer: C=US; ST=CA; L=SF; O=SFDC; OU=Heroku; CN=www.heroku.com
* SSL certificate verify ok.
> GET / HTTP/1.1
> User-Agent: curl/7.19.7 (universal-apple-darwin10.0) libcurl/7.19.7 OpenSSL/0.9.8r zlib/1.2.3
> Host: www.example.com
> Accept: */*
...
Pay attention to the output. The correct configuration yields SSL certificate verify ok
. If it prints something like common name: www.example.com (doesn’t match 'www.somedomain.com')
, something isn’t configured correctly.
For macOS users: Using the -k
flag with the curl
command can result in a connection error. On many versions of macOS, curl
with -k
doesn’t pass SNI information.
Update Certificate
The certs:update
command updates with a new certificate and a new or an existing private key:
$ heroku certs:update --name=mamenchisaurus-65072 server.crt server.key
Updated certificate details:
Common Name(s): www.example.com
Expires At: 2017-03-21 21:35 UTC
Issuer: /C=US/ST=California/L=San Francisco/O=Heroku/OU=Engineering/CN=www.example.com
Starts At: 2016-03-21 21:35 UTC
Subject: /C=US/ST=California/L=San Francisco/O=Heroku/OU=Engineering/CN=www.example.com
Remove Certificate
Remove a certificate using the certs:remove
command:
$ heroku certs:remove --name=mamenchisaurus-65072
Removing SSL certificate mamenchisaurus-65072 (exemplary-sushi-4gr7rb6h8djkvo9j5zf16mfp.herokudns.com) from example... done
Removing a certificate ceases any HTTPS traffic to the certificate’s domain.
SSL Details
Client IP Address
When a client, often the browser, initiates an SSL request, it decrypts the request before sending it to an app. This extra SSL termination step obfuscates the originating IP address of the request.
As a workaround, the X-Forwarded-For
HTTP request header includes the IP address of the external client.
Supported SSL Protocols
- TLS 1.2
- TLS 1.3
Heroku doesn’t support SSLv3, TLS 1.0, or TLS 1.1 for security reasons. Heroku curates the cipher suites to strike a balance between security best practices and backward compatibility.
Heroku SSL doesn’t allow customization of TLS versions or ciphers for Common Runtime apps. See Routing in Private Spaces for how to adjust cipher suites for Private Space apps.
Using Heroku SSL on Apps With Internal Routing
You must use a DNS-01 challenge with a custom domain when using Heroku SSL on internally routed apps. Other challenge types (HTTP-01, TLS-ALPN-01) won’t work as internally routed apps have a private IP that can’t be externally accessed or validated.
Troubleshooting
Internal Server Error
If Internal server error
occurs when adding a certificate, check if the Heroku CLI is outdated. Verify the CLI installation and update it to the latest version with heroku update
, or reinstall it.
SSL File Types
Creating an SSL certificate produces and consumes several different file types:
- A
.csr
file is a Certificate Signing Request. This file initiates a certificate request with a certificate provider and contains administrative information about the organization making the request. - A
.key
file is the private key used for a site’s SSL-enabled requests. .pem
and.crt
extensions are both base64 ASCII encoded files. Often used interchangeably, the technical difference is that.pem
files contain the certificate and key. A.crt
file only contains the certificate. In reality, this distinction is often ignored.