A Laravel package for easily generating and renewing SSL certificates using Let's Encrypt. This package is especially useful if you have a Laravel application that manages the SSL certificates of many domains. This package is not recommended if you just need to generate a single SSL certificate for your application.
This package is essentially a Laravel-friendly wrapper around Acme PHP.
You can install the package via composer:
composer require daanra/laravel-lets-encrypt
Publish the configuration file and the migration:
php artisan vendor:publish --provider="Daanra\LaravelLetsEncrypt\LetsEncryptServiceProvider" --tag="lets-encrypt"
Run the migration:
php artisan migrate
Note:
You somehow have to return a stored challenge whenever it it retrieved from the /.well-known/acme-challenge
endpoint. You could do this by configuring NGINX/Apache appropriately or by registering a route:
Route::get('/.well-known/acme-challenge/{token}', function (string $token) {
return \Illuminate\Support\Facades\Storage::get('public/.well-known/acme-challenge/' . $token);
})
Sometimes the /.well-known/
prefix is disabled by default in the NGINX/Apache config (see #4). Make sure it is forwarded to your Laravel application if you want Laravel to return the challenge.
Creating a new SSL certificate for a specific domain is easy:
// Puts several jobs on the queue to handle the communication with the lets-encrypt server
[$certificate, $pendingDispatch] = \Daanra\LaravelLetsEncrypt\Facades\LetsEncrypt::create('mydomain.com');
// You could, for example, chain some jobs to enable a new virtual host
// in Apache and send a notification once the website is available
[$certificate, $pendingDispatch] = \Daanra\LaravelLetsEncrypt\Facades\LetsEncrypt::create('mydomain.com', [
new CreateNewApacheVirtualHost('mydomain.com'),
new ReloadApache(),
new NotifyUserOfNewCertificate(request()->user()),
]);
// You can also do it synchronously:
\Daanra\LaravelLetsEncrypt\Facades\LetsEncrypt::createNow('mydomain.com');
Alternative syntax:
LetsEncrypt::certificate('mydomain.com')
->setChain([])
->setTries(4)
->setRetryAfter(4)
->setRetryList([1, 5, 10])
->setDelay(5)
->create();
LetsEncrypt::certificate('mydomain.com')
->setChain([])
->setTries(4)
->setRetryAfter(4)
->setRetryList([1, 5, 10])
->setDelay(5)
->renew();
Where you can specify values for all jobs:
- tries (The number of times the job may be attempted)
- retryAfter (The number of seconds to wait before retrying the job)
- retryList (The list of seconds to wait before retrying the job)
- chain (Chain some jobs)
- delay (Set the desired delay for the job)
You could also achieve the same by using an artisan command:
php artisan lets-encrypt:create -d mydomain.com
Certificates are stored in the database. You can query them like so:
// All certificates
\Daanra\LaravelLetsEncrypt\Models\LetsEncryptCertificate::all();
// All expired certificates
\Daanra\LaravelLetsEncrypt\Models\LetsEncryptCertificate::query()->expired()->get();
// All currently valid certificates
\Daanra\LaravelLetsEncrypt\Models\LetsEncryptCertificate::query()->valid()->get();
// All certificates that should be renewed (because they're more than 60 days old)
\Daanra\LaravelLetsEncrypt\Models\LetsEncryptCertificate::query()->requiresRenewal()->get();
// Find certificate by domain
$certificate = LetsEncryptCertificate::where('domain', 'mydomain.com')->first();
// If you no longer need it, you can soft delete
$certificate->delete();
// Or use a hard delete
$certificate->forceDelete();
Each job has the following events available that you can track in your application:
Daanra\LaravelLetsEncrypt\Events\CleanUpChallengeFailed
Daanra\LaravelLetsEncrypt\Events\ChallengeAuthorizationFailed
Daanra\LaravelLetsEncrypt\Events\RegisterAccountFailed
Daanra\LaravelLetsEncrypt\Events\RequestAuthorizationFailed
Daanra\LaravelLetsEncrypt\Events\RequestCertificateFailed
Daanra\LaravelLetsEncrypt\Events\StoreCertificateFailed
Daanra\LaravelLetsEncrypt\Events\RenewExpiringCertificatesFailed
Either use a single listener:
Daanra\LaravelLetsEncrypt\Interfaces\NotifiableEvent;
Certificates are valid for 90 days. Before those 90 days are over, you will want to renew them. To do so, you
could add the following to your App\Console\Kernel
:
protected function schedule(Schedule $schedule)
{
$schedule->job(new \Daanra\LaravelLetsEncrypt\Jobs\RenewExpiringCertificates)->daily();
}
This will automatically renew every certificate that is older than 60 days, ensuring that they never expire.
By default this package will use Let's Encrypt's staging server to issue certificates. You should set:
LETS_ENCRYPT_API_URL=https://acme-v02.api.letsencrypt.org/directory
in the .env
file of your production server.
By default, this package will attempt to validate a certificate using a HTTP-01 challenge.
For this reason, a file will be temporarily stored in your application's storage directory under the path
app/public/.well-known/acme-challenge/<CHALLENGE_TOKEN>
. You can customise this behavior by setting a custom
PathGenerator
class in your config under path_generator
. Note that Let's Encrypt expects the following path:
/.well-known/acme-challenge/<CHALLENGE_TOKEN>
to return the contents of the file located at $pathGenerator->getPath($token)
.
composer test
Please see CHANGELOG for more information on what has changed recently.
Please see CONTRIBUTING for details.
If you discover any security related issues, please email daanraatjes+dev@gmail.com instead of using the issue tracker.
The MIT License (MIT). Please see License File for more information.