acmephp / symfony-bundle
AcmePhpBundle
Requires
- php: >=5.5.0
- acmephp/core: 1.0.x-dev
- psr/log: ^1.0.0
- symfony/console: ^2.3|^3.0
- symfony/dependency-injection: ^2.7|^3.0
- symfony/filesystem: ^2.3|^3.0
- symfony/finder: ^2.3|^3.0
- symfony/framework-bundle: ^2.6|^3.0
- webmozart/path-util: ^1.0|^2.0
Requires (Dev)
- behat/behat: ~3.1@dev
- behat/symfony2-extension: ~2.0
- phpunit/phpunit: ^4.8
- sllh/php-cs-fixer-styleci-bridge: ^1.5
- symfony/process: ^2.5|^3.0
- symfony/property-access: ^3.0
This package is auto-updated.
Last update: 2024-10-22 22:00:54 UTC
README
Note this bundle is in active development (it is not ready for the moment).
The ACME protocol is a protocol defined by the Let's Encrypt Certificate Authority. You can see the complete specification on https://letsencrypt.github.io/acme-spec/.
The ACME PHP project aims to implement the ACME protocol in PHP to be able to use it easily in various projects.
This repository is the Symfony bundle based on the PHP library.
Installation
Step 1: Download AcmePhpBundle using composer
Require the acmephp/symfony-bundle
with composer Composer.
$ composer require acmephp/symfony-bundle
Step 2: Enable the bundle
Enable the bundle in the kernel:
<?php // app/AppKernel.php public function registerBundles() { $bundles = array( // ... new AcmePhp\Bundle\AcmePhpBundle(), // ... ); }
Step 3: Configure the AcmePhpBundle
Below is a minimal example of the configuration necessary to use the
AcmePhpBundle
in your application:
# app/config/config.yml acme_php: contact_email: contact@mycompany.com default_distinguished_name: country: FR state: France locality: Paris organization_name: MyCompany organization_unit_name: IT domains: myapp.com: ~
Step 4: Import AcmePhpBundle routing files
Now that you have activated and configured the bundle, all that is left to do is import the AcmePhpBundle routing files.
# app/config/routing.yml acme_php: resource: "@AcmePhpBundle/Resources/config/routing.xml"
Usage
Once the bundle is installed and configured, you can request your certificates
by runnig the command acmephp:generate
$ ./bin/console acmephp:generate
The first time you run this command, AmePhpBundle will request a new
certificate to the configured Certificate Autority (default
Letsencrypt) and store the generated certificate in
the configured folder (default ~/.acmephp
).
Automatic renewal
Each time you run the command acmephp:generate
the certificate will be renew
with a lifetime of 90 days (defined by the Certificate Autority). You can add
a crontab to perform this task.
$ crontab -e 0 0 1 * * /var/www/my_app/bin/console acmephp:generate
After regenerating a certificate you have to reload the web server to take the changes into account.
If you use a dedicated cron file in
/etc/cron.d/
be carrefull of the certificate storage location (configured by default in the$HOME
directory) which is related to the user who run the command.
Configuration reference
# app/config/config.yml acme_php: # Certificates locations. Default: `~/.acmephp` # Beware to use a directory readable by the web server # It should be writable too, to store certificates, keys and challenges. certificate_dir: ~/.acmephp # Certificate Authority used to deliver certificates. Default: `letsencrypt`. Available values : `letsencrypt` # You can use your own Certificate Authority by : # - implementing the CertificateAuthorityConfigurationInterface interface # - registering the service with the tag "acme_php.certificate_authority" and with an alias to use here certificate_authority: letsencrypt # Email addresse associated to the account used to generate certificate contact_email: contact@mycompany.com # Default Distinguished Name (or a DN) informations used to request certificates. default_distinguished_name: # https://scotthelme.co.uk/setting-up-le/ # Country Name (2 letter code) country: FR # State or Province Name (full name) state: France # Locality Name (eg, city) locality: Paris # Organization Name (eg, company) organization_name: MyCompany # Organizational Unit Name (eg, section) organization_unit_name: IT # Email Address. When missing, the adresse defined in the parameter contact_email will be used email_address: john.doe@mycompany.com # List of domains to request domains: myapp.com: ~ www.myapp.com: ~ invoice.myapp.com: # You can override default distinguished name define above for each domain organization_unit_name: sales
Usage
You can both, request and renew a certificate with the single commande
$ bin/console acmephp:generate
The certificates will be stored in the folder defined by the parameter certificate_dir
.
$ tree ~/.acmephp
├── account # Your account's keys
│ ├── private.pem
│ └── public.pem
├── challenges # Pending challenges
├── domains # Contains all domain's certificate (1 sub directory per domain)
│ ├── company.com # Contains the certificates for domain `company.com`
│ │ ├── cert.pem # Server certificate only
│ │ ├── chain.pem # All certificates that need to be served by the browser **excluding** server certificate
│ │ ├── combined.pem # All certificates plus private key
│ │ ├── fullchain.pem # All certificates, **including** server certificate
│ │ ├── private.pem # Private key for the certificate
│ │ └── public.pem # Public key for the certificate
│ └── www.company.com
│ └── ...
└── domains-backup # Previous versions of the certificates
├── company.com # domains as subdirectory
│ └── 20160314-144416 # each subdirectory is a backup
│ └── ...
└── www.company.com
└── ...
Monitoring
If your application use monolog (which should be the case by default), Acme PHP Symfony Bundle will log in a acme_php
channel. By this way, you can handle logs and being notified on renewal failure.
Here is a sample of configuration
# app/config/config.yml monolog: handlers: certificate_slack: type: slack token: # Your slack's token : https://api.slack.com/web channel: "#production" # name of the slack's channel bot_name: CertificatesBot icon_emoji: lock_with_ink_pen level: NOTICE channels: [acme_php]
Extensions
Certificate Authority: You can add your own certificate authority by implementing the interface
AcmePhp\Bundle\Acme\CertificateAuthority\Configuration\CertificateAuthorityConfigurationInterface
and adding the
service with tag acme_php.certificate_authority
as follow :
# app/config/services.yml services: app.custom_certificate_authority: class: AppBundle\Acme\CustomConfiguration public: false tags: - name: acme_php.certificate_authority alias: custom
You just have to reference it in your configuration
# app/config/config.yml acme_php: certificate_authority: custom
Domain Loader: By default, the bundle loads domain's configurations through the config's file. But, you can add
your own loader by implementing the interface AcmePhp\Bundle\Acme\Domain\Loader\LoaderInterface
and adding the service
with tag acme_php.domains_configurations_loader
as follow:
# app/config/services.yml services: app.custom_certificate_authority: class: AppBundle\Acme\CustomLoader public: false tags: - name: acme_php.domains_configurations_loader
Certificate Formatter: When a new certificate is requested, it is dumped in several formats (cert.pem,
chain.pem, combined.pem, ...). You can add your own formatter by implementing the interface
AcmePhp\Bundle\Acme\Certificate\Formatter\FormatterInterface
and adding the service with tag
acme_php.certificate_formatter
as follow:
# app/config/services.yml services: app.custom_certificate_authority: class: AppBundle\Acme\CustomFormatter public: false tags: - name: acme_php.certificate_formatter
Events: AcmePhpBundle triggers many events:
- CERTIFICATE_REQUESTED: When a certificate is requested on renewed
- CHALLENGE_REQUESTED: When a new challenge is requested
- CHALLENGE_CHECKED: When the challenge is checked (whether or not it have been accepted)
- CHALLENGE_ACCEPTED: When the challenge have been accepted
- CHALLENGE_REJECTED: When the challenge have been rejected
WebServer Configuration sample
Here are some basic configurations for the common web servers.
Mozilla provide a tool to generate more advance configuration: https://mozilla.github.io/server-side-tls/ssl-config-generator/
You can also check your online certificate with this tool: https://www.ssllabs.com/ssltest/
### Apache 2.2
# /etc/apache2/sites-available/<domain>.
<VirtualHost *:443>
SSLEngine on
SSLCertificateFile /var/www/.acmephp/domains/<domain>/cert.pem
SSLCertificateKeyFile /var/www/.acmephp/domains/<domain>/private.pem
SSLCACertificateFile /var/www/.acmephp/domains/<domain>/chain.pem
...
</VirtualHost>
$ sudo service apache2 reload
### Apache 2.4
# /etc/apache2/sites-available/<domain>.
<VirtualHost *:443>
SSLEngine on
SSLCertificateFile /var/www/.acmephp/domains/<domain>/fullchain.pem
SSLCertificateKeyFile /var/www/.acmephp/domains/<domain>/private.pem
...
</VirtualHost>
$ sudo service apache2 reload
### Nginx
# /etc/nginx/sites-available/<domain>.
server {
listen 443 ssl default_server;
server_name my-domain;
ssl_certificate /var/www/.acmephp/domains/<domain>/fullchain.pem
ssl_certificate_key /var/www/.acmephp/domains/<domain>/private.pem
...
}
$ sudo service nginx reload
haproxy
# /etc/haproxy/haproxy.cfg
frontend www
bind :80
bind :443 ssl crt /var/www/.acmephp/domains/<domain>/combined.pem
...
$ sudo service haproxy reload
Contributing
Unit tests
composer install
./bin/phpunit
Functionnal testing
composer install
docker run -d --net host acmephp/testing-ca
docker run --rm --net host martin/wait -c localhost:4000 -t 120
features/fixtures/TestApp/console acmephp:server:start
./bin/behat
features/fixtures/TestApp/console acmephp:server:stop
Manual testing
Because Letsencrypt has a rate limiting, We recommends to use
Boulder as Certificate Authority.
Which is include and fully package in the docker image acmephp/testing-ca
You'll find a micro symfony application in the folder
features/fixtures/TestApp
.
It allow you to easily test the application. You just have to edit the config
file in features/fixtures/TestApp/config/config.yml
. Then start Boulder and
the symfony's server (to handle challenge requests).
composer install
# Launch boulder
docker run -d --net host acmephp/testing-ca
docker run --rm --net host martin/wait -c localhost:4000 -t 120
# Launche the application to listen to challenge checks
features/fixtures/TestApp/console acmephp:server:start
# Generate the certificate
features/fixtures/TestApp/console acmephp:generate
ls -al features/fixtures/TestApp/certs/domains/*/