---
title: Deploy custom certificate
description: Configure the Cloudflare One Client to use a custom root certificate instead of the Cloudflare certificate.
image: https://developers.cloudflare.com/zt-preview.png
---

> Documentation Index  
> Fetch the complete documentation index at: https://developers.cloudflare.com/cloudflare-one/llms.txt  
> Use this file to discover all available pages before exploring further.

[Skip to content](#%5Ftop) 

### Tags

[ TLS ](https://developers.cloudflare.com/search/?tags=TLS)[ Python ](https://developers.cloudflare.com/search/?tags=Python) 

# Deploy custom certificate

Note

Only available on Enterprise plans.

Enterprise customers who do not wish to install a [Cloudflare certificate](https://developers.cloudflare.com/cloudflare-one/team-and-resources/devices/user-side-certificates/manual-deployment/) have the option to upload their own root certificate to Cloudflare. This feature is sometimes referred to as Bring Your Own Public Key Infrastructure (BYOPKI). Gateway will use your uploaded certificate to encrypt all sessions between the end user and Gateway, enabling all HTTPS inspection features that previously required a Cloudflare certificate. You can upload multiple certificates to your account, but only one can be active at any given time. You also need to upload a private key to intercept domains with JIT certificates and to enable the [block page](https://developers.cloudflare.com/cloudflare-one/reusable-components/custom-pages/gateway-block-page/).

You can upload either a root certificate or a full certificate chain (root certificate plus intermediate certificates). Uploading a certificate chain allows end-user devices to only install the root certificate, which can simplify certificate management for larger enterprises.

You can upload up to five custom root certificates. If your organization requires more than five certificates, contact your account team.

Warning

Custom certificates are limited to use between your users and the Gateway proxy. Gateway connects to origin servers using publicly trusted certificates, similar to how a browser validates secure websites.

If your users need to connect to self-signed origin servers, create an HTTP Allow policy for the origin server with the [untrusted certificate action](https://developers.cloudflare.com/cloudflare-one/traffic-policies/http-policies/#untrusted-certificates) set to _Pass through_.

## Generate a custom root CA

1. Open a terminal.
2. (Optional) Create a directory for the root CA and change into it.  
Terminal window  
```  
mkdir -p /root/customca  
cd /root/customca  
```  
You can generate the certificate files in any directory. This step keeps things organized. If you skip it, files will be created in your current working directory.
3. Generate a private key for the root CA.  
Terminal window  
```  
openssl genrsa -out <CUSTOM-ROOT-PRIVATE-KEY>.pem 2048  
```  
The `2048` value specifies the RSA key size in bits. You can use `4096` for stronger security at the cost of slightly slower TLS handshakes.  
Warning  
Keep the private key secure — if it is compromised, an attacker could issue trusted certificates on your behalf.
4. Generate a self-signed root certificate.  
Terminal window  
```  
openssl req -x509 -sha256 -new -nodes \  
  -key <CUSTOM-ROOT-PRIVATE-KEY>.pem \  
  -days 365 \  
  -out <CUSTOM-ROOT-CERT>.pem \  
  -addext "basicConstraints=critical,CA:TRUE" \  
  -addext "keyUsage=critical,keyCertSign,cRLSign"  
```  
The `-addext` flags add the `basicConstraints` and `keyUsage` extensions required by [RFC 5280 ↗](https://datatracker.ietf.org/doc/html/rfc5280) for CA certificates. Without them, some TLS clients may reject certificates signed by your custom CA. In particular, Python 3.13 and later enforce strict RFC 5280 compliance by default (`ssl.VERIFY_X509_STRICT`), causing HTTPS requests to fail for devices using the Cloudflare One Client when the uploaded CA does not include these extensions.  
The `-days 365` value controls certificate expiry. A shorter duration reduces risk if the key is compromised, but requires more frequent rotation. Rotating a deployed BYOPKI certificate is a disruptive operation, so choose an expiry that balances security with operational overhead.  
Error: `Unknown cipher or option -addext`  
If your system runs OpenSSL versions older than 1.1.1, the `-addext` flag is not available. Use a config file instead:  
Terminal window  
```  
openssl req -x509 -sha256 -new -nodes \  
  -key <CUSTOM-ROOT-PRIVATE-KEY>.pem \  
  -days 365 \  
  -out <CUSTOM-ROOT-CERT>.pem \  
  -config <(printf '[req]\ndistinguished_name=dn\n[dn]\n[v3_ca]\nbasicConstraints=critical,CA:TRUE\nkeyUsage=critical,keyCertSign,cRLSign') \  
  -extensions v3_ca  
```
5. Verify the required RFC 5280 extensions are present:  
Terminal window  
```  
openssl x509 -in <CUSTOM-ROOT-CERT>.pem -noout -ext keyUsage,basicConstraints  
```  
The output should include:  
```  
X509v3 Basic Constraints: critical  
    CA:TRUE  
X509v3 Key Usage: critical  
    Certificate Sign, CRL Sign  
```  
If these fields are missing, regenerate the certificate using the command in step 4.
6. To review the private key, run the following command:  
Terminal window  
```  
openssl rsa -in <CUSTOM-ROOT-PRIVATE-KEY>.pem -text  
```  
To review the certificate, run the following command:  
Terminal window  
```  
openssl x509 -in <CUSTOM-ROOT-CERT>.pem -text  
```

When preparing your certificate and private key for upload, be sure to remove any unwanted characters, such as mismatching subdomains in the certificate's common name.

## Deploy a custom root certificate

You can upload a single root certificate or a full certificate chain. When uploading a certificate chain via the dashboard, API, or Terraform, concatenate the root certificate and any intermediate certificates in PEM format, with the root certificate first.

* [ Dashboard ](#tab-panel-5264)
* [ API ](#tab-panel-5265)

1. In the [Cloudflare dashboard ↗](https://dash.cloudflare.com/), go to **Zero Trust** \> **Traffic policies** \> **Traffic settings** \> **Certificates**.
2. Select **Upload certificate**.
3. Enter the private key and SSL certificate you generated or select **Paste certificate from file** to upload them from a file. If uploading a certificate chain, paste all certificates (root and intermediates) in PEM format with the root certificate first.
4. Select **Upload custom certificate**.  
You can now [use the generated custom root certificate](#use-a-custom-root-certificate) for inspection.

1. Use the [Upload mTLS certificate endpoint](https://developers.cloudflare.com/api/resources/mtls%5Fcertificates/methods/create/) to upload the certificate and private key to Cloudflare. The certificate must be a root CA or certificate chain, formatted as a single string with `\n` replacing the line breaks.  
Required API token permissions  
At least one of the following [token permissions](https://developers.cloudflare.com/fundamentals/api/reference/permissions/)is required:  
   * `Account: SSL and Certificates Write`  
Upload mTLS certificate  
```  
curl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/mtls_certificates" \  
  --request POST \  
  --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \  
  --json '{  
    "name": "example_ca_cert",  
    "certificates": "-----BEGIN CERTIFICATE-----\nXXXXX\n-----END CERTIFICATE-----",  
    "private_key": "-----BEGIN PRIVATE KEY-----\nXXXXX\n-----END PRIVATE KEY-----",  
    "ca": true  
  }'  
```  
The response will return a UUID for the certificate. For example:  
```  
{  
  "success": true,  
  "errors": [],  
  "messages": [],  
  "result": {  
    "id": "2458ce5a-0c35-4c7f-82c7-8e9487d3ff60",  
    "name": "example_ca_cert",  
    "issuer": "O=Example Inc.,L=California,ST=San Francisco,C=US",  
    "signature": "SHA256WithRSA",  
    ...  
  }  
}  
```  
When uploading a certificate chain, the `certificates` field should contain all certificates in PEM format. To format this field, order the root certificate first, then concatenate any intermediate certificates.
2. Set the certificate as available for use in inspection with the [Activate a Zero Trust certificate endpoint](https://developers.cloudflare.com/api/resources/zero%5Ftrust/subresources/gateway/subresources/certificates/methods/activate/). This will deploy the certificate across the Cloudflare global network.  
Activate a Zero Trust certificate  
```  
curl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/gateway/certificates/$CERTIFICATE_ID/activate" \  
  --request POST \  
  --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN"  
```  
The response will return the certificate and a `pending_deployment` binding status. For example:  
```  
{  
  "errors": [],  
  "messages": [],  
  "success": true,  
  "result": {  
    "in_use": false,  
    "id": "f174e90a-fafe-4643-bbbc-4a0ed4fc8415",  
    "certificate": "-----BEGIN CERTIFICATE-----\\n ... \\n-----END CERTIFICATE-----\\n",  
    "issuer_org": "Example Inc.",  
    "issuer_raw": "O=Example Inc.,L=California,ST=San Francisco,C=US",  
    "fingerprint": "E9:19:49:AA:DD:D8:1E:C1:20:2A:D8:22:BF:A5:F8:FC:1A:F7:10:9F:C7:5B:69:AB:0:31:91:8B:61:B4:BF:1C",  
    "binding_status": "pending_deployment",  
    "type": "custom",  
    "updated_at": "2014-01-01T05:20:00.12345Z",  
    "uploaded_on": "2014-01-01T05:20:00.12345Z",  
    "created_at": "2014-01-01T05:20:00.12345Z",  
    "expires_on": "2014-01-01T05:20:00.12345Z"  
  }  
}  
```
3. Use the [Get Zero Trust certificate details endpoint](https://developers.cloudflare.com/api/resources/zero%5Ftrust/subresources/gateway/subresources/certificates/methods/get/) to verify the certificate's binding status is set to `available`.  
Get Zero Trust certificate details  
```  
curl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/gateway/certificates/$CERTIFICATE_ID" \  
  --request GET \  
  --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN"  
```  
```  
{  
  "errors": [],  
  "messages": [],  
  "success": true,  
  "result": {  
    "in_use": false,  
    "id": "f174e90a-fafe-4643-bbbc-4a0ed4fc8415",  
    "certificate": "-----BEGIN CERTIFICATE-----\\n ... \\n-----END CERTIFICATE-----\\n",  
    "issuer_org": "Example Inc.",  
    "issuer_raw": "O=Example Inc.,L=California,ST=San Francisco,C=US",  
    "fingerprint": "E9:19:49:AA:DD:D8:1E:C1:20:2A:D8:22:BF:A5:F8:FC:1A:F7:10:9F:C7:5B:69:AB:0:31:91:8B:61:B4:BF:1C",  
    "binding_status": "available",  
    "type": "custom",  
    "updated_at": "2014-01-01T05:20:00.12345Z",  
    "uploaded_on": "2014-01-01T05:20:00.12345Z",  
    "created_at": "2014-01-01T05:20:00.12345Z",  
    "expires_on": "2014-01-01T05:20:00.12345Z"  
  }  
}  
```
4. (Optional) Verify the certificate is installed on your user's devices either [with the Cloudflare One Client](https://developers.cloudflare.com/cloudflare-one/team-and-resources/devices/user-side-certificates/automated-deployment/) or [manually](https://developers.cloudflare.com/cloudflare-one/team-and-resources/devices/user-side-certificates/manual-deployment/).
5. Use the [Patch Zero Trust account configuration endpoint](https://developers.cloudflare.com/api/resources/zero%5Ftrust/subresources/gateway/subresources/configurations/methods/edit/) to turn on the certificate for use in inspection. For example:

Patch Zero Trust account configuration

```

curl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/gateway/configuration" \

  --request PATCH \

  --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \

  --json '{

    "settings": {

        "certificate": {

            "id": "{certificate_id}",

            "in_use": true

        }

    }

  }'


```

Once `in-use` is set to `true`, Gateway will sign your traffic using the custom root certificate and private key. If you turn off or deactivate the custom certificate, Gateway will revert to the next available Cloudflare certificate generated for your Zero Trust account.

Private key visibility

When you upload a private key to Zero Trust, Cloudflare encrypts the key and stores it at rest. Only your delegated apps have the necessary decryption keys to decrypt the private key. You will not be able to retrieve the private key after upload.

## Use a custom root certificate

To use a custom root certificate you generated and uploaded to Cloudflare, refer to [Activate a root certificate](https://developers.cloudflare.com/cloudflare-one/team-and-resources/devices/user-side-certificates/#activate-a-root-certificate).

## Troubleshooting

### Error 526: Invalid SSL certificate

If Gateway returns an **HTTP Response Code: 526** after deploying a custom certificate, refer to the [Error 526 documentation](https://developers.cloudflare.com/cloudflare-one/traffic-policies/troubleshooting/#error-526-invalid-ssl-certificate).

### Python 3.13+ SSL errors with the Cloudflare One Client

Python 3.13 and later enable `ssl.VERIFY_X509_STRICT` by default, which requires CA certificates to comply with [RFC 5280 ↗](https://datatracker.ietf.org/doc/html/rfc5280). If your BYOPKI certificate was generated without the `keyUsage` and `basicConstraints` extensions, Python HTTPS requests will fail when the Cloudflare One Client is active. To resolve the issue, [generate a new custom root CA](https://developers.cloudflare.com/cloudflare-one/team-and-resources/devices/user-side-certificates/custom-certificate/#generate-a-custom-root-ca) and upload it to Cloudflare.

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/cloudflare-one/","name":"Cloudflare One"}},{"@type":"ListItem","position":3,"item":{"@id":"/cloudflare-one/team-and-resources/","name":"Team and resources"}},{"@type":"ListItem","position":4,"item":{"@id":"/cloudflare-one/team-and-resources/devices/","name":"Devices"}},{"@type":"ListItem","position":5,"item":{"@id":"/cloudflare-one/team-and-resources/devices/user-side-certificates/","name":"User-side certificates"}},{"@type":"ListItem","position":6,"item":{"@id":"/cloudflare-one/team-and-resources/devices/user-side-certificates/custom-certificate/","name":"Deploy custom certificate"}}]}
```
