helios-ag / leclient
PHP LetsEncrypt 客户端库,用于 ACME v2
Requires
- php: >=5.2
- ext-openssl: *
Requires (Dev)
- psr/log: ^1.1
This package is auto-updated.
Last update: 2024-09-16 05:57:32 UTC
README
PHP LetsEncrypt 客户端库,用于 ACME v2。此客户端的目标是提供一个易于使用和集成的解决方案,通过 PHP 创建由 Let's Encrypt 签发的 SSL/TLS 证书。用户必须能够访问 web 服务器或 DNS 管理,才能验证域名是否可访问/由用户所有。
当前版本
当前版本为 1.2.2
入门指南
以下说明将指导您开始使用此客户端库。如果您有任何问题或发现任何问题,请随时提交问题,我会尽力查看。
还可以查看 Let's Encrypt 文档 以获取有关 Let's Encrypt 和 ACME 的更多信息。
先决条件
所需的最小 PHP 版本是 5.2.0。需要 7.1.0 版本才能使用 EC 密钥。当尝试使用低于 7.1.0 版本的 PHP 生成 EC 密钥时,生成 EC 密钥的函数将抛出异常。
版本 1.0.0 将继续提供,但将不再维护。
此客户端还依赖于 cURL 和 OpenSSL。
安装
使用 composer
composer require yourivw/leclient
建议为脚本设置更高的最大执行时间,以留出一些执行时间。有多种方法可以做到这一点。一种方法是在页面顶部添加以下内容
ini_set('max_execution_time', 120); // Maximum execution time in seconds.
用法
这里显示了基本功能和必要的参数。每个类中还包括了扩展描述。
从版本 1.1.6 开始,还可以使用 PSR-3 日志记录器 (\Psr\Log\LoggerInterface) 初始化 LEClient。
初始化客户端
use LEClient\LEClient; $client = new LEClient($email); // Initiating a basic LEClient with an array of string e-mail address(es). $client = new LEClient($email, LEClient::LE_STAGING); // Initiating a LECLient and use the LetsEncrypt staging URL. $client = new LEClient($email, LEClient::LE_PRODUCTION); // Initiating a LECLient and use the LetsEncrypt production URL. $client = new LEClient($email, true); // Initiating a LECLient and use the LetsEncrypt staging URL. $client = new LEClient($email, true, $logger); // Initiating a LEClient and use a PSR-3 logger (\Psr\Log\LoggerInterface). $client = new LEClient($email, true, LEClient::LOG_STATUS); // Initiating a LEClient and log status messages (LOG_DEBUG for full debugging). $client = new LEClient($email, true, LEClient::LOG_STATUS, 'keys/'); // Initiating a LEClient and select custom certificate keys directory (string or array) $client = new LEClient($email, true, LEClient::LOG_STATUS, 'keys/', '__account/'); // Initiating a LEClient and select custom account keys directory (string or array)
如果未找到帐户,客户端将自动创建一个新帐户。它将转发在初始化过程中提供的电子邮件地址,如上所示。
使用帐户函数
$acct = $client->getAccount(); // Retrieves the LetsEncrypt Account instance created by the client. $acct->updateAccount($email); // Updates the account with new contact information. Supply an array of string e-mail address(es). $acct->changeAccountKeys(); // Generates a new RSA keypair for the account and updates the keys with LetsEncrypt. $acct->deactivateAccount(); // Deactivates the account with LetsEncrypt.
创建证书订单实例。如果找到已存储在本地的订单,它将使用此订单。否则,它将创建一个新订单。如果提供的域名与订单不匹配,也将创建新订单。构造 Let's Encrypt 订单实例
$order = $client->getOrCreateOrder($basename, $domains); // Get or create order. The basename is preferably the top domain name. This will be the directory in which the keys are stored. Supply an array of string domain names to create a certificate for. $order = $client->getOrCreateOrder($basename, $domains, $keyType); // Get or create order. keyType can be set to "ec" to get ECDSA certificate. "rsa-4096" is default value. Accepts ALGO-SIZE format. $order = $client->getOrCreateOrder($basename, $domains, $keyType, $notBefore); // Get or create order. Supply a notBefore date as a string similar to 0000-00-00T00:00:00Z (yyyy-mm-dd hh:mm:ss). $order = $client->getOrCreateOrder($basename, $domains, $keyType, $notBefore, $notAfter); // Get or create order. Supply a notBefore and notAfter date as a string similar to 0000-00-00T00:00:00Z (yyyy-mm-dd hh:mm:ss).
使用订单函数
use LEClient\LEOrder; $valid = $order->allAuthorizationsValid(); // Check whether all authorizations in this order instance are valid. $pending = $order->getPendingAuthorizations($type); // Get an array of pending authorizations. Performing authorizations is described further on. Type is LEOrder::CHALLENGE_TYPE_HTTP or LEOrder::CHALLENGE_TYPE_DNS. $verify = $order->verifyPendingOrderAuthorization($identifier, $type); // Verify a pending order. The identifier is a string domain name. Type is LEOrder::CHALLENGE_TYPE_HTTP or LEOrder::CHALLENGE_TYPE_DNS. $deactivate = $order->deactivateOrderAuthorization($identifier); // Deactivate an authorization. The identifier is a string domain name. $finalize = $order->finalizeOrder(); // Finalize the order and generate a Certificate Signing Request automatically. $finalize = $order->finalizeOrder($csr); // Finalize the order with a custom Certificate Signing Request string. $finalized = $order->isFinalized(); // Check whether the order is finalized. $cert = $order->getCertificate(); // Retrieves the certificate and stores it in the keys directory. $revoke = $order->revokeCertificate(); // Revoke the certificate without a reason. $revoke = $order->revokeCertificate($reason); // Revoke the certificate with a reason integer as found in section 5.3.1 of RFC5280.
辅助函数
use LEClient\LEFunctions; LEFunctions::RSAGenerateKeys($directory, $privateKeyFile, $publicKeyFile); // Generate a RSA keypair in the given directory. Variables privateKeyFile and publicKeyFile are optional and have default values private.pem and public.pem. LEFunctions::ECGenerateKeys($directory, $privateKeyFile, $publicKeyFile); // Generate a EC keypair in the given directory (PHP 7.1+ required). Variables privateKeyFile and publicKeyFile are optional and have default values private.pem and public.pem. LEFunctions::Base64UrlSafeEncode($input); // Encode the input string as a base64 URL safe string. LEFunctions::Base64UrlSafeDecode($input); // Decode a base64 URL safe encoded string. LEFunctions::log($data, $function); // Print the data. The function variable is optional and defaults to the calling function's name. LEFunctions::checkHTTPChallenge($domain, $token, $keyAuthorization); // Checks whether the HTTP challenge is valid. Performing authorizations is described further on. LEFunctions::checkDNSChallenge($domain, $DNSDigest); // Checks whether the DNS challenge is valid. Performing authorizations is described further on. LEFunctions::createhtaccess($directory); // Created a simple .htaccess file in the directory supplied, denying all visitors.
文件系统结构
LEClient 将帐户密钥、证书密钥、证书和订单数据存储在文件系统中。默认情况下,使用的文件夹结构如下,相对于您的当前工作目录
keys/ Top-level LEClient folder
public.pem Your certificate’s public key
private.pem Your certificate’s private key
order A file used to store the order URL
fullchain.crt The full-chain certificate
certificate.crt The certificate
__account/ An internal folder for LEClient to store your account keys
public.pem Your ACME account’s public key
private.pem Your ACME account’s private key
.htaccess An automatically-generated .htaccess to prevent accidental exposure
您可以通过在创建 LEClient
时传递值来自定义这些位置,这些值将传递给 $certificateKeys
和 $accountKeys
构造参数。
传递字符串将更改顶级 LEClient 文件夹的位置和名称,以及帐户密钥文件夹的名称。请注意,在传递字符串时,帐户密钥文件夹始终是顶级文件夹的子文件夹,这意味着
$client = new LEClient('email@example.com', LEClient::PRODUCTION, LEClient::LOG_OFF, 'path/to/my/key/folder/', 'my_account_folder');
将导致以下结构
path/to/my/key/folder/
public.pem
…
my_account_folder/
public.pem
…
如果您想要更精确地控制各种文件存储的确切位置,您可以改为传递数组给 $certificateKeys
和 $accountKeys
参数。如果您向其中一个传递数组,则必须向两个都传递数组。
$client = new LEClient('email@example.com', LEClient::PRODUCTION, LEClient::LOG_OFF, [ 'public_key' => 'path/to/public/key.pem', // Required 'private_key' => 'path/to/private/key.pem', // Required 'order' => 'path/to/order.txt', // Required 'certificate' => 'path/to/certificate.crt', // One or both of certificate and fullchain_certificate 'fullchain_certificate' => 'path/to/fullchain.crt' // must be provided. ], [ 'public_key' => 'path/to/account/public/key.pem', // Required 'private_key' => 'path/to/account/private/key.pem' // Required ]);
授权挑战
Let's Encrypt (ACME) 对您希望在证书中包含的域名进行授权,以验证您确实可以访问该特定域名。因此,在创建订单时,将为每个域名添加一个授权。如果某个域名最近(在过去的30天内)已被您的账户验证过,例如在其他订单中,则无需再次验证。此时,可以通过向文件发起HTTP请求(http-01)或DNS TXT记录(dns-01)来验证域名。客户端通过调用getPendingAuthorizations()提供所需数据以进行选择的验证。由于创建文件或DNS记录的每个服务器都不同,因此客户端中不实现这一点。用户满足挑战要求后,必须调用verifyPendingOrderAuthorization()进行验证。此客户端将首先通过checkHTTPChallenge()或checkDNSChallenge()自行验证挑战,然后开始由Let's Encrypt进行验证。请注意,通配符域名只能通过DNS挑战进行验证。以下展示了两种挑战的示例。
HTTP挑战
对于此示例,我们假设还有一个域名需要验证。
use LEClient\LEOrder; $pending = $order->getPendingAuthorizations(LEOrder::CHALLENGE_TYPE_HTTP);
这会返回一个数组
Array
(
[0] => Array
(
[type] => http-01
[identifier] => test.example.org
[filename] => A8Q1DAVcd_k_oKAC0D_y4ln2IWrRX51jmXnR9UMMtOb
[content] => A8Q1DAVcd_k_oKAC0D_y4ln2IWrRX51jmXnR9UMMtOb.C4kIiiwfcynb3i48AQVtZRtNrD51z4JiIrdQsgVqcL8
)
)
对于成功的验证,将向以下URL发起请求
http://test.example.org/.well-known/acme-challenge/A8Q1DAVcd_k_oKAC0D_y4ln2IWrRX51jmXnR9UMMtOb
此文件的应设置为上面数组中的内容。用户应在验证授权之前创建此文件。
DNS挑战
对于此示例,我们假设还有两个域名需要验证。其中一个是一个通配符域名。此示例中的第二个域名是为了演示目的添加的。向证书中添加一个子域名,而该子域名也已被通配符域名覆盖,并不会带来太大的增值。
$pending = $order->getPendingAuthorizations(LEOrder::CHALLENGE_TYPE_DNS);
这会返回一个数组
Array
(
[0] => Array
(
[type] => dns-01
[identifier] => example.org
[DNSDigest] => FV5HgbpjIYe1x9MkPI81Nffo2oA-Jo2S88gCL7-Ky5P
)
[1] => Array
(
[type] => dns-01
[identifier] => test.example.org
[DNSDigest] => WM5YIsgaZQv1b9DbRZ81EwCf2fi-Af2JlgxTC7-Up5D
)
)
对于成功的验证,应创建如下DNS记录
如果需要,可以将TTL值设置得更高,但我更倾向于将其保持在尽可能低。为了确保验证成功,建议运行一个使用DNS挑战的两部分脚本,中间有一定的等待时间,以便DNS记录更新。用户本人应确保在记录可以验证之前设置此DNS记录。DNS记录名称也取决于您的提供商,因此getPendingAuthorizations()不会提供现成的记录名称。一些提供商仅接受像_acme-challenge
这样的名称,不带顶级域名,例如_acme-challenge.example.org
。一些提供商接受(需要?)像上面显示的完整名称。
通配符域名,如*.example.org
,将验证为example.org
,如上所示。这意味着DNS记录名称应该是_acme-challenge.example.org
完整示例
对于HTTP和DNS授权,完整示例可在项目的主代码目录中找到。HTTP授权示例包含在一个文件中。如上所述,DNS授权示例分为两部分,以便在同时允许DNS记录更新。虽然记录的TTL可能很低,但在对记录进行修改后,您的提供商可能需要一些时间来更新您的DNS记录。
如果您无法获取这些示例或客户端库,请尝试查看上面提到的Let's Encrypt文档。为了使示例代码正常工作,请确保用您自己的信息替换所有'example.org'信息。使用预设示例数据运行示例时,示例将失败。
安全
安全性是关于SSL/TLS证书的一个重要主题,当然。由于这个客户端是PHP脚本,因此很可能这段代码正在Web服务器上运行。很明显,您存储在Web服务器上的私钥绝不能从Web上访问。当客户端第一次创建密钥目录时,它将在这个目录中存储一个.htaccess文件,拒绝所有访问者。请务必确保您的密钥不会被Web访问!如果您的私钥被公开,我绝不承担责任。如果这种情况发生,最简单的解决方案是更改您的账户密钥(如上所述)或停用您的账户并创建一个新的账户。接下来,创建一个新的证书。
许可协议
本项目采用MIT许可协议 - 有关详细信息,请参阅LICENSE文件。