LetsEncrypt recently entered into a public beta. Thanks to the work of the LetsEncrypt team and Fedora packagers, the official LetsEncrypt client is now available in both Fedora 23 and Rawhide. To learn how LetsEncrypt works or what it is, you can read more in the Fedora Magazine article announcing the public beta launch. In this article, we provide a basic configuration to secure an Apache HTTPD-based site with a LetsEncrypt certificate.
Using
letsencrypt
in Fedora
The official letsencrypt client is can be installed in Fedora 23 or later with this command:
dnf install letsencrypt
In the official client, there are three methods to prove ownership of your domain(s).
- Manual verification: The secret needs to be put in place by hand.
- Standalone verification: The LetsEncrypt client listens on port 80 or 443 and responds to the server itself.
- Web root verification: The client is pointed to the web root (e.g.
/var/www/html
) and writes files directly.
At the time of writing, full automatic configuration of Apache and nginx are in progress.
Once the package is installed, you will be able to see a list of available options using the –help flag:
letsencrypt --help all
Manual verification
Manual verification has the most overhead, but lets you run the LetsEncrypt client on a separate system from the web server. Depending on the security model you prefer, you may find this desirable.
The default uses an ncurses interface, but text-only is also possible.
$ letsencrypt --text --email recovery@example.com \ --domains www.example.com,example.com,foo.example.com \ --agree-tos --renew-by-default --manual certonly
The email address is used only if you lose the account details. This will allow you to verify your identity to revoke a certificate and request a new one.
If multiple domains are listed, these will be included as SubjectAltNames in a single certificate.
The client then prompts for a secret per domain to be stored at specific locations. Run the following commands to set the secret location.
$ cd /var/www/html $ mkdir -p .well-known/acme-challenge $ echo "somethingrandomgivenbyservergoeshere" > .well-known/acme-challenge/anotherrandomthinghere
Once you acknowledge the secret has been put in place, the ACME server tests the site for this secret. If the secret matches, LetsEncrypt will provide the certificate. The certificate should then be either moved, or symbolically linked to facilitate automatic renewing, to the right location.
Standalone verification
Standalone verification automatically responds to the challenge, which allows for some automated behavior. The downside of this method is that the web server must be temporarily stopped so LetsEncrypt can listen with its own HTTP server and respond to the challenge.
The IP requesting standalone configuration must match the A record for the domain requested, so this has to run on the target web server.
$ letsencrypt --text --renew-by-default --email recovery@example.com \ --domains www.example.com,example.com,foo.example.com \ --agree-tos --standalone --standalone-supported-challenges http-01 certonly
No interaction is required on the user’s part. This allows automation if either ports 80 or 443 are not already in use on the system, or if a short downtime can be tolerated. For example, this could be an initial provisioning step in an automated management system like Ansible before the main web server is actually started.
Once the certificate is acquired, the server must be configured to use it in some manner.
Web root verification
This method of verification is a nice middle ground. If an existing web server is running, LetsEncrypt can refer to the HTML document root and the client will automatically create the response to the ACME challenge. This method also must run on the same system that matches the A record for the domain.
$ letsencrypt --text --renew-by-default --email recovery@example.com \ --domains www.example.com,example.com,foo.example.com \ --agree-tos --webroot --webroot-path /var/www/html certonly
Using the LetsEncrypt certificate
When the verification selected is complete, /etc/letsencrypt is populated with a configuration matching the method chosen for the domain, along with the keys, certificate, and signing request used.
The files could be copied to an appropriate location for the web server to use. An even better idea is to symbolically link them, so in the future, renewals pick up the new files with no other configuration.
An example for a mod_ssl configuration would be as follows:
$ ln -s /etc/letsencrypt/live/www.example.com/cert.pem /etc/pki/tls/certs/www.example.com.crt $ ln -s /etc/letsencrypt/live/www.example.com/chain.pem /etc/pki/tls/certs/www.example.com.chain.crt $ ln -s /etc/letsencrypt/live/www.example.com/privkey.pem /etc/pki/tls/private/www.example.com.key $ cp /etc/httpd/conf.d/ssl.conf{,.backup} $ sed -i 's@\(SSLCertificateFile\) .*@\1 /etc/pki/tls/certs/www.example.com.crt@' /etc/httpd/conf.d/ssl.conf $ sed -i 's@\(SSLCertificateKeyFile\) .*@\1 /etc/pki/tls/private/www.example.com.key@' /etc/httpd/conf.d/ssl.conf $ sed -i 's@#\(SSLCertificateChainFile\) .*@\1 /etc/pki/tls/certs/www.example.com.chain.crt@' /etc/httpd/conf.d/ssl.conf
Once you restart the web server, it should make use of the new certificates.
The certificates in their default location will get an selinux context of type etc_t. This is readable by httpd and nginx so they can start with this configuration. However, until the base selinux policy includes the Let’s Encrypt certificates, it’s sensible to label them manually to prevent exploitation.
$ semanage fcontext -a -t cert_t '/etc/letsencrypt/(archive|live)(/.*)?' $ restorecon -Rv /etc/letsencrypt
Renewing a certificate
The lifetime of these certificates is only 90 days, to mitigate the impact of any rogue certificates that may end up existing. There are even discussions to lower this in the future. The expectation for the user is to create an automated job to run every 30 to 60 days in order to fetch a fresh certificate valid for another 90 days.
All that’s required to request a new certificate is to run the letsencrypt command again, with a new verification of some nature, and a new key and certificate will be generated.
The files in the live directory are actually symbolic links to the current versions in /etc/letsencrypt/archive. This lets you check the history of changes and rollback if needed.
$ ls -1 /etc/letsencrypt/archive/www.example.com cert1.pem cert2.pem chain1.pem chain2.pem fullchain1.pem fullchain2.pem privkey1.pem privkey2.pem
$ ls -lGg /etc/letsencrypt/live/www.example.com lrwxrwxrwx. 1 41 Dec 2 23:19 cert.pem -> ../../archive/www.example.com/cert2.pem lrwxrwxrwx. 1 42 Dec 2 23:19 chain.pem -> ../../archive/www.example.com/chain2.pem lrwxrwxrwx. 1 46 Dec 2 23:19 fullchain.pem -> ../../archive/www.example.com/fullchain2.pem lrwxrwxrwx. 1 44 Dec 2 23:19 privkey.pem -> ../../archive/www.example.com/privkey2.pem
To make use of new files, just reload the web server. If you use a method that requires no interaction such as webroot, this can be trivially automated via cron or a systemd timer.
An example with a timer would be:
# cd /etc/systemd/system # cat > www-example-com-renewal.service <<EOF [Unit] Description=Automatically renew the www.example.com certificate [Service] Type=oneshot ExecStart=/usr/bin/letsencrypt -d www.example.com --renew-by-default -m recovery@example.com --agree-tos -t --webroot -w /var/www/html certonly ExecStart=/usr/sbin/systemctl reload httpd EOF # cat > www-example-com-renewal.timer <<EOF [Unit] Description=Trigger an automatic renewal every month [Timer] OnCalendar=monthly Persistent=true [Install] WantedBy=multi-user.target EOF systemctl daemon-reload
Revoking a certificate
Sometimes things go wrong and a private key is disclosed. If this happens, it’s important to revoke the certificate so no one can impersonate the web server. Note that certificates are not revoked during renewal, to give grace to restart services or distribute files.
To revoke, use the same client with the revoke option:
$ letsencrypt revoke --cert-path /etc/letsencrypt/archive/www.example.com/cert1.pem
If there is an error carrying out the revocation, it will be displayed. Otherwise, that is it!
Final words
The LetsEncrypt platform only just entered its open beta stage recently and remains under heavy development. It is important to check the upstream documentation to stay current on the expected behavior and see if any options have changed. Note that there are a few commands and items described upstream that are not in Fedora, such as the auto-updating version and the Apache configuration plugin.
If any issues are encountered with the Fedora-packaged version, please report them to Bugzilla so they can be properly tracked and ensure a great experience for those using it in the future.
Matty
I didn’t realise that there was manual verification too – I’ve got it running on my site, but I didn’t need to use the option, so I guess I missed it. This actually quashes the one biggest issues that was leveraged to me about LE, because you need root access for the other methods.
I’m extremely tempted now to create a really small VM which runs LE in virtualbox, so that those with little knowledge of Linux can download it, and execute it themselves.
This does beg the question though – why don’t LE create a web page for doing this?
Sander Hoentjen
How would a web page work? You need the private key, and the private key needs to remain, well, private.
Justin W. Flory
Hmmm, what do you mean? LetsEncrypt does generate a private key and you can implement it like a traditional SSL certificate.
Sander Hoentjen
What I said was in reply to:
“This does beg the question though – why don’t LE create a web page for doing this?”
Maybe I misunderstood what “this” is, but I understood it to mean that you wouldn’t need something local, LE creates a webpage where you can fill all stuff in, respond correctly to the challenge and then get your certificates. However to do this LE would need to create your private key (because if they don’t, you will have to so then what is the whole point of the web page?). But if LE creates the private key, it isn’t really private after all.
Not sure if I just made myself clearer, or even more unclear 🙂
Torsten
“dnf search letsencrypt” gets an error
on my machine run fedora 23 with fedora and update repo
Justin W. Flory
You may need to clean your DNF cache. Try running
and try again. Usually that does the trick for me.
Torsten
yesterday this trick doesn’t work – today it’s ok
andrei
SSL? Isn’t SSL less secure than TLS?
Matthew Miller
It’s an X.509 certificate. You can use it for SSL or TLS. TLS is basically SSL 3.1 and newer. As I understand it, the name was changed to avoid possible issues with rights to the name, not for any technical reason.
gabx
Thank you much for this indeep article + the systemd timer.
Please take note that when running Nginx, it is the fullchain.pem which must be used. Otherwise, Nginx will complain and not start.
Jason
Lets encrypt is the best thing since sliced bread and it is great that you have picked it up so early. I already have it on my site running Fedora and Docker. Fedora has to be the best distro for me from both a professional and personal perspective.
Great work Guys
Barak A. Pearlmutter
Also already available in Debian, and therefore soon in Debian derivatives like Ubuntu.
We’re all in this together!
Justin W. Flory
Definitely agreed, Barak! 🙂 Thanks for the update about Debian – here’s to a more secure web for everyone!
Peter
Hi,
you are talking about current development of ‘full automatic configuration of Apache and nginx beeing developed’ currently. Where could one find these?
Thanks in advance
Berend
Thanks for writing this. I was already using letsencrypt, but more integration and automation is always useful.
gabx
I would suggest the following:
– add a require in the unit file this way:
Requires=httpd.service
After=httpd.service
This avoid let’s encrypt to fail in case server is not running
Then, I would remove the
ExecStart=/usr/sbin/systemctl reload httpd
from service file. Why? Because of say 10 virtual server with different root path, you will need 10 service+timer. Best is thus to restart only once the server when all renewal are done. In this case, play with the OnCalendar=
to be sure httpd restart once all renewal are done.
Sudhir Khanger
LE’s CentOS branch is broken so this came super handy. The only thing I would say is to avoid complex bash statements. Or explain them if you have to because if they fail then users have no idea what happened. Thanks for writing this.