stonemax/acme2 is a simple PHP tool to manage TLS certificates with ACME-compliant CAs, it's mainly used with let's Encrypt, support for both ESA and ECDSA certifacates. It will not set challenge file or DNS record for you, you can do these jobs manually, or automaticlly with you own code and hooks in stonemax/acme2.
The current version is 1.0.4
.
This version works with PHP-5.4.0 or higher, if you need to generate ECDSA certificates, PHP version should be 7.1.0 or higher. PHP need curl and openssl extensons enabled in addition. Although acme2 uses composer, but composer is just uesd as an autoloader, this porject has no any third party dependencies.
Clone this project and run compose install
.
cd example-directory
git clone git@github.com:stonemax/acme2.git .
composer install
The basic methods and its necessary arguments are shown here. An example is supplied in examples/.
$emailList = ['alert@example.com']; // Email list as contact info
$storagePath = './data'; // Account data and certificates files will be stored here
$staging = TRUE; // Using stage environment or not, make sure to empty $storagePath directory after you change from staging/test server to the real one
$client = new Client($emailList, $storagePath, $staging); // Initiating a client
After Client
had been initiated, a Let's Encrypt account will be created and the account data will be placed in $storagePath
.
When you reinitialize the client, the accout will not be created again.
$account = $client->getAccount(); // Get account service instance
$account->updateAccountContact($emailList); // Update account contact info with an email list
$account->updateAccountKey(); // Regenerate private/public key pair,the old will be replaced by the new
$account->deactivateAccount(); // Deactive the account
These methods bellow are mainly used for generating certificates.
/* Domains and challenges info for a single certificate with multiple SAN: abc.example.com, *.www.example.com and www.example.com */
$domainInfo = [
CommonConstant::CHALLENGE_TYPE_HTTP => [
'abc.example.com'
],
CommonConstant::CHALLENGE_TYPE_DNS => [
'*.www.example.com',
'www.example.com',
],
];
$algorithm = CommonConstant::KEY_PAIR_TYPE_RSA; // Generate RSA certificates, `CommonConstant::KEY_PAIR_TYPE_EC` for ECDSA certificates
$order = $client->getOrder($domainInfo, $algorithm, TRUE); // Get an order service instance
$order->getPendingChallengeList(); // Get all authorization challenges for domains
$order->getCertificateFile(); // Get certificates, such as certificates path, private/public key pair path, valid time
$order->revokeCertificate($reason); // Revoke certificates, the certificaes ara unavailable after revoked
The prototype of method getOrder()
is shown as bellow:
public function getOrder(array $domainInfo,int $algorithm, bool $generateNewOder = TRUE): OrderService
The third param $generateNewOder
controls whether a new order need to be generated. When $generateNewOder == TRUE
, all files under original certificates directory will be removed in order to generate new certificates; When $generateNewOder == FALSE
, it will return an existing order service instance used to revoke certificates generally.
$challengeList = $order->getPendingChallengeList();
foreach ($challengeList as $challenge)
{
$challenge->getType(); // Challenge type, http-01 or dns-01
$challenge->getCredential(); // Challenge detail, http-01 with file name and file content, dns-01 with dns record value
$challenge->verify(); // Do verifying operation, this method will loop infinitely until verification passed
}
The prototype of method verify()
is shown as bellow:
public function verify(int $verifyLocallyTimeout = 0, int $verifyCATimeout = 0): bool
- The first param
$verifyLocallyTimeout
stands for the timeout of local verification. Default value 0 won't trigger time-out mechanism; - The second param
$verifyCATimeout
stand for the timeout of Let's Encrypt verification. Default value 0 won't trigger time-out mechanism.
When generating a certificate, Let's Encrypt need to verify the ownership and validity of the domain. There are two types of verification: http-01, dns-01.
In the following, we take www.example.com
as an example.
As this type, Let's Encrypt will access a specific file under web server to verify domain.
As this time, the $challenge
info is like bellow.
echo $challenge->getType();
/* output */
'http-01'
print_r($challenge->getCredential());
/* output */
[
'identifier' => 'www.example.com',
'fileName' => 'RzMY-HDa1P0DwZalmRyB7wLBNI8fb11LkxdXzNrhA1Y',
'fileContent' => 'RzMY-HDa1P0DwZalmRyB7wLBNI8fb11LkxdXzNrhA1Y.CNWZAGtAHIUpstBEckq9W_-0ZKxO-IbxF9Y8J_svbqo',
];
With the aboved $challenge
info, Let's Encrypt will access "http://www.example.com/.well-known/acme-challenge/HDa1P0DwZalmRyB7wLBNI8fb11LkxdXzNrhA1Y", and the file content will be expected as "RzMY-HDa1P0DwZalmRyB7wLBNI8fb11LkxdXzNrhA1Y.CNWZAGtAHIUpstBEckq9W_-0ZKxO-IbxF9Y8J_svbqo".
As this type, you should add a DNS TXT record for domain, Let's Encrypt will check domain's specific TXT record value for verification.
As this time, the $challenge
info is like bellow.
echo $challenge->getType();
/* output */
'dns-01'
print_r($challenge->getCredential());
/* output */
[
'identifier' => 'www.example.com',
'dnsContent' => 'xQwerUEsL8UVc6tIahwIVY4e8N5MAf1xhyY20AELurk',
];
With the aboved $challenge
info, you shuoud add a TXT record for domain www.example.com
, the record name should be "_acme-challenge.www.example.com", the record value should be "xQwerUEsL8UVc6tIahwIVY4e8N5MAf1xhyY20AELurk".
It's worth noting that you should set TTL as short as possible to let the record take effect as soon as possible.
This tool supports generating certificates for wildcard domains.
A wildcard domain, like *.www.example.com
, will be verified as www.example.com
, this means the DNS record name should be _acme-challenge.www.example.com
.
Here is a simple summary for dns-01 challenges about domain and DNS record.
Domain | DNS record name | Type | TTL | DNS record value(just examples) |
---|---|---|---|---|
example.com | _acme-challenge.example.com | TXT | 60 | xQwerUEsL8UVc6tIahwIVY4e8N5MAf1xhyY20AELurk |
*.example.com | _acme-challenge.example.com | TXT | 60 | G2dOkzSjW3ohib5doPRDrz5a5l8JB1qU8CxURtzF7aE |
www.example.com | _acme-challenge.www.example.com | TXT | 60 | x1sc0pIwN5Sbqx0NO0QQeu8LxIfhbM2eTjwdWliYxF1 |
*.www.example.com | _acme-challenge.www.example.com | TXT | 60 | eZ9ViY12gKfdruYHOO7Lu74ICXeQRMDLp5GuHLvPsf7 |
Project supplies a full example under directory examples/.
This Project had got a lot of inspirations from yourivw/LEClient. Thanks!
This project is licensed under the MIT License, see the LICENSE file for detail.