Scenario
You are using a provider such as Arvixe which provides CPanel. You are a bit bored with manually renewing the certificate every three months and would like to automate it.
We will:
- check if the certificate(s) expires and, if yes;
- issue new certificates
- upload them to arvixe using cpanel interface
Assumptions and pre-requisites
- This assumes to have access to a *nix box from where you’ll manage your certificates and upload them onto CPanel.
- ssh access to your remote website
- use certbot
- you already have one or several sites and certificates
- you have downloaded sslic.php from https://github.com/neurobin/sslic
Overview
Here is the certbot command we will use:
certbot certonly --non-interactive --staple-ocsp --email youremail@example.org -d yourserver.com -d www.yourserver.com --agree-tos --manual --manual-auth-hook /path/toyour/scripts/letsencryptauth.sh --manual-cleanup-hook /path/toyour/scripts/letsencryptclean.sh
- non-interactive, email and agree-tos: This is to be used in a script so it has to be non-interactive.
- d: list all your domains here, add as many -d as you need.
- manual-auth-hook and manual-cleanup-hook: Let’s Encrypt will need to verify the ownership of your sites, those scripts will automate the upload and deletion of the authorisation files.
- you already have set up ssh keys on the remote server so you don’t need to type a password to log in from the machine where the script is to your remote server.
- I also use –redirect –hsts –uir, however, I am not sure they are effective and would welcome feedback on those.
We will, therefore, use three shell scripts:
- certupdate.sh: the main script checking the validity of the certificates, generating the new certificates and uploading them to cpanel
- letsencryptauth.sh: to upload the authorisation files.
- letsencryptclean.sh: to clean up.
certupdate.sh
#!/bin/bash RENEW=22 echo "=======================================" date '+%a %d %b %y %H:%M:%S' echo "============Starting script============" #downloading let's encrypt CA file wget -O /tmp/letsencryptCA.crt https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem.txt # #checking yourserver.com #add '-servername yourserver.com' to use SNI in case you are on a shared server and ensure your certificate is gathered instead of the main cert. # certificate=$(echo |openssl s_client -servername yourserver.com -connect yourserver.com:443 2>/tmp/cert.tmp|openssl x509 -checkend $[86400 * $RENEW] -enddate) if [ "$certificate" == "" ]; then echo "Error: unable to check certificate" else if [[ $certificate =~ (.*)Certificate will expire ]]; then echo $certificate echo "certificate needs to be renewed" # #cert generation for yourserver.com and www.yourserver.com # certbot certonly --non-interactive --staple-ocsp --email email@example.org -d yourserver.com -d www.yourserver.com --agree-tos --manual --manual-auth-hook /path/toyour/scripts/letsencryptauth.sh --manual-cleanup-hook /path/toyour/scripts/letsencryptclean.sh echo "yourserver.com cert process completed, now uploading it to CPanel" #upload to cpanel. Only one upload as www and . share one cert for my configuration. You may want to change that to your own config. USER='cpanel username' PASS='cpanelpassword' EMAIL='email@example.org' /usr/bin/php /path/toyour/scripts/sslic.php yourserver.com /etc/letsencrypt/live/yourserver.com/cert.pem /etc/letsencrypt/live/yourserver.com/privkey.pem /tmp/letsencryptCA.crt echo "yourserver.com upload to cpanel process complete" else echo $certificate echo "cert does not need to be renewed" fi fi echo "===================================" date '+%a %d %b %y %H:%M:%S' echo "============Script ends============"
RENEW=22 means that if the certificate is due to expire in 22 days, then we update it. Change this value as you wish.
letsencryptauth.sh
I call this script from certupdate.sh which I run as root/sudo, but my ssh key is under a normal user (non-root), so I call scp from another user.
#!/bin/bash case "$CERTBOT_DOMAIN" in "www.yourserver.com") echo $CERTBOT_VALIDATION >/tmp/$CERTBOT_TOKEN /usr/bin/sudo -u username /usr/bin/scp /tmp/$CERTBOT_TOKEN username@yourserver.com:/path/tosite/www/.well-known/acme-challenge ;; "yourserver.com") echo $CERTBOT_VALIDATION >/tmp/$CERTBOT_TOKEN /usr/bin/sudo -u username /usr/bin/scp /tmp/$CERTBOT_TOKEN username@yourserver.com:/path/tosite/www/.well-known/acme-challenge ;; "testcert.yourserver.com") echo $CERTBOT_VALIDATION >/tmp/$CERTBOT_TOKEN usr/bin/sudo -u username /usr/bin/scp /tmp/$CERTBOT_TOKEN username@yourserver.com:/path/tosite/testcert.yourserver.com/.well-known/acme-challenge ;; esac
certbot passes the variables $CERTBOT_DOMAIN, $CERTBOT_VALIDATION and $CERTBOT_TOKEN to the script so you just have to add as many many “example.org”) sites you want. See certbot documentation for more details.
As you can see I have added a line for a third domain, testcert.yourserver.com, this is just to show that you can add as many cases as you want. You’ll need to modify certupdate.sh accordingly – or run separate certupdate_01.sh, certupdate_01.sh, etc, that each call letsencryptauth.sh.
Modify paths, domains and username to match your configuration.
letsencryptclean.sh
#!/bin/bash case "$CERTBOT_DOMAIN" in "www.yourserver.com") /usr/bin/sudo -u username /usr/bin/ssh -t username@yourserver.com "rm -vf /path/tosite/www/.well-known/acme-challenge/*" ;; "yourserver.com") /usr/bin/sudo -u username /usr/bin/ssh -t username@yourserver.com "rm -vf /path/tosite/www/.well-known/acme-challenge/*" ;; "testcert.yourserver.com") /usr/bin/sudo -u username /usr/bin/ssh -t username@yourserver.com "rm -vf /path/tosite/testcert.yourserver.com/.well-known/acme-challenge/*" ;; esac
sslic.php
// Define the API call. $cpanel_host = 'localhost'; $request_uri = "https://$cpanel_host:2083/execute/SSL/install_ssl";
modify the values to match your own config, for instance, mine looks like that:
// Define the API call. $cpanel_host = 'dallas123.arvixeshared.com'; $request_uri = "https://$cpanel_host:2083/execute/SSL/install_ssl";
Crontab
As certupdate.sh has your cpanel login and password, you have to make sure it is in a safe location, at a minimum make sure that only the user running the script can read it.
50 15 * * WED /path/toyour/scripts/certupdate.sh>>/path/toyour/log/certupdate.log
This runs the script weekly, every Wednesday at 15:50.
To-do
- test –redirect –hsts –uir
- follow-up on must-staple support by Let’s Encrypt.
support of DNS CAA by Arvixe: when?full HSTS support, not a dirty WordPress only 301 redir: so far Arvixe say they don’t support it (and probably won’t…).
Update – 30APR2018
Arvixe support confirmed they don’t support DNS CAA for my product yet but they will support it when they’ll upgrade CPanel to a version above 11.66, currently I am on 11.62. No ETA though.
Arvie support provided me with a new .htaccess file and it indeed solves my problems.
The rules I was using was causing Safari to complain of multiple redirections.
RewriteEngine On RewriteCond %{HTTPS} off RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
The rule they provided solved that.
RewriteEngine On RewriteCond %{SERVER_PORT} 80 RewriteRule ^(.*)$ https://catelin.net/$1 [R,L]
Update – 24MAY2018
I finally decided to give Cloudfare a try. It didn’t improve anything for me, I guess my traffic is far too low to see any improvements. However, I now use their DNS and – among other things – that allowed me to set DNS CAA records.