acme v2 to Let'sEncrypt by dns cloudflare or your own.

v1.0.0 2023-03-03 08:22 UTC

This package is auto-updated.

Last update: 2024-05-21 11:15:36 UTC


phpunit composer

This Library helps us to obtain Let's Encrypt SSLCertificate with DNS-01 ACMEv2.

This is Pure-PHP , intend to be LE embedded WEB-PHP-App (ex. laravel).

Independent from shell command like certbot.


request issue of certificate by DNS-01.


export LE_CLOUDFLARE_TOKEN='X-811Gxxxxx'
export LE_EMAIL='yourname@example.tld'
php bin/request-issue.php 'aab.example.tld' 'aaa.example.tld'


In you php code.


/** ********
 * Prepare
use Takuya\LEClientDNS01\Account;
$cf_api_token = getenv( 'LE_CLOUDFLARE_TOKEN' );
$your_email   = getenv( 'LE_EMAIL' );
$domain_names = ["www.your-domain.tld",'*.www.your-domain.tld'];
$account = new Account( $your_email );
/** ********
 * Order certificate.
$dns = new CloudflareDNSPlugin( $cf_api_token, base_domain($domain_names[0]) );
$cli = new LetsEncryptAcmeDNS( $account );
$cli->setDomainNames( $domain_names );
$cli->setAcmeURL( LetsEncryptACMEServer::PROD );
$cli->setDnsPlugin( $dns );
$cert_and_a_key = $cli->orderNewCert();
/** ********
 * Save in your own way.
$owner_pkey = $account->private_key;
$cert_pem  = $cert_and_a_key->cert();
$cert_pkey = $cert_and_a_key->privKey();//domain pkey, not an owner's pkey. 
$full_chain = $cert_and_a_key->fullChain();
$pkcs12     = $cert_and_a_key->pkcs12('enc pass');
$cert_info = new SSLCertificateInfo( $cert_and_a_key->cert(); );

More cases.

WildCard name.

$cli->setDomainNames( ['*.your-domain.tld'] );

Single name

$cli->setDomainNames( ['www.your-domain.tld'] );

Multiple sub domain

$cli->setDomainNames( ['www.your-domain.tld','ipsec.your-domain.tld'] );

Multi , different BASE

$cli->setDomainNames( ['www.first.tld','www.second.tld'] );

Feature: Two domain in Two DNS server into One Certificate SAN

If you uses two dns server , you can set dns per domain.

For example , Cert with two domain in SAN.

cert domain
commonName example.tld
subjectAltName DNS:example.tld, DNS:example.biz

DNS-01 plugins for above.

Base Domain DNS plugin
example.tld cloudflare CloudflareDNSPlugin
example.biz your_own YourOwnPlugin

You can use Multiple Domain DNS Server API to complete LE ACME challenge.

// set dns plugin per Domain.
$cli = new LetsEncryptAcmeDNS( 'priv_key_pem', 'your_email@gmail.com' );
$dns_plugin_1 = new CloudflareDNSPlugin( 'cloudflare_token', 'example.tld' );
$dns_plugin_2 = new YourOwnPlugin( 'your_own_key', 'example.biz' );
$cli->setDnsPlugin( $dns_plugin_1, 'example.tld' );
$cli->setDnsPlugin( $dns_plugin_2, 'example.biz' );

How to write your Own DNS Plugin.

Create class and extends DNSPlugin class.

class YourOwnPlugin extends DNSPlugin{


Then, complete implementation by your code to update DNS server.

class YourOwnPlugin extends DNSPlugin{
  public function addDnsTxtRecord ( $domain, $content ): bool;{
    // TODO: write your way to add TXT Record for ACME challenge.
  public  function removeTxtRecord ( $domain, $content ): bool{
    // TODO: Write in your way, how to remove TXT Record , after ACME.


From GitHub.

composer config repositories.$repository \
vcs https://github.com/takuya/$repository  
composer require takuya/$repository:master
composer install

From composer packagist

composer require takuya/php-letencrypt-acme-dns


php: >=8.1
    "cloudflare/sdk": "^1.3",
    "acmephp/core": "^2.1",
    "pear/net_dns2": "^1.5",
    "ext-openssl": "*"

Fiber used. To use Fiber php8.1 required. Fiber used in waiting dns update.


To Check DNS TXT recoed updated.

  • This package requires Outbound UDP/53 are open.


git clone git@github.com:takuya/php-letencrypt-acme-dns.git
cd php-letencrypt-acme-dns
composer install 

## write codes, then run tests.
echo "
export LE_CLOUDFLARE_TOKEN1=Bxxxxxxxx4q8mm
export LE_CLOUDFLARE_TOKEN2=KxxxxxxxxxxPbh
export LE_BASE_DOMAIN1=txxxxx.biz
export LE_BASE_DOMAIN2=dxxxxx.com
" > ./env
source ./env
vendor/bin/phpunit --filter CloudflarePluginTest

Future Plan

I will remove acme/php dependency in the future.