Monitoring Website SSL/TLS Certificate Expiration Times with R, {openssl}, {pushoverr}, and {DT}

macOS R users who tend to work on the bleeding edge likely noticed some downtime at <> this past weekend. Part of the issue was an SSL/TLS certificate expiration situation. Moving forward, we can monitor this with R using the super spiffy {openssl} and {pushoverr} packages whilst also generating a daily report with {rmarkdown} and {DT}.

The Basic Process

The {openssl} package has a handy function — download_ssl_cert() — which will, by default, hit a given host on the standard HTTPS port (443/TCP) and grab the site certificate and issuer. We’ll grab the “validity end” field and convert that to a date to use for comparison.

To get the target list of sites to check I used Rapid7’s FDNS data set and a glance at a few certificate transparency logs to put together a current list of “r-project” domains that have been known to have SSL certs. This process could be made more dynamic, but things don’t change that quickly in r-project domain land.

Finally, we use the {DT} package to build a pretty HTML table and the {pushoverr} package to send notifications at normal priority for certs expiring within a week and critical priority for certs that have expired (the package has excellent documentation which will guide you through setting up a Pushover account).

I put this all in a plain R script named r-project-ssl-notify.R that’s then called from a Linux CRON job which runs:

/usr/bin/Rscript -e 'rmarkdown::render(input="PATH_TO/r-project-ssl-notify.R", output_file="PATH_TO/r-project-cert-status/index.html", quiet=TRUE)'

once a day at 0930 ET to make this status page and also fire off any notifications which I have going to my watch and phone (I did a test send by expanding the delta to 14 days):



Here’s the contents of

#' ---
#' title: "r-project SSL/TLS Certificate Status"
#' date: "`r format(Sys.time(), '%Y-%m-%d')`"
#' output:
#'   html_document:
#'     keep_md: false
#'     theme: simplex
#'     highlight: monochrome
#' ---
#+ init, include=FALSE
  message = FALSE, 
  warning = FALSE, 
  echo = FALSE, 

#+ libs

# Setup -----------------------------------------------------------------------------------------------------------

# This env config file contains two lines:
# See the {pushoverr} package for how to setup your Pushover account

# Check certs -----------------------------------------------------------------------------------------------------

# domains retrieved from Rapid7's FDNS data set
# ( and cert transparency logs

#+ work
  "", "", "", 
  "", "", "", 
  "", "", "", 
  "", "", "", 
  "", "", "", 
  "", "", "", "", 
  "", "", "", 
  "", "", "", 
  "", "", "", 
  "", ""
) -> r_doms

# grab each cert

r_certs <- map(r_doms, openssl::download_ssl_cert)

# make a nice table
  dom = r_doms,
  expires = map_chr(r_certs, ~.x[[1]][["validity"]][[2]]) %>% # this gets us the "validity end"
    as.Date(format = "%b %d %H:%M:%S %Y", tz = "GMT"),        # and converts it to a date object
  delta = as.numeric(expires - Sys.Date(), "days")            # this computes the delta from the day this script was called
) %>% 
  arrange(expires) -> r_certs_expir

# Status page generation ------------------------------------------------------------------------------------------

# output nice table  
DT::datatable(r_certs_expir, list(pageLength = nrow(r_certs_expir))) # if the # of r-proj doms gets too large we'll cap this for pagination

# Notifications ---------------------------------------------------------------------------------------------------

# See if we need to notify abt things expiring within 1 week
# REMOVE THIS or edit the delta max if you want less noise
one_week <- filter(r_certs_expir, between(delta, 1, 7))
if (nrow(one_week) > 0) {
    title = "There are r-project SSL Certs Expiring Within 1 Week", 
    message = "Check which ones:"

# See if we have expired certs
expired <- filter(r_certs_expir, delta <= 0)
if (nrow(expired) > 0) {
    title = "There are expired r-project SSL Certs!", 
    message = "Check which ones:"


With just a tiny bit of R code we have the ability to monitor expiring SSL certs via a diminutive status page and alerts to any/all devices at our disposal.

Cover image from Data-Driven Security
Amazon Author Page

7 Comments Monitoring Website SSL/TLS Certificate Expiration Times with R, {openssl}, {pushoverr}, and {DT}

  1. Pingback: Monitoring Website SSL/TLS Certificate Expiration Times with R, {openssl}, {pushoverr}, and {DT} – Data Science Austria

  2. Martin Mächler

    Dear Bob, thank you for this service to the community.

    I assume you were not aware of the sites (where the sources are maintained, hosted here at ETH Zurich) and the even less prominent sites.. We’d be grateful if you’d add them as well.


    1. hrbrmstr

      Got them in and they’re in the latest cron run. The query was almost a one-liner but my eyes are the reason I missed thing. The query against our FDNS dataset came back with 769 unique names ( and I eyeballed ones I “knew” were web-ones. I’ll also do a query against our own certificate db in a bit and add what I find there, too.

      1. hrbrmstr
         [1] ""         ""        
         [3] ""        ""
         [5] ""      ""     
         [7] ""      ""        
         [9] ""        ""     
        [11] ""      ""   
        [13] ""          ""    
        [15] ""      ""             
        [17] ""             ""      
        [19] ""          "" 
        [21] ""     ""    
        [23] ""     ""    
        [25] ""     ""    
        [27] ""  "" 
        [29] ""     ""         
        [31] ""        

        come back as everything that isn’t r-forge related. I’ll validate the ones that have SSL enabled and get those in too.


Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.