Monthly Archives: July 2019

Let’s Encrypt using Acme.sh on Centos and Apache

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:

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.