ACME a Let’s Encrypt
Driver acme je natívny klient ACME v2 (RFC 8555). Transport zabezpečuje HTTP klient Laravelu, CSR ext-openssl a každý podpis, JWK aj parsovanie X.509 pochádza z crypto-for-laravel — bez externého ACME či kryptografického SDK. Nasmerujte ho na adresár certifikačnej autority, zadajte kontaktnú adresu a vystavujte:
CERTIFICATES_DRIVER=acme
CERTIFICATES_ACME_DIRECTORY=https://acme-staging-v02.api.letsencrypt.org/directory
CERTIFICATES_ACME_CONTACT=[email protected]
CERTIFICATES_ACME_HTTP_DISK=local
CERTIFICATES_ACME_STORE_DISK=local// config/certificates.php → 'default' => 'acme', or:
Certificates::for('app.example.com')->using('acme')->issue();Počas testovania používajte staging adresár Let’s Encrypt — je uvedený v publikovanej konfigurácii — a na produkčný prepnite, keď vystavovanie funguje.
Kľúče drivera
| Kľúč | Env | Predvolené | Účel |
|---|---|---|---|
directory | CERTIFICATES_ACME_DIRECTORY | produkcia Let’s Encrypt | URL adresára ACME v2 certifikačnej autority. |
contact | CERTIFICATES_ACME_CONTACT | null | E-mail, ktorý autorita dostane pri registrácii ako kontakt mailto:. |
account.key_type | CERTIFICATES_ACME_KEY_TYPE | EC | Generovaný kľúč účtu: EC (P-256) alebo RSA (2048 bitov) — presne takto, iná hodnota vyhodí výnimku. |
account.disk | CERTIFICATES_ACME_ACCOUNT_DISK | local | Disk s kľúčom účtu a záznamami účtov. |
account.key_path | CERTIFICATES_ACME_ACCOUNT_KEY | acme/account.pem | Cesta ku kľúču účtu na tomto disku. |
account.auto_register | CERTIFICATES_ACME_AUTO_REGISTER | true | Vygenerovať kľúč pri prvom použití; false vyžaduje kľúč na disku. |
solver | CERTIFICATES_ACME_SOLVER | null | Názov triedy AcmeChallengeSolver; null alebo prázdna hodnota použije HTTP-01 solver, trieda, ktorá nie je AcmeChallengeSolver, vyhodí výnimku. Typ výzvy určuje metóda type() solvera. |
http.disk | CERTIFICATES_ACME_HTTP_DISK | local | Disk, na ktorý sa zapisujú súbory s tokenmi HTTP-01. |
http.path | CERTIFICATES_ACME_HTTP_PATH | acme-challenge | Adresár pre súbory s tokenmi. |
store.disk | CERTIFICATES_ACME_STORE_DISK | local | Disk pre vystavený materiál. |
store.path | CERTIFICATES_ACME_STORE_PATH | certificates | Adresár pre vystavený materiál. |
poll.attempts | CERTIFICATES_ACME_POLL_ATTEMPTS | 30 | Maximálny počet kontrol pri overení a finalizácii. |
poll.seconds | CERTIFICATES_ACME_POLL_SECONDS | 2 | Sekundy medzi kontrolami. |
verify | CERTIFICATES_ACME_VERIFY | true | Overovanie TLS voči autorite: cesta k CA balíku, true alebo null (1, on, yes) pre systémový balík, alebo false na vypnutie. Pole či float vyhodí výnimku. |
Priebeh objednávky
- Účet sa v nakonfigurovanom adresári zaregistruje, prípadne sa použije existujúci.
- Pre všetky domény sa vytvorí nová objednávka. Pri každej autorizácii sa vyberie výzva typu, ktorý vracia type() solvera, solver ju zverejní, autorita dostane pokyn na overenie a autorizácia sa opakovane kontroluje (poll.attempts × poll.seconds). Upratanie solvera prebehne potom vždy, aj pri chybe.
- Vygeneruje sa nový 2048-bitový RSA kľúč certifikátu a CSR pre všetky domény; objednávka sa finalizuje a kontroluje, kým nie je platná.
- Certifikát sa stiahne, rozdelí na koncový certifikát a reťazec a uloží sa spolu s privátnym kľúčom.
- Každá chyba protokolu vyhodí AcmeException — adresár, nonce, účet, objednávka, výzva, finalizácia alebo stiahnutie.
HTTP-01
Predvolený solver zapíše key authorization do súboru pomenovaného podľa tokenu v adresári http.path na disku http.disk. Vaša aplikácia musí obsah tohto súboru servírovať na /.well-known/acme-challenge/{token} pre každú overovanú doménu. Po skončení overenia sa súbor zmaže.
Kľúč účtu
Pri prvom použití sa kľúč účtu vygeneruje a uloží do account.key_path na disku account.disk (account.auto_register): EC vytvorí kľúč P-256, RSA 2048-bitový. Kľúč, ktorý tam umiestnite sami, sa použije bez zmeny — prijímajú sa EC P-256 aj P-384 a každý podpisuje vlastným algoritmom (ES256 / ES384). Ak je auto_register vypnuté a na disku kľúč nie je, vystavenie vyhodí AcmeException.
Samotný účet sa eviduje pre každý adresár autority zvlášť, vedľa kľúča ({key_path}.{sha256(directory)}.kid), a je viazaný na kľúč, s ktorým sa registroval. Prechod zo stagingu na produkciu pri ďalšom vystavení zaregistruje produkčný účet namiesto opakovaného použitia staging účtu, návrat späť použije staging účet a vymenený kľúč sa zaregistruje nanovo, namiesto toho, aby podpisoval pod účtom predchodcu. Opätovná registrácia už známeho kľúča je bezpečná — autorita vráti existujúci účet.
verify riadi overovanie TLS pri spojení s autoritou: cesta k CA balíku, true alebo null pre systémový balík, alebo false na vypnutie (neodporúčame). Akýkoľvek iný reťazec sa číta ako cesta k balíku, takže preklep zlyhá pri handshaku namiesto toho, aby overovanie vypol.
Kam sa certifikát uloží
Vystavený materiál sa zapíše do store.path na disku store.disk, jeden adresár pre každý názov certifikátu:
certificates/ path on the disk
└── generated-tls-app-example-com/ Certificates::certificateName($domain)
├── certificate.pem leaf certificate
├── private.key private key
└── chain.pem intermediate chain, when presentKontajner viaže kontrakt CertificateStore na to isté úložisko, takže PEM súbory si môžete načítať späť — napríklad pre webový server — a spracovať ich cez CertificateMapper:
use RoundlyConsulting\Certificates\Contracts\CertificateStore;
use RoundlyConsulting\Certificates\Facades\Certificates;
$material = app(CertificateStore::class)->get(Certificates::certificateName('app.example.com'));
$material?->certificatePem; // leaf certificate
$material?->privateKeyPem; // private key
$material?->chainPem; // intermediates, or null
$material?->fullChainPem(); // leaf followed by the chainuse RoundlyConsulting\Certificates\Support\CertificateMapper;
$parsed = app(CertificateMapper::class)->parse($material->certificatePem);
$parsed->commonName; // 'app.example.com'
$parsed->subjectAltNames; // list<string>
$parsed->notBefore; // CarbonImmutable
$parsed->notAfter; // CarbonImmutable
$parsed->issuer; // issuer CN, or its organization
$parsed->serial; // upper-case hex
$parsed->fingerprint; // upper-case SHA-256 hex
$parsed->isExpired(); // boolDNS-01
DNS-01 je bod rozšírenia — balík nedodáva žiadne SDK DNS poskytovateľa. Rozšírte DnsChallengeSolver a implementujte publishRecord() a removeRecord() nad API vášho DNS poskytovateľa; dostanú názov a hodnotu TXT záznamu:
use RoundlyConsulting\Certificates\ChallengeSolvers\DnsChallengeSolver;
final class Route53Solver extends DnsChallengeSolver
{
protected function publishRecord(string $name, string $value): void { /* upsert TXT */ }
protected function removeRecord(string $name, string $value): void { /* delete TXT */ }
}Potom zaregistrujte názov triedy solvera v drivers.acme.solver (CERTIFICATES_ACME_SOLVER). Nič viac netreba: typ výzvy určuje metóda type() samotného solvera — dns-01 pre DnsChallengeSolver, http-01 pre dodávaný predvolený solver — takže niet samostatného nastavenia typu výzvy, ktoré by ste museli udržiavať v súlade. Solver sa vytvára z kontajnera, takže funguje injektovanie cez konštruktor:
// config/certificates.php — the solver's own type() picks the challenge (dns-01 here)
'acme' => [
// ...
'solver' => App\Acme\Route53Solver::class,
],ACME autority ako Let’s Encrypt pre názov *. nikdy neponúkajú HTTP-01, takže wildcard objednávky potrebujú DNS solver; s predvoleným HTTP-01 solverom wildcard objednávka zlyhá s AcmeException, ktorá to výslovne uvedie. Pre plnú kontrolu implementujte priamo kontrakt AcmeChallengeSolver — solve() aj cleanup() dostanú AcmeChallenge:
namespace RoundlyConsulting\Certificates\Contracts;
interface AcmeChallengeSolver
{
public function type(): string; // 'http-01' or 'dns-01'
public function solve(AcmeChallenge $challenge): void; // publish the challenge
public function cleanup(AcmeChallenge $challenge): void; // remove it afterwards
}$challenge->type; // 'http-01' or 'dns-01'
$challenge->domain; // 'app.example.com'
$challenge->token;
$challenge->keyAuthorization; // token + '.' + account key thumbprint
$challenge->httpPath(); // '/.well-known/acme-challenge/{token}'
$challenge->dnsRecordName(); // '_acme-challenge.app.example.com'
$challenge->dnsRecordValue(); // base64url(SHA-256(key authorization))Prejavte lásku k open source
Tento balík je zadarmo pod licenciou MIT. Ak vám šetrí čas, jednorazový príspevok alebo členstvo na Patreone nám pomôže ho ďalej udržiavať, testovať a dokumentovať.
Ďalšie spôsoby podpory vrátane kryptomienOdoslaním daru súhlasíte s našimi podmienkami prijímania darov.
Chcete to zabudovať do svojho produktu?
Naše balíky integrujeme do zákazkových Laravel a AI riešení. Napíšte nám, na čom pracujete, a ozveme sa do 48 hodín.