diff --git a/doc/configuration.txt b/doc/configuration.txt
index 7c17f5408..3acf5c15e 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -1824,6 +1824,18 @@ The following keywords are supported in the "global" section :
Please note that this option is only available when HAProxy has been
compiled with USE_51DEGREES and 51DEGREES_VER=4.
+acme.scheduler { auto | off }
+ Enable or disable the ACME scheduler.
+
+ The ACME scheduler starts at HAProxy startup, it will loop over the
+ certificates and start an ACME renewal task when the notAfter value is past
+ curtime + (notAfter - notBefore) / 12, or 7 days if notBefore is not defined.
+ The scheduler will then sleep and wakeup after 12 hours.
+
+ The default value is "auto".
+
+ See also: acme
+
ca-base
Assigns a default directory to fetch SSL CA certificates and CRLs from when a
relative path is used with "ca-file", "ca-verify-file" or "crl-file"
diff --git a/include/haproxy/ssl_sock-t.h b/include/haproxy/ssl_sock-t.h
index 2c7f73b3b..44055492b 100644
--- a/include/haproxy/ssl_sock-t.h
+++ b/include/haproxy/ssl_sock-t.h
@@ -316,6 +316,10 @@ struct global_ssl {
int disable;
} ocsp_update;
#endif
+
+#ifdef HAVE_ACME
+ int acme_scheduler;
+#endif
};
/* The order here matters for picking a default context,
diff --git a/src/acme.c b/src/acme.c
index a49c621b3..2700adf5f 100644
--- a/src/acme.c
+++ b/src/acme.c
@@ -411,6 +411,34 @@ out:
return err_code;
}
+/* parse 'acme.scheduler' option */
+static int cfg_parse_global_acme_sched(char **args, int section_type, struct proxy *curpx, const struct proxy *defpx,
+ const char *file, int linenum, char **err)
+{
+ int err_code = 0;
+
+ if (!*args[1]) {
+ memprintf(err, "parsing [%s:%d]: keyword '%s' in '%s' section requires an argument\n", file, linenum, args[0], cursection);
+ goto error;
+ }
+ if (alertif_too_many_args(1, file, linenum, args, &err_code))
+ goto error;
+
+ if (strcmp(args[1], "auto") == 0) {
+ global_ssl.acme_scheduler = 1;
+ } else if (strcmp(args[1], "off") == 0) {
+ global_ssl.acme_scheduler = 0;
+ } else {
+ memprintf(err, "parsing [%s:%d]: keyword '%s' in '%s' section requires either 'auto' or 'off' argument", file, linenum, args[0], cursection);
+ goto error;
+ }
+
+ return 0;
+
+error:
+ return -1;
+}
+
/* Initialize stuff once the section is parsed */
static int cfg_postsection_acme()
{
@@ -545,7 +573,7 @@ static int cfg_postparser_acme()
}
- if (acme_cfgs) {
+ if (acme_cfgs && global_ssl.acme_scheduler) {
task = task_new_anywhere();
if (!task) {
ret++;
@@ -589,6 +617,7 @@ static struct cfg_kw_list cfg_kws_acme = {ILH, {
{ CFG_ACME, "bits", cfg_parse_acme_cfg_key },
{ CFG_ACME, "curves", cfg_parse_acme_cfg_key },
{ CFG_ACME, "map", cfg_parse_acme_kws },
+ { CFG_GLOBAL, "acme.scheduler", cfg_parse_global_acme_sched },
{ 0, NULL, NULL },
}};
@@ -2054,6 +2083,9 @@ time_t acme_schedule_date(struct ckch_store *store)
time_t notAfter = 0;
time_t notBefore = 0;
+ if (!global_ssl.acme_scheduler)
+ return 0;
+
/* compute the validity period of the leaf certificate */
if (!store->data || !store->data->cert)
return 0;
@@ -2347,12 +2379,18 @@ static int cli_acme_status_io_handler(struct appctx *appctx)
if (store->conf.acme.id) {
char str[50] = {};
- char *state = "Scheduled";
+ char *state;
time_t notAfter = 0;
time_t sched = 0;
time_t remain = 0;
+ int running = !!store->acme_task;
- if (store->acme_task)
+ if (global_ssl.acme_scheduler)
+ state = "Scheduled";
+ else
+ state = "Stopped";
+
+ if (running)
state = "Running";
chunk_appendf(&trash, "%s\t%s\t%s\t", store->path, store->conf.acme.id, state);
@@ -2367,12 +2405,16 @@ static int cli_acme_status_io_handler(struct appctx *appctx)
/* Scheduled time */
remain = 0;
- sched = acme_schedule_date(store);
+ if (!running) /* if running no schedule date yet */
+ sched = acme_schedule_date(store);
if (sched > date.tv_sec)
remain = sched - date.tv_sec;
strftime(str, sizeof(str), "%Y-%m-%dT%H:%M:%SZ", gmtime(&sched));
- chunk_appendf(&trash, "%s\t", str);
- chunk_appendf(&trash, "%lud %luh%02lum%02lus\n", remain / 86400, (remain % 86400) / 3600, (remain % 3600) / 60, (remain % 60));
+ chunk_appendf(&trash, "%s\t", sched ? str : "-");
+ if (sched)
+ chunk_appendf(&trash, "%lud %luh%02lum%02lus\n", remain / 86400, (remain % 86400) / 3600, (remain % 3600) / 60, (remain % 60));
+ else
+ chunk_appendf(&trash, "%s\n", "-");
if (applet_putchk(appctx, &trash) == -1)
return 1;
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index 793862b94..e7f01bc84 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -145,6 +145,10 @@ struct global_ssl global_ssl = {
.ocsp_update.mode = SSL_SOCK_OCSP_UPDATE_OFF,
.ocsp_update.disable = 0,
#endif
+#ifdef HAVE_ACME
+ .acme_scheduler = 1,
+#endif
+
};
static BIO_METHOD *ha_meth;