LetsEncrypt certs on OpenShift using acme-tiny

Update (17 June 2016): The API for OpenShift has changed and what is described here no longer works and I’ve been unable to figure out how to make it work.

Update (19 July 2016): The API shown below is working again, sometime between the last update and this one things must have changed again with OpenShift.

LetsEncrypt is a new certificate authority that issues free certificates that can be used to offer HTTPS on your website. LetsEncrypt certificates currently have a short lifetime (90 days) and as they are both free and short duration, you are encouraged to automate the issuance and installation of the certs so that your sites never show an expired cert.

OpenShift is RedHat’s Platform-as-a-Service offering that has both free and paid plans and if you are on the bronze plan or above, you can have your custom cert applied to your site. Interestingly enough, the bronze plan still allows 3 small gears to run for free (much like the free plan), so if your application is small enough (like this site) you can still run an HTTPS site for free.

The big gotcha is that for SSL certs on OpenShift, you can’t just drop them in a directory in your gear and point the apache/nginx/whatever web server at the certs and just go. You have to add the certs to your account, either via the web or via their REST api.

The official LetsEncrypt tool is a bit heavy-weight for running on a gear, I’m not even sure if it is possible with all the prerequisites it has, so I’ve chosen to use acme-tiny to implement my solution for LetsEncrypt certs on OpenShift.

Since my code isn’t the prettiest, I’m not going to show it here, but will describe how it works so that you can implement it in your project.

  • Follow the acme-tiny instructions for generating your account key and domain key files, then generate your CSR. I’ve named my CSR files after the short application name in my account (like staging or prod) and included both the official name (like www.example.com) and the rhcloud name (like example-gotmarko.rhcloud.com) so that either will work correctly without browser warnings.
  • Since my gear is running the PHP cartridge, make sure that /.well-known/acme-challenge points to a directory that acme-tiny can write in, I do this by creating a subdirectory $OPENSHIFT_REPO_DIR/.well-known/acme-challenge and linking it back into the directory where the script runs.
  • Script then calls acme-tiny with the account key, domain CSR (based on $OPENSHIFT_APP_NAME) with the challenge dir pointing to the local linked directory, then makes the chained cert like shown in the acme-tiny documentation
  • Backup the keys, CSR, and certs
  • Use the OpenShift REST API to upload the key using curl (where $CERT_FILE is the path to chained cert and $KEY_FILE is the path to the domain.key file):
curl -k -X PUT https://openshift.redhat.com/broker/rest/domains/$OPENSHIFT_NAMESPACE/applications/$OPENSHIFT_APP_NAME/aliases/$ALIAS_NAME --user "<openshift-user>:<openshift-password>" --data-urlencode "ssl_certificate@$CERT_FILE" --data-urlencode "private_key@$KEY_FILE"
  • After first time cert gets installed, you can then add the following to your .htaccess file to force all traffic to be HTTPS except for the /.well-known/acme-challenge path:
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteCond %{REQUEST_URI} !^/.well-known/acme-challenge
RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [R,L]
  • Setup a cron job (add the cron cartridge if not already installed) to run daily and skip all but the day you want run like so:
day=$(date '+%d')
if [ $day != 17 ]; then
# run only 1 day per month, specified above

And there you have it, automatically renewing LetsEncrypt certificates on OpenShift (for the PHP cartridge at least).

Wednesday December 30, 2015   ·   Permalink