Recently I installed Let’s Encrypt, the free, automated, and open Certificate Authority to websites:
- brifishjones.com (this website)
- jenfishjones.com (my wife’s website featuring her paintings)
- big-dogs-large-stories.com (my wife’s latest artistic collaboration with dog owners)
- rubycms.org (a content management system I developed over 10 years ago using Ruby on Rails)
I wanted a solution that was written in Shell with no dependencies on Python to eliminate any additional installs, so Acme.sh was chosen. There were a couple of pain points along the way to get https functional so I thought I’d share those with you. Note that this tutorial applies to the following setup:
- Linux virtual server running Centos 6 with root access
- Apache web server
- Acme.sh to install Let’s Encrypt
Begin by logging in to your server as root (or as a user with sudo privileges). Download Acme.sh into your home directory:
# curl https://get.acme.sh | sh
This will create a hidden folder called .acme.sh in your home directory that will contain all of the files, certificates, and keys needed for certification.
Next issue the certificates for each site. Replace /path/to/your/webroot with your actual path. For example:
# acme.sh --issue -d jenfishjones.com -d www.jenfishjones.com -w /path/to/your/webroot/jenfishjones.com/public_html
Install the certificates (you will need to be root or have sudo privileges):
# acme.sh --install-cert -d jenfishjones.com \ --cert-file /path/to/your/webroot/jenfishjones.com/cert.pem \ --key-file /path/to/your/webroot/jenfishjones.com/key.pem \ --fullchain-file /path/to/your/webroot/jenfishjones.com/fullchain.pem \ --reloadcmd "service httpd force-reload"
Repeat the installation process for any additional domains then restart Apache:
# service httpd restart
There was a problem restarting Apache.
Starting httpd: skipping (98)Address already in use: make_sock: could not bind to address 0.0.0.0:80 no listening sockets available, shutting down Unable to open logs [FAILED]
To remedy the problem the old process had to be killed manually (11188 is the process id, yours will be different):
# fuser 80/tcp 80/tcp: 11188 # kill 11188
It is assumed that you already have a functioning Apache server with a secure VirtualHost directive <VirtualHost xx.xx.xxx.xxx:443> already in place in your conf file. For each domain modify /etc/httpd/conf/httpd.conf to include the new certs. Place them within the <VirtualHost xx.xx.xxx.xxx:443> declaration for each ServerName. Note that your conf file may be at a different location:
SSLEngine on SSLProtocol all -SSLv2 -SSLv3 SSLCertificateFile /path/to/your/webroot/jenfishjones.com/cert.pem SSLCertificateKeyFile /path/to/your/webroot/jenfishjones.com/key.pem SSLCertificateChainFile /path/to/your/webroot/jenfishjones.com/fullchain.pem SSLCACertificateFile /path/to/your/webroot/jenfishjones.com/fullchain.pem
With the certificates added to the httpd.conf file and the server restarted all of the sites served up https except brifishjones.com. Since the server itself had the same name as the website, an outdated certificate at /etc/pki/tls/certs/localhost.crt was being read instead. This was deduced by running the following commands:
# echo | openssl s_client -connect brifishjones.com:443 -servername brifishjones.com 2>/dev/null | awk '/Certificate chain/,/---/'
and:
# grep -r SSLCertificateFile /etc/httpd /etc/httpd/conf.d/ssl.conf:# Point SSLCertificateFile at a PEM encoded certificate. If /etc/httpd/conf.d/ssl.conf:SSLCertificateFile /etc/pki/tls/certs/localhost.crt /etc/httpd/conf.d/ssl.conf:# the referenced file can be the same as SSLCertificateFile
To fix the file /etc/httpd/conf.d/ssl.conf was changed so that the Let’s Encrypt generated certificates would be read instead:
# Server Certificate: # Point SSLCertificateFile at a PEM encoded certificate. If # the certificate is encrypted, then you will be prompted for a # pass phrase. Note that a kill -HUP will prompt again. A new # certificate can be generated using the genkey(1) command. #SSLCertificateFile /etc/pki/tls/certs/localhost.crt SSLCertificateFile /path/to/your/webroot/brifishjones.com/cert.pem # Server Private Key: # If the key is not combined with the certificate, use this # directive to point at the key file. Keep in mind that if # you've both a RSA and a DSA private key you can configure # both in parallel (to also allow the use of DSA ciphers, etc.) #SSLCertificateKeyFile /etc/pki/tls/private/localhost.key SSLCertificateKeyFile /path/to/your/webroot/brifishjones.com/key.pem # Server Certificate Chain: # Point SSLCertificateChainFile at a file containing the # concatenation of PEM encoded CA certificates which form the # certificate chain for the server certificate. Alternatively # the referenced file can be the same as SSLCertificateFile # when the CA certificates are directly appended to the server # certificate for convinience. #SSLCertificateChainFile /etc/pki/tls/certs/server-chain.crt SSLCertificateChainFile /path/to/your/webroot/brifishjones.com/fullchain.pem # Certificate Authority (CA): # Set the CA certificate verification path where to find CA # certificates for client authentication or alternatively one # huge file containing all of them (file must be PEM encoded) #SSLCACertificateFile /etc/pki/tls/certs/ca-bundle.crt SSLCACertificateFile /path/to/your/webroot/brifishjones.com/fullchain.pem
Once the certificate chain was changed to /path/to/your/webroot/brifishjones.com and the Apache server restarted, all sites were up and running with the Let’s Encrypt certificates.
To wrap up there are a couple of items to note. Acme.sh installs a cron job that keeps the certificates up-to-date. You should see a listing like:
# crontab -l 0 0 * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null
If you want to force a manual renewal issue the command:
# acme.sh --renew -d jenfishjones.com --force
Periodically Acme.sh should be updated to the latest version:
# acme.sh --upgrade
Or simply enable auto upgrade and updates will happen automatically:
acme.sh --upgrade --auto-upgrade
As we have now seen, Let’s Encrypt using Acme.sh is a relatively straightforward way to generate signed certificates so that users can visit your websites securely using https.