PHPackages                             blendbyte/coyotecert - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [HTTP &amp; Networking](/categories/http)
4. /
5. blendbyte/coyotecert

ActiveLibrary[HTTP &amp; Networking](/categories/http)

blendbyte/coyotecert
====================

Full-featured ACME v2 (RFC 8555) PHP 8.3+ client for issuing, renewing, and revoking TLS certificates from Let's Encrypt, ZeroSSL, Google Trust Services, SSL.com, Buypass, or any standards-compliant CA — with ARI smart renewal, ECDSA/RSA key support, EAB, and PSR-18 HTTP client integration.

v1.2.2(1mo ago)1222↓77.8%11MITPHPPHP ^8.3CI passing

Since Apr 18Pushed 1mo agoCompare

[ Source](https://github.com/blendbyte/coyotecert)[ Packagist](https://packagist.org/packages/blendbyte/coyotecert)[ RSS](/packages/blendbyte-coyotecert/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (10)Dependencies (22)Versions (13)Used By (1)

[![coyotecert-banner-2560x1706](https://private-user-images.githubusercontent.com/4669888/579629738-d5510075-b62c-462f-a941-1d31b48bbec3.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3ODQzNTI3NTgsIm5iZiI6MTc4NDM1MjQ1OCwicGF0aCI6Ii80NjY5ODg4LzU3OTYyOTczOC1kNTUxMDA3NS1iNjJjLTQ2MmYtYTk0MS0xZDMxYjQ4YmJlYzMucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI2MDcxOCUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNjA3MThUMDUyNzM4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NDllNDhhYjkyNWVjY2NkNDVjNDYzMDhkYWQ1ODRjMTZkNmY1NmVhMDFmZDg1ZGFjNjY0ZWI0OGMwYWU0NTcxMyZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmcmVzcG9uc2UtY29udGVudC10eXBlPWltYWdlJTJGcG5nIn0.YCGUcgG4oiCIQQbU0bHJ32H63k2jiEKAQrzuQonnM0w)](https://private-user-images.githubusercontent.com/4669888/579629738-d5510075-b62c-462f-a941-1d31b48bbec3.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3ODQzNTI3NTgsIm5iZiI6MTc4NDM1MjQ1OCwicGF0aCI6Ii80NjY5ODg4LzU3OTYyOTczOC1kNTUxMDA3NS1iNjJjLTQ2MmYtYTk0MS0xZDMxYjQ4YmJlYzMucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI2MDcxOCUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNjA3MThUMDUyNzM4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NDllNDhhYjkyNWVjY2NkNDVjNDYzMDhkYWQ1ODRjMTZkNmY1NmVhMDFmZDg1ZGFjNjY0ZWI0OGMwYWU0NTcxMyZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmcmVzcG9uc2UtY29udGVudC10eXBlPWltYWdlJTJGcG5nIn0.YCGUcgG4oiCIQQbU0bHJ32H63k2jiEKAQrzuQonnM0w)CoyoteCert
==========

[](#coyotecert)

[![Latest Version on Packagist](https://camo.githubusercontent.com/952518aa66f5d2cca6cb3bcd421769b023adf4975b5841de7cc3b499343a22a0/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f626c656e64627974652f636f796f7465636572742e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/blendbyte/coyotecert)[![License: MIT](https://camo.githubusercontent.com/a7e65aee57b11d28e4caff8b945729a66be0bb663f7f93bd24c5aa65699f148e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d626c75652e7376673f7374796c653d666c61742d737175617265)](https://github.com/blendbyte/coyotecert/blob/main/LICENSE)[![PHP](https://camo.githubusercontent.com/6ddbc13de7b150d442633160eb3ad4ae3ee4b85dcab74b1877cceb62db79ede2/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e332532422d3738376362353f7374796c653d666c61742d737175617265)](https://www.php.net)[![Tests](https://camo.githubusercontent.com/98c610c8e691ced0eb1b02f27ed32ade5ee89b62bcf54a7ca2b23a48ac9227ba/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f626c656e64627974652f636f796f7465636572742f74657374732e796d6c3f6272616e63683d6d61696e267374796c653d666c61742d737175617265266c6162656c3d7465737473)](https://github.com/blendbyte/coyotecert/actions/workflows/tests.yml)[![Static Analysis](https://camo.githubusercontent.com/f474f48da2f5bc8bf4fe3838d52f295ce7709891cd0b4c496e2a2d4e81e341bd/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f626c656e64627974652f636f796f7465636572742f7374617469632d616e616c797369732e796d6c3f6272616e63683d6d61696e267374796c653d666c61742d737175617265266c6162656c3d7068707374616e)](https://github.com/blendbyte/coyotecert/actions/workflows/static-analysis.yml)[![Coverage](https://camo.githubusercontent.com/66cc29438e9ef2127efdfb21e7bb3929060634534476d5067e01a0575a6c7412/68747470733a2f2f696d672e736869656c64732e696f2f636f6465636f762f632f6769746875622f626c656e64627974652f636f796f7465636572743f7374796c653d666c61742d737175617265)](https://codecov.io/gh/blendbyte/coyotecert)

**A PHP 8.3+ ACME v2 client for issuing, renewing, and revoking TLS certificates.** Works with Let's Encrypt, ZeroSSL, Google Trust Services, SSL.com, Buypass, and any RFC 8555-compliant CA. Fluent API, no framework dependencies, solid test coverage.

ACME (Automatic Certificate Management Environment) is the protocol behind free, automated TLS certificates. Yes, same name as the cartoon supply company. We leaned into it. CoyoteCert covers the whole thing: account management, order lifecycle, HTTP-01, DNS-01, and TLS-ALPN-01 challenges, certificate issuance, ARI smart renewal, and revocation. One `composer require blendbyte/coyotecert` and you're off. No cliff. No 🪨.

---

Contents
--------

[](#contents)

- [Why CoyoteCert](#why-coyotecert)
- [Requirements](#requirements)
- [Installation](#installation)
- [Laravel](#laravel)
- [Quick start](#quick-start)
- [Full example: nginx + automatic renewal](#full-example-nginx--automatic-renewal)
- [CLI](#cli)
- [Providers](#providers)
- [Challenge handlers](#challenge-handlers)
- [DNS-01 providers](#dns-01-providers)
- [Storage backends](#storage-backends)
- [Issuing certificates](#issuing-certificates)
- [Event callbacks](#event-callbacks)
- [CAA pre-check](#caa-pre-check)
- [Error handling](#error-handling)
- [Wildcard and multi-domain certificates](#wildcard-and-multi-domain-certificates)
- [IP address certificates](#ip-address-certificates-rfc-8738)
- [Automatic renewal](#automatic-renewal)
- [ARI: CA-guided renewal windows](#ari-ca-guided-renewal-windows)
- [ACME profiles](#acme-profiles)
- [Preferred chain selection](#preferred-chain-selection)
- [Key types](#key-types)
- [Certificate revocation](#certificate-revocation)
- [Security](#security)
- [PSR-18 HTTP client](#psr-18-http-client)
- [HTTP timeout](#http-timeout)
- [Logging](#logging)
- [Inspecting StoredCertificate](#inspecting-storedcertificate)
- [Builder reference](#builder-reference)
- [Low-level API](#low-level-api)
- [Testing with Pebble](#testing-with-pebble)

---

Why CoyoteCert
--------------

[](#why-coyotecert)

### How it stacks up

[](#how-it-stacks-up)

Every other crate in the ACME catalogue makes you do at least one of these manually: fetch EAB credentials, wire up a DNS provider, write the CLI wrapper, figure out ARI yourself. This one comes pre-loaded.

Feature**CoyoteCert**[ACMECert](https://github.com/skoerfgen/ACMECert)[acmephp](https://github.com/acmephp/acmephp)[kelunik/acme](https://github.com/kelunik/acme)[yaac](https://github.com/afosto/yaac)ARI (RFC 9773)✅✅❌❌❌EAB auto-provisioning ¹✅manualmanual❌❌IP SANs (RFC 8738)✅✅❌❌❌TLS-ALPN-01✅✅❌❌❌Built-in DNS providers**6**—3——CLI shipped with package✅—✅——Laravel integration✅————¹ "auto-provisioning" means CoyoteCert fetches EAB credentials directly from the ZeroSSL API key (no copy-pasting tokens). "manual" means EAB is supported but credentials are your problem.

Cells verified from each library's public repository, May 2026. If something's changed, open a PR. We check before merging.

### Every major CA, out of the box

[](#every-major-ca-out-of-the-box)

Built-in providers for Let's Encrypt, ZeroSSL, Google Trust Services, SSL.com, and Buypass. Full EAB support included; ZeroSSL auto-provisions credentials from your API key, no token copy-pasting. Need something more exotic? `CustomProvider` handles any RFC 8555-compliant CA.

### A CLI that ships with the package

[](#a-cli-that-ships-with-the-package)

`coyote issue` and `coyote status` come in the box. Issue a certificate with one command, inspect it with another. Drop it anywhere certbot or acme.sh would go in a PHP stack: same providers, same key types, same storage paths, cron-friendly exit codes.

### Storage that fits wherever you are

[](#storage-that-fits-wherever-you-are)

Filesystem with file locking, PDO for MySQL/PostgreSQL/SQLite, and in-memory for tests, all sharing the same interface. Switching backends never touches your issuance code.

### Six DNS-01 providers, no extra SDK needed

[](#six-dns-01-providers-no-extra-sdk-needed)

Cloudflare, Hetzner DNS, DigitalOcean, ClouDNS, AWS Route53, and shell/exec, all with automatic zone detection, post-deploy propagation checking, and fluent timeout controls. Route53 handles SigV4 signing itself; no AWS SDK required. Wildcards need DNS-01, and CoyoteCert has the providers covered.

### 🪨 Fails fast, before it costs you

[](#-fails-fast-before-it-costs-you)

CoyoteCert checks CAA DNS records for every domain before touching the CA. If a record blocks your chosen CA, you get a `CaaException` immediately, not after burning a rate-limit attempt. Same pre-flight logic verifies your HTTP token or DNS TXT record locally before the CA comes knocking. Unlike a certain cartoon coyote, we check for obstacles before ordering supplies.

### Typed exceptions that tell you what actually went wrong

[](#typed-exceptions-that-tell-you-what-actually-went-wrong)

`RateLimitException` carries the CA's `Retry-After` seconds so your retry logic is precise. `AuthException` means bad credentials, not a transient blip. `AcmeException::getSubproblems()` tells you exactly which domain in a multi-domain order was rejected and why.

### Short-lived certificates and ACME profiles

[](#short-lived-certificates-and-acme-profiles)

Let's Encrypt's `shortlived` profile gives you 6-day certs with no OCSP or CRL overhead. CoyoteCert passes the profile through and quietly ignores it on CAs that haven't caught up yet. Call `->profile()` unconditionally.

### RFC 8555 + RFC 9773, done right

[](#rfc-8555--rfc-9773-done-right)

Proper nonce handling with automatic retry on `badNonce`, JWS signing for every request, EAB for CAs that require it, and ARI (RFC 9773) so renewal windows are set by the CA rather than a fixed calendar guess.

### No default CA, no hidden opinions

[](#no-default-ca-no-hidden-opinions)

CoyoteCert has no default CA. Every call requires an explicit provider. Trust store coverage, rate limits, certificate lifetime, EAB requirements, data residency. Those trade-offs are yours, not ours.

### Also worth knowing

[](#also-worth-knowing)

**ECDSA-first:** keys default to EC P-256; EC P-384, RSA-2048, and RSA-4096 are all there.

**IP address certificates** (RFC 8738): pass an IP to `->identifiers()` and it works. `type: ip` on the order, `IP:` SANs in the CSR, no extra setup.

**PSR-18 HTTP client:** the built-in curl client needs no extra dependencies; swap it for any PSR-18 client with one builder call.

**94%+ test coverage:** unit tests with mocked responses plus a live [Pebble](https://github.com/letsencrypt/pebble) integration suite across PHP 8.3, 8.4, and 8.5. No mock-only false confidence.

**Modern PHP:** strict types, backed enums, readonly constructor promotion. No magic methods, no global state.

**Truly independent:** no CA affiliation, not maintained or financed by one.

---

Requirements
------------

[](#requirements)

PHP ^8.3 with `ext-curl`, `ext-json`, `ext-mbstring`, and `ext-openssl`.

---

Installation
------------

[](#installation)

```
composer require blendbyte/coyotecert
```

---

Laravel
-------

[](#laravel)

First-party Laravel integration is available as a separate package: [`blendbyte/coyotecert-laravel`](https://github.com/blendbyte/coyotecert-laravel).

Adds a service provider, config file, Artisan commands (`cert:issue`, `cert:renew`, `cert:status`, `cert:revoke`), HTTP-01 challenge served through your app via the cache store (no web server changes, works behind load balancers), Laravel Events, queue job support for DNS-01, and a daily scheduled renewal task. No boilerplate beyond publishing the config.

```
// In a Laravel app
use Blendbyte\CoyoteCertLaravel\Facades\Cert;

Cert::for('example.com')->issueOrRenew();
```

Full docs and installation in the [companion repo](https://github.com/blendbyte/coyotecert-laravel).

---

Quick start
-----------

[](#quick-start)

**HTTP-01** write a token to your web root:

```
use CoyoteCert\CoyoteCert;
use CoyoteCert\Challenge\Http01Handler;
use CoyoteCert\Provider\LetsEncrypt;
use CoyoteCert\Storage\FilesystemStorage;

$cert = CoyoteCert::with(new LetsEncrypt())
    ->storage(new FilesystemStorage('/var/certs'))
    ->identifiers('example.com')
    ->email('admin@example.com')
    ->challenge(new Http01Handler('/var/www/html'))
    ->issueOrRenew();
```

**DNS-01** deploy a TXT record via a DNS provider (required for wildcards):

```
use CoyoteCert\CoyoteCert;
use CoyoteCert\Challenge\Dns\CloudflareDns01Handler;
use CoyoteCert\Provider\LetsEncrypt;
use CoyoteCert\Storage\FilesystemStorage;

$cert = CoyoteCert::with(new LetsEncrypt())
    ->storage(new FilesystemStorage('/var/certs'))
    ->identifiers(['example.com', '*.example.com'])
    ->email('admin@example.com')
    ->challenge(new CloudflareDns01Handler(apiToken: 'your-api-token'))
    ->issueOrRenew();
```

Both return the same value object:

```
echo $cert->certificate; // PEM leaf certificate
echo $cert->privateKey;  // PEM private key
echo $cert->fullchain;   // PEM leaf + intermediates
echo $cert->caBundle;    // PEM intermediate chain
```

---

Full example: nginx + automatic renewal
---------------------------------------

[](#full-example-nginx--automatic-renewal)

A complete production setup: certificate issuance, PEM files on disk, nginx pointed at them, automatic reload on renewal, and a daily cron job.

**`/usr/local/bin/renew-certs.php`**

```
