This library allows you to request, renew and revoke SSL certificates provided by Let's Encrypt.
If you're looking for an easy-to-use CLI tool for managing your LE certificates, take a look at the RW ACME CLI project.
- PHP ^8.2
- OpenSSL >= 1.0.1
- cURL extension
- JSON extension
Notes:
- It's recommended to have dig installed on your system, as it will be used to fetch DNS information.
- v4 of this package only supports
php:^8.2
. If you're looking for the older versions, check out v1 or v3.
You can install the package via composer:
composer require rogierw/rw-acme-client
Create an instance of Rogierw\RwAcme\Api
client and provide it with a local account that will be used to store the account keys.
$localAccount = new \Rogierw\RwAcme\Support\LocalFileAccount(__DIR__.'/__account', 'test@example.com');
$client = new Api(localAccount: $localAccount);
You could also create a client and pass the local account data later:
$client = new Api();
// Do some stuff.
$localAccount = new \Rogierw\RwAcme\Support\LocalFileAccount(__DIR__.'/__account', 'test@example.com');
$client->setLocalAccount($localAccount);
Please note that setting a local account is required before making any of the calls detailed below.
if (!$client->account()->exists()) {
$account = $client->account()->create();
}
// Or get an existing account.
$account = $client->account()->get();
account
is the account created at the ACME (Let's Encrypt) server with data from thelocalAccount
.localAccount
handles the private/public key pair and contact email address used to sign requests to the ACME server. Depending on the implementation, this data is stored locally or, for example, in a database.
$order = $client->order()->new($account, ['example.com']);
Simply create a new order to renew an existing certificate as described above. Ensure that you use the same account as you did for the initial request.
$order = $client->order()->get($order->id);
$validationStatus = $client->domainValidation()->status($order);
Get the name and content for the validation file:
// Get the data for the HTTP challenge; filename and content.
$validationData = $client->domainValidation()->getValidationData($validationStatus, \Rogierw\RwAcme\Enums\AuthorizationChallengeEnum::HTTP);
This returns an array:
Array
(
[0] => Array
(
[type] => http-01
[identifier] => example.com
[filename] => sqQnDYNNywpkwuHeU4b4FTPI2mwSrDF13ti08YFMm9M
[content] => sqQnDYNNywpkwuHeU4b4FTPI2mwSrDF13ti08YFMm9M.kB7_eWSDdG3aWIaPSp6Uy4vLBbBI5M0COvM-AZOBcoQ
)
)
The Let's Encrypt validation server will make a request to the following URL:
http://example.com/.well-known/acme-challenge/sqQnDYNNywpkwuHeU4b4FTPI2mwSrDF13ti08YFMm9M
Get the name and the value for the TXT record:
// Get the data for the DNS challenge.
$validationData = $client->domainValidation()->getValidationData($validationStatus, \Rogierw\RwAcme\Enums\AuthorizationChallengeEnum::DNS);
This returns an array:
Array
(
[0] => Array
(
[type] => dns-01
[identifier] => example.com
[name] => _acme-challenge
[value] => 8hSNdxGNkx4MI7ZN5F8uZj3cTSMX92SGMCMHQMh0cMA
)
)
try {
$client->domainValidation()->start($account, $validationStatus[0], \Rogierw\RwAcme\Enums\AuthorizationChallengeEnum::HTTP);
} catch (DomainValidationException $exception) {
// The local HTTP challenge test has been failed...
}
try {
$client->domainValidation()->start($account, $validationStatus[0], \Rogierw\RwAcme\Enums\AuthorizationChallengeEnum::DNS);
} catch (DomainValidationException $exception) {
// The local DNS challenge test has been failed...
}
$privateKey = \Rogierw\RwAcme\Support\OpenSsl::generatePrivateKey();
$csr = \Rogierw\RwAcme\Support\OpenSsl::generateCsr(['example.com'], $privateKey);
if ($order->isReady() && $client->domainValidation()->allChallengesPassed($order)) {
$client->order()->finalize($order, $csr);
}
if ($order->isFinalized()) {
$certificateBundle = $client->certificate()->getBundle($order);
}
if ($order->isValid()) {
$client->certificate()->revoke($certificateBundle->fullchain);
}