SSL: automatic renewal

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.

Renews by itself

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, cPanel, Kubernetes.

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

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.

#!/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

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/.

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.

This page in Markdown