# Upload your own certificate

> Serve a certificate you bought from another certificate authority on a website, in place of the free one.

Source: https://www.coritan.com/docs/websites/ssl/upload-a-certificate/

In the dashboard:

- /dashboard/websites/…/ssl: https://www.coritan.com/dashboard/websites

Upload a certificate you bought from another certificate authority, and Coritan's network serves it for the website's name in place of the free one. Do this when you need a certificate from a particular authority. Otherwise the free certificate that Coritan issues and renews does the same job ([How SSL/TLS certificates work](/docs/websites/ssl/)).

## Before you begin

- The domain needs a web proxy for its own name, such as `example.com`. The **Your own certificate** card appears on the **SSL** tab only then ([Create a web proxy](/docs/proxies/web-proxies/create-a-web-proxy/)).
- You need the certificate and its private key in PEM form, and the chain when your certificate authority sent it as a separate file. A PEM certificate starts with `-----BEGIN CERTIFICATE-----`.
- The certificate must cover the website's name. A wildcard covers only names one level below it, so `*.example.com` does not cover `example.com`.
- The certificate must be valid now and issued by a certificate authority. A self-signed certificate is refused.
- The key must be an RSA key of at least 2048 bits, or an ECDSA key on the P-256 or P-384 curve, without a passphrase.
- Once [account plans open on your account](/docs/billing/account-plans/#plans-open-in-stages), uploads come with the Pro, Business and Enterprise plans.

## Upload the certificate

1. In the dashboard, go to [Websites](https://www.coritan.com/dashboard/websites), open the domain and select the **SSL** tab.
2. On the **Your own certificate** card, select **Upload certificate…**.
3. In **Certificate**, paste the certificate. If you have a full-chain file, paste all of it.
4. In **Private key**, paste the private key.
5. If your certificate authority sent the intermediate certificates as a separate file, paste them in **Chain**, starting with the one that issued your certificate.
6. Select **Upload certificate**.

You can upload 10 certificates to one website in an hour.

## Result

The dashboard confirms `Certificate for example.com uploaded.` The **Certificate** card shows the certificate as `active`, the **Issuer** row reads **Uploaded by you**, and the **Expires** row shows its expiry date. When the certificate lists more than one name, the **Covers** row lists them. Coritan's network serves it for the website's name.

Coritan does not renew a certificate you upload, so the **Renewal** card has no **Renew now** button for it. About 30 days before it expires, Coritan replaces it with a free certificate, unless you upload a newer one first. To keep your own, get a new certificate from your certificate authority before then and upload it the same way.

To go back to a free certificate sooner, [remove this one](/docs/websites/ssl/renew-or-revoke-a-certificate/#remove-a-certificate), then request a new one on the **Request a certificate** card that appears on the same tab.

## Troubleshooting

The **SSL** tab has no **Your own certificate** card
: The domain has no web proxy for its own name. Create one, then open the tab again.

The card shows `Certificate uploads come with the Pro plan`
: Account plans are open on your account, and your plan leaves uploads out. Select `Upgrade to Pro` on the card, or see [Account plans](/docs/billing/account-plans/).

`The private key does not belong to this certificate.`
: The key was made for another certificate. Find the key you created with this certificate's request.

`The certificate does not cover example.com. It covers www.example.net.`
: The certificate is for other names. Get a certificate that lists the website's name.

`The certificate is self-signed, so browsers would warn every visitor. Upload one that a certificate authority issued.`
: Upload a certificate from a certificate authority, or [request a free certificate](/docs/websites/ssl/issue-a-certificate/) instead.

`The certificate expired on 1 March 2026.`
: Get a new certificate from your certificate authority.

`The certificate is not valid until 1 March 2027.`
: The certificate starts to be valid on that date. Upload it then.

`The private key has a passphrase. Remove it and upload the key again.`
: Write the key out without its passphrase, for example with `openssl pkey -in example.key -out example-open.key`, which asks for the passphrase. Upload the new file.

`The chain is out of order. Start with the certificate that issued yours, then the one that issued that, and so on.`
: Put the intermediate certificates in that order, in **Chain** or after the certificate.

`The certificate is not in PEM form. A PEM certificate starts with -----BEGIN CERTIFICATE-----.`
: The file is in another format. Convert a `.cer` or `.der` file with `openssl x509 -inform der -in example.cer -out example.pem`.

`The RSA key has 1024 bits. Use a key of at least 2048 bits.`
: Create a new key and certificate request, and have the certificate issued again.

`Too many requests for this action. Please wait and try again.`
: You uploaded 10 certificates to this website in the last hour. Wait, then try again.

## Related

- [How SSL/TLS certificates work](/docs/websites/ssl/#your-own-certificate)
- [Issue an SSL/TLS certificate](/docs/websites/ssl/issue-a-certificate/)
- [Renew or remove a certificate](/docs/websites/ssl/renew-or-revoke-a-certificate/)

## With the API

Upload to a web proxy by its ID, with the PEM text as JSON strings. `chain_pem` is optional, and `certificate_pem` may hold the whole chain. With `jq`, the files go straight into the request:

```bash
jq -n --rawfile cert fullchain.pem --rawfile key example.key \
  '{certificate_pem: $cert, private_key_pem: $key}' |
curl -X POST https://api.coritan.com/api/v1/proxy/routes/31/certificate \
  -H "Authorization: Bearer $CORITAN_TOKEN" \
  -H "Content-Type: application/json" \
  -d @-
```

The answer is `200` with the names on the certificate and its expiry:

```json
{
  "certificate_id": 91,
  "domain": "example.com",
  "names": ["example.com", "www.example.com"],
  "expires_at": "2027-03-01T23:59:59"
}
```

A certificate that does not check out answers `422` with one of the messages under [Troubleshooting](#troubleshooting) in `detail`, and the answer never repeats the key. The eleventh upload to one web proxy in an hour answers `429` with a `Retry-After` header. A web proxy that is not yours answers `404` with `Route not found`. Once account plans open on your account, a plan without uploads answers `402` with `entitlement_exceeded`.

[Read the certificate status](/docs/websites/ssl/#read-certificates-with-the-api) afterwards: it has `issuer` set to `custom`.

## API

- `POST /api/v1/proxy/routes/{route_id}/certificate`: Serve your own certificate on this website instead of a free one (https://www.coritan.com/docs/api/reference/client/reverse-proxy/#op-post-api-v1-proxy-routes-route-id-certificate)
