# Cloudflare in front of your site

> Site behind Cloudflare: on Free and Pro our certificate sits on your server; on Business and Enterprise a script renews it in Cloudflare via the API.

URL: https://zrazu.com/en/docs/ssl-auto-cloudflare/

If your site works through the Cloudflare proxy (the orange cloud in DNS), visitors see the certificate served by Cloudflare, not by your server.

## Free and Pro plans

Cloudflare issues a free certificate for visitors itself, and on these plans you cannot upload your own there. Our certificate is needed on **your server**, so that the Cloudflare → server connection is also protected and verified (the **SSL/TLS → Full (strict)** mode). Set up automatic renewal on the server using the guide for it: [Linux server](https://zrazu.com/en/docs/ssl-auto-linux.md), [cPanel](https://zrazu.com/en/docs/ssl-auto-cpanel.md), [Kubernetes](https://zrazu.com/en/docs/ssl-auto-kubernetes.md).

## Business and Enterprise plans — your own certificate in Cloudflare

Here you can upload your own certificate (**SSL/TLS → Edge Certificates → Upload Custom SSL Certificate**), but Cloudflare does not renew it. The script below fetches the fresh certificate from the link once a day and updates it in Cloudflare through the API. Run it on any Linux server with `curl` and `openssl`, usually the one behind Cloudflare.

### What you need

- The certificate link from your account: `https://api.zrazu.com/ssl-pull/zsp_YOUR_TOKEN`.
- A private key without a password. An ECDSA key must not have an `EC PARAMETERS` block.
- **Zone ID** — on your domain's page in Cloudflare, bottom right (**API → Zone ID**).
- **Certificate ID**: **SSL/TLS → Edge Certificates**, your certificate's row → expand → **Certificate ID**. If there is no certificate yet, first upload it manually (the button above) from `https://api.zrazu.com/ssl-pull/zsp_YOUR_TOKEN/fullchain.pem` with your key.
- **API token**: **My Profile → API Tokens → Create Token → Create Custom Token** → permission **Zone → SSL and Certificates → Edit**, **Zone Resources** — only this domain.

### Step 1. Key and script on the server

```sh
sudo mkdir -p /etc/ssl/zrazu/example.com
sudo chmod 700 /etc/ssl/zrazu/example.com
sudo nano /etc/ssl/zrazu/example.com/key.pem
sudo nano /usr/local/bin/zrazu-cloudflare-example.com.sh
```

Paste the key into the first file and the script below into the second, with your `ZONE`, `CERT_ID` and `TOKEN`.

```sh file=zrazu-cloudflare-update.sh
#!/bin/sh
# ZRAZU: updates your own certificate in Cloudflare using the personal link. Run by cron once a day.
set -eu
PULL="https://api.zrazu.com/ssl-pull/zsp_YOUR_TOKEN"
DIR="/etc/ssl/zrazu/example.com"
ZONE="ZONE_ID"
CERT_ID="CERTIFICATE_ID"
TOKEN="API_TOKEN"
API="https://api.cloudflare.com/client/v4/zones/$ZONE/custom_certificates"

umask 077
cd "$DIR"
[ -f cert_id ] || echo "$CERT_ID" > cert_id
curl -fsS --retry 3 --max-time 60 -o new.pem "$PULL/fullchain.pem"
grep -q "BEGIN CERTIFICATE" new.pem || { echo "ZRAZU: the link does not return a certificate"; exit 1; }
if [ -f applied.pem ] && cmp -s new.pem applied.pem; then echo "ZRAZU: certificate unchanged"; exit 0; fi
cert_pub=$(openssl x509 -in new.pem -noout -pubkey | openssl sha256)
key_pub=$(openssl pkey -in key.pem -pubout | openssl sha256)
[ "$cert_pub" = "$key_pub" ] || { echo "ZRAZU: certificate was issued for a different key — put the new key.pem in place"; exit 1; }
json() { awk '{ gsub(/\\/, "\\\\"); gsub(/"/, "\\\""); printf "%s\\n", $0 }' "$1"; }
printf '{"certificate":"%s","private_key":"%s","bundle_method":"force"}' "$(json new.pem)" "$(json key.pem)" > body.json
out=$(curl -sS -X PATCH "$API/$(cat cert_id)" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" --data @body.json)
rm -f body.json
if printf '%s' "$out" | grep -q '"success": *true'; then
  id=$(printf '%s' "$out" | tr -d '\n' | grep -o '"result": *{.*' | grep -o '"id": *"[0-9a-f]*"' | head -n 1 | cut -d'"' -f4)
  [ -z "$id" ] || echo "$id" > cert_id
  mv -f new.pem applied.pem
  echo "ZRAZU: certificate updated in Cloudflare"
else
  echo "ZRAZU: Cloudflare refused:"
  printf '%s\n' "$out"
  exit 1
fi
```

Cloudflare may give the updated certificate a new ID. The script remembers it in the `cert_id` file by itself.

### Step 2. First run and schedule

```sh
sudo chmod 700 /usr/local/bin/zrazu-cloudflare-example.com.sh
sudo /usr/local/bin/zrazu-cloudflare-example.com.sh
echo "23 4 * * * root /usr/local/bin/zrazu-cloudflare-example.com.sh >> /var/log/zrazu-ssl.log 2>&1" | sudo tee /etc/cron.d/zrazu-cloudflare-example.com
```

### Check

1. The first run prints "certificate updated in Cloudflare", later runs print "certificate unchanged".
2. **SSL/TLS → Edge Certificates** — your certificate shows a new **Expires On** date.
3. Site: [https://zrazu.com/tools/ssl/example.com/](https://zrazu.com/tools/ssl/example.com/).

### If it did not work

- `Authentication error` — the token lacks the **SSL and Certificates → Edit** permission or is not for this domain.
- `custom certificate not found` — wrong `CERT_ID`: delete the file `/etc/ssl/zrazu/example.com/cert_id`, fix the line in the script and run it again.
- "certificate was issued for a different key" — the certificate was reissued with a new key: replace `key.pem`.
