Back to blog

PHP ACME Clients in 2026: CoyoteCert, ACMECert, Acme PHP, and the Rest

8 min read
On this page

At some point, you need TLS certificates managed from PHP. Maybe it's a multi-tenant app where tenants bring custom domains. Maybe it's a provisioning pipeline that needs to issue certs without SSH access. Maybe you're just tired of certbot's snap drama and want something that lives in your codebase.

Whatever the reason, you need a PHP ACME client. Which immediately raises the question: which one?

There are five libraries worth considering, a handful of abandoned ones, and the ever-tempting option of just talking to the ACME API directly (don't). Here's what we found.

The landscape

Five PHP libraries implement ACME v2 (RFC 8555) and are actively maintained or at least not formally abandoned:

CoyoteCert (ours). PHP 8.3+, strict types throughout, built-in DNS providers for wildcard automation, Laravel integration, CLI included. We built this, so we're biased. We'll be upfront about that throughout this post.

ACMECert by skoerfgen. A solid single-class library that covers the protocol well. Has ARI support (RFC 9773) and TLS-ALPN-01. No DNS providers, no CLI, no framework integration. Clean and minimal.

Acme PHP by the acmephp project, now maintained by ZeroSSL. Historically the most established PHP ACME implementation. CLI-first with a config file approach. The library components (acmephp/core, acmephp/ssl) can be used independently for integration. Has DNS providers for Route53, Cloudflare, and DigitalOcean. Last tagged release: June 2022.

kelunik/acme by Niklas Keller. Built on amphp, PHP's async framework. If you're already in the amphp ecosystem, this fits naturally. If you're not, you're pulling in an async runtime for certificate management, which is probably more machinery than you need.

yaac by Afosto. Simple, focused, gets the job done for basic flows. No built-in DNS providers, no TLS-ALPN-01, no ARI. Fine if all you need is a standard cert for a single domain.

There are others (LEClient, le-acme2-php, lescript), but they're either unmaintained, feature-limited, or both. We're not covering them here.

What actually matters when choosing

Before the feature table, let's talk about what drives the decision in practice.

Maintenance and activity

This matters more than feature count. An ACME client that doesn't keep up with CA policy changes, new RFCs, or PHP version bumps will bite you eventually. Let's Encrypt tweaks things. CAs add requirements. PHP deprecates functions. You need a library that keeps moving.

Acme PHP's last tagged release is from June 2022. The repo says "maintained by ZeroSSL," and there have been commits since then, but four years without a release is a long time in a protocol that's actively evolving. ARI (RFC 9773) landed in 2024. If your library doesn't support it, you're missing the CA's hint about when to renew, which means you're either renewing too early or cutting it too close.

Challenge type support

HTTP-01 is the baseline. Everyone supports it. It works for single domains on servers you control.

DNS-01 is what you need for wildcards. Not everyone supports it, and even fewer ship built-in DNS provider handlers. Without those, you're writing the API integration yourself (Cloudflare, Route 53, Hetzner, etc.), which is exactly the kind of boilerplate a library should handle.

TLS-ALPN-01 is niche but matters if you can't modify your webroot or DNS. Only CoyoteCert and ACMECert support it.

Typing and developer experience

This might sound like a nice-to-have, but if you're integrating ACME into a production application, the difference between "returns an associative array with string keys" and "returns a typed Certificate object with methods" is the difference between debugging at 3 AM with var_dump and debugging at 3 AM with your IDE's autocomplete.

The comparison

Here's where each library stands on the features that matter for production use. We verified these against each library's public repository.

Feature CoyoteCert ACMECert Acme PHP kelunik/acme yaac
ARI (RFC 9773)
EAB auto-provisioning manual manual
IP SANs (RFC 8738)
TLS-ALPN-01
Built-in DNS providers 6 0 3 0 0
CLI included
Laravel integration
PHP version 8.3+ 5.3+ 7.1+ 8.1+ 7.2+
Last release 2026 2025 2022 2024 2022

A few things jump out.

ARI (ACME Renewal Information, RFC 9773) is how CAs tell your client the optimal renewal window. Without it, you're guessing: renew at 30 days before expiry and hope that lines up with what the CA expects. With it, the CA tells you exactly when to come back. Only CoyoteCert and ACMECert support this.

EAB (External Account Binding) matters for CAs like ZeroSSL and SSL.com that require it. CoyoteCert auto-provisions EAB credentials from your ZeroSSL API key, so you don't have to copy-paste tokens from a dashboard. ACMECert and Acme PHP support EAB but leave the credential wrangling to you.

The DNS provider count matters because DNS-01 without built-in providers means you're writing API glue yourself. CoyoteCert ships handlers for Cloudflare, Route 53, DigitalOcean, ClouDNS, Hetzner, and a sixth (check the docs for the latest). Acme PHP has Route 53, Cloudflare, and DigitalOcean. Everyone else: bring your own.

Code comparison: issuing a certificate

Same task, three libraries. Issue a cert for example.com with Let's Encrypt.

CoyoteCert

use Blendbyte\CoyoteCert\CoyoteCert;
use Blendbyte\CoyoteCert\Provider\LetsEncrypt;
use Blendbyte\CoyoteCert\Storage\FilesystemStorage;

$cert = CoyoteCert::with(new LetsEncrypt())
    ->storage(new FilesystemStorage('/var/certs'))
    ->identifiers(['example.com'])
    ->email('admin@example.com')
    ->issueOrRenew();

// $cert->fullchain, $cert->privateKey

Fluent API, typed return. issueOrRenew() is idempotent: if a valid cert exists and isn't due for renewal, it returns the existing one.

ACMECert

$ac = new ACMECert();
$ac->loadAccountKey('file://account.pem');

$handler = function ($opts) {
    // You implement the HTTP-01 challenge handler
    // Write the token file, return a cleanup callback
};

$cert = $ac->getCertificateChain(
    'mailto:admin@example.com',
    ['example.com' => ['challenge' => 'http-01']],
    $handler
);

// $cert is a PEM string

Single class, minimal dependencies. You handle challenge logic yourself. The return is a PEM string, not a typed object. Clean if you want full control.

Acme PHP

// Acme PHP is primarily CLI-driven
// Library usage via acmephp/core:
$client = new AcmeClient($secureHttpClient, $directoryUrl);
$client->registerAccount(null, 'mailto:admin@example.com');

$order = $client->requestOrder(['example.com']);
// ... authorize, solve challenges, finalize, download

The core library is lower-level. You're managing the ACME flow step by step: create order, get authorizations, solve challenges, finalize, download certificate. More control, more code. The CLI handles all of this behind a config file if you prefer that approach.

When to use each

CoyoteCert if you're building certificate management into a PHP application. Multi-tenant SaaS, API-driven provisioning, Laravel integration, wildcard automation with DNS-01. It's opinionated about modern PHP (8.3+, strict types) and handles the most edge cases out of the box.

ACMECert if you want a minimal, dependency-light library and you're comfortable implementing challenge handlers yourself. Good for custom setups where you need TLS-ALPN-01 or IP certificates but don't want a framework.

Acme PHP if you need a CLI tool for server-side certificate management and you're fine with a library that hasn't seen a release in four years. The core components still work, and ZeroSSL's involvement provides some assurance of continuity, but the development pace is a concern for long-term projects.

kelunik/acme if you're already using amphp and want async certificate management. Not worth pulling in amphp solely for this.

yaac if you have a simple use case and want the smallest possible library. It does less, but what it does, it does simply.

When to just use certbot

Real talk: if you're running a standard server with a few domains and you just need certs to renew automatically, certbot is still fine. It has its warts (we wrote about those), but for the "single server, cron job, done" use case, it works and has a decade of battle testing.

You need a PHP ACME client when:

  • Certificate management is part of your application logic (multi-tenant, API-driven)
  • You're in an environment without shell access (shared hosting, some PaaS)
  • You want certificates managed by the same codebase that uses them
  • You need to support multiple CAs and switch between them programmatically
  • You're automating wildcard issuance as part of a provisioning pipeline

If none of those apply, certbot with a cron job is honest, boring, and correct.

Disclosure and methodology

We built CoyoteCert. We're obviously going to think it's the best option. We've tried to be fair in this comparison, verified every feature claim against each library's public repository, and included scenarios where other tools are the better choice.

The comparison table matches what's published on coyotecert.com, which includes an open invitation: if anything is wrong, open a PR. We verify before merging.

If you disagree with anything here, check the repos yourself. The links are all above.

Need help with certificate automation?

We've built certificate provisioning into client applications handling thousands of domains. If you're evaluating how to handle TLS in a multi-tenant setup, or you need help integrating ACME into your PHP application, talk to us. We'll tell you whether you need a library, a CLI tool, or just a properly configured certbot.

Written by

Blendbyte

Blendbyte Team

We run what we write about. Production experience only, no theory.

Need help with your setup?

We build and run infrastructure for clients every day. If you need help with your server, cloud, or software setup, talk directly to the engineers who do the work.

Let's talk