Uploading Certificates

In some cases, rather than let Cloudflare handle the certificate lifecycle, your customers may need to provide their own key material.

The typical use cases for custom certificate are for serving Extended Validation (EV) certificates, i.e., the “green bar” and when your customers’ information security policy dictates that third-parties are not permitted to generate private keys on their behalf. The challenge with providing your own certificates is that they must be renewed manually and re-uploaded prior to expiration.

Note that Cloudflare only accepts publicly trusted certificates of these three types:

  • SHA256WithRSA
  • SHA1WithRSA
  • ECDSAWithSHA256

If you attempt to upload a self-signed certificate, or a certificate of another type, it will be rejected.

Uploading a custom certificate

The call below will upload a certificate for use with app.example.com. 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. Replace line endings with the string “\n” and build the payload

$ cat app_example_com.pem
-----BEGIN CERTIFICATE-----
MIIFJDCCBAygAwIBAgIQD0ifmj/Yi5NP/2gdUySbfzANBgkqhkiG9w0BAQsFADBN
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMScwJQYDVQQDEx5E
...
SzSHfXp5lnu/3V08I72q1QNzOCgY1XeL4GKVcj4or6cT6tX6oJH7ePPmfrBfqI/O
OeH8gMJ+FuwtXYEPa4hBf38M5eU5xWG7
-----END CERTIFICATE-----
$ MYCERT="$(cat app_example_com.pem|perl -pe 's/\r?\n/\\n/'|sed -e 's/..$//')"
$ MYKEY="$(cat app_example_com.key|perl -pe 's/\r?\n/\\n/'|sed -e's/..$//')"
$ echo $MYCERT
-----BEGIN CERTIFICATE-----\nMIIFJDCCBAygAwIBAgIQD0ifmj/Yi5NP/2gdUySbfzANBgkqhkiG9w0BAQsFADBN\nMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMScwJQYDVQQDEx5E...SzSHfXp5lnu/3V08I72q1QNzOCgY1XeL4GKVcj4or6cT6tX6oJH7ePPmfrBfqI/O\nOeH8gMJ+FuwtXYEPa4hBf38M5eU5xWG7\n-----END CERTIFICATE-----\n

$ request_body=$(< <(cat <<EOF
{
  "hostname": "app.example.com",
  "ssl": { 
    "custom_certificate": "$MYCERT",
    "custom_key": "$MYKEY"
  }
}
EOF
))

2. Upload the custom certificate and private key

Note that the serial number returned is unique to the issuer, but not globally unique. Additionally, it is returned as a string, not an integer.

$ curl -sX POST https://api.cloudflare.com/client/v4/zones/{zone_id}/custom_hostnames\
    -H "X-Auth-Email: {email}" -H "X-Auth-Key: {key}"
    -H 'Content-Type: application/json' -d "$request_body" 

{
  "result": {
    "id": "f03e8f82-8ad0-4939-a600-82c30261f901",
    "hostname": "app.example.com",
    "ssl": {
      "id": "68ab2d69-4b49-4ee3-88a2-0e6b2a3446a1",
      "status": "pending_deployment",
      "hosts": [
        "app.example.com"
      ],
      "issuer": "DigiCertInc",
      "serial_number": "6743787633689793699141714808227354901",
      "signature": "SHA256WithRSA",
      "uploaded_on": "2017-12-17T19:19:21.779446Z",
      "expires_on": "2019-01-04T12:00:00Z"
    }
  },
  "success": true
}