Skip to content
Visit SSL on GitHub
Set theme to dark (⇧+D)


Custom Certificates can be uploaded in the Cloudflare Dashboard or using the Cloudflare API.

Certificate packs

Certificates uploaded to Cloudflare will be automatically grouped together into a Certificate Pack before being deployed to the global edge. A Certificate Pack is a group of certificates that share the same set of hostnames, e.g., and *, but use different signature algorithms. Each pack can include up to three certificates, with one from each of the following signature algorithms: SHA-2/RSA, SHA-2/ECDSA, and SHA-1/RSA.

Certificate requirements

Certificates are parsed and checked for validity before being accepted. Each certificate uploaded must:

  • Be encoded in PEM format
  • Not be expiring in less than 14 days from time of upload
  • Have a subject alternative name (SAN) matching at least one hostname in the zone where it’s being uploaded
  • Use a private key greater than or equal to a minimum length (currently 2048 bit for RSA and 225 bit for ECDSA)
  • Be publicly trusted by a major browser, unless the User Defined bundling method is used

Using the Cloudflare API

The call below will upload a certificate for use with Cloudflare will automatically bundle the certificate with a certificate chain optimized for maximum compatibility with browsers.

Note that if you are using an ECC key generated by OpenSSL, you will need to first remove the -----BEGIN EC PARAMETERS-----...-----END EC PARAMETERS----- section of the file.

1. Prior to uploading your certificate, you will need to replace line endings with the string “\n” and build the payload

$ cat app_example_com.pem-----BEGIN CERTIFICATE-----MIIFJDCCBAygAwIBAgIQD0ifmj/Yi5NP/2gdUySbfzANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMScwJQYDVQQDEx5E...SzSHfXp5lnu/3V08I72q1QNzOCgY1XeL4GKVcj4or6cT6tX6oJH7ePPmfrBfqI/OOeH8gMJ+FuwtXYEPa4hBf38M5eU5xWG7-----END CERTIFICATE-----
$ MYCERT="$(cat www_example_com.pem|perl -pe 's/\r?\n/\\n/'|sed -e 's/..$//')"$ MYKEY="$(cat www_example_com.key|perl -pe 's/\r?\n/\\n/'|sed -e's/..$//')"

With the certificate and key saved to environment variables (using escaped newlines), we build the payload:

$ request_body=$(< <(cat <<EOF{    "certificate": "$MYCERT",    "private_key": "$MYKEY",    "bundle_method":"ubiquitous"}EOF))

You can optionally add geographic restrictions that specify where your private key can physically be decrypted:

$ request_body=$(< <(cat <<EOF{    "certificate": "$MYCERT",    "private_key": "$MYKEY",    "bundle_method":"ubiquitous",    "geo_restrictions":{"label":"us"}}'}

You can also enable support for legacy clients which do not include SNI in the TLS handshake.

$ request_body=$(< <(cat <<EOF{    "certificate": "$MYCERT",    "private_key": "$MYKEY",    "bundle_method":"ubiquitous",    "geo_restrictions":{"label":"us"}}',    "type":"sni_custom"}

sni_custom is recommended by Cloudflare. Use legacy_custom when a specific client requires non-SNI support. The Cloudflare API treats all Custom SSL certificates as Legacy by default.

2. With the payload built, make the API call to upload your certificate and key

$ curl -sX POST{zone_id}/custom_certificates \     -H "X-Auth-Email: {email}" -H "X-Auth-Key: {key}" \     -H "Content-Type: application/json" -d "$request_body"