diff --git a/roles/base/files/if-changed b/roles/base/files/if-changed
new file mode 100644
index 0000000000000000000000000000000000000000..4ac31739425bd46a77e5705670c389e68184d1c1
--- /dev/null
+++ b/roles/base/files/if-changed
@@ -0,0 +1,27 @@
+#!/bin/bash
+#
+# Returns true if one or more files have changed since the previous
+# invocation over the same set of files.
+#
+
+files_fp=$(echo "$@" | md5sum - | awk '{print $1}')
+state_file="/var/tmp/.if-changed.${files_fp}"
+
+max_ts=0
+for file in "$@"
+do
+    ts=$(stat -c %Y "$file")
+    if [ $ts -gt $max_ts ]; then
+        max_ts=$ts
+    fi
+done
+
+prev_ts=0
+if [ -e $state_file ]; then
+    prev_ts=$(cat $state_file)
+fi
+echo $max_ts > $state_file
+if [ $max_ts -gt $prev_ts ]; then
+    exit 0
+fi
+exit 1
diff --git a/roles/base/tasks/debian_misc.yml b/roles/base/tasks/debian_misc.yml
index f3689b063a87631c3aeba4a1fb3ff9848d604e1b..2e78eeced14e25082f9aae26c6bbd813d99aaed2 100644
--- a/roles/base/tasks/debian_misc.yml
+++ b/roles/base/tasks/debian_misc.yml
@@ -24,6 +24,7 @@
     mode: 0755
   with_items:
     - splay
+    - if-changed
 
 - name: Configure sysctl
   template:
diff --git a/roles/nginx/files/acme-reload-nginx b/roles/nginx/files/acme-reload-nginx
new file mode 100644
index 0000000000000000000000000000000000000000..ba97d70330da3a00dcee2f8320582679b0a538d7
--- /dev/null
+++ b/roles/nginx/files/acme-reload-nginx
@@ -0,0 +1,13 @@
+#!/bin/sh
+#
+# Reload NGINX when the certificates change.
+#
+
+# The grep/awk one-liner finds all certificate files referenced in
+# NGINX site configuration files.
+sites_dirs="/etc/nginx/sites-available /etc/nginx/sites-auto"
+certs=$(fgrep -r ssl_certificate $sites_dirs \
+            | awk '$2=="ssl_certificate" {print $3}' \
+            | sed -e 's/;$//')
+if-changed $certs && systemctl reload nginx
+exit 0
diff --git a/roles/nginx/files/acme-reload-nginx.cron b/roles/nginx/files/acme-reload-nginx.cron
new file mode 100644
index 0000000000000000000000000000000000000000..8192d60fa8453d6c00405e5ad0e30b5df3a0c8f1
--- /dev/null
+++ b/roles/nginx/files/acme-reload-nginx.cron
@@ -0,0 +1 @@
+45 3 * * * root /usr/local/bin/acme-reload-nginx
diff --git a/roles/nginx/tasks/nginx.yml b/roles/nginx/tasks/nginx.yml
index 07e2e968d4acc7cb56922f83330dce2642d3ec4d..40fbd24e559e1501ae9ab8f72cdf190e4710e7eb 100644
--- a/roles/nginx/tasks/nginx.yml
+++ b/roles/nginx/tasks/nginx.yml
@@ -168,3 +168,14 @@
     dest: /etc/firewall/filter.d/20nginx
   notify: "reload firewall"
 
+# Misc setup.
+- name: Install acme-reload-nginx script
+  copy:
+    src: acme-reload-nginx
+    dest: /usr/local/bin/acme-reload-nginx
+    mode: 0755
+
+- name: Install acme-reload-nginx cron job
+  copy:
+    src: acme-reload-nginx.cron
+    dest: /etc/cron.d/acme-reload-nginx