Forge Cron Jobs & Certbot

In Laravel Forge cron jobs can be set up using the control panel or Forge ui, but you can of course work from the command line. Now what if you would like to see all jobs running from the command line?

General Forge Cron Jobs

Well, when you check /etc/crontab you can see this for example

forge@domain-staging:~$ cat /etc/crontab
 /etc/crontab: system-wide crontab
 Unlike any other crontab you don't have to run the `crontab'
 command to install the new version when you edit this file
 and files in /etc/cron.d. These files also have username fields,
 that none of the other crontabs do.
 SHELL=/bin/sh
 PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
 m h dom mon dow user  command
 17 *    * * *   root    cd / && run-parts --report /etc/cron.hourly
 25 6    * * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
 47 6    * * 7   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
 52 6    1 * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
 #
 Laravel Forge Scheduler 283055
 0 0 * * * root /usr/local/bin/composer self-update > /home/forge/.forge/scheduled-283055.log 2>&1
 Laravel Forge Scheduler 408852
 * * * * forge php /home/forge/staging.domain.com/current/artisan schedule:run > /home/forge/.forge/scheduled-408852.log 2>&1 

You can see the regular scheduled jobs and the Laravel Forge Scheduler. These are not all jobs however.

Certbot Renewal

In our case this did not show the setup Let’s Encrypt SSL job set up for a wildcard domain using Certbot. These you find elsewhere (etc/cron.d):

forge@domain-staging:~$ cd /etc/cron.d
 forge@domain-staging:/etc/cron.d$ ll
 total 32
 drwxr-xr-x   2 root root 4096 Feb 20 07:14 ./
 drwxr-xr-x 106 root root 4096 Feb 20 07:14 ../
 -rw-r--r--   1 root root  102 Nov 16  2017 .placeholder
 -rw-r--r--   1 root root  775 Feb 10  2019 certbot
 -rw-r--r--   1 root root  589 Mar  7  2018 mdadm
 -rw-r--r--   1 root root  712 Jan 25  2018 php
 -rw-r--r--   1 root root  191 May 22  2018 popularity-contest
 -rw-r--r--   1 root root 2477 Jun 19  2018 sendmail

The Certbot task has the following content

forge@domain-staging:/etc/cron.d$ cat certbot 
 /etc/cron.d/certbot: crontab entries for the certbot package
 #
 Upstream recommends attempting renewal twice a day
 #
 Eventually, this will be an opportunity to validate certificates
 haven't been revoked, etc.  Renewal will only occur if expiration
 is within 30 days.
 #
 Important Note!  This cronjob will NOT be executed if you are
 running systemd as your init system.  If you are running systemd,
 the cronjob.timer function takes precedence over this cronjob.  For
 more details, see the systemd.timer manpage, or use systemctl show
 certbot.timer.
 SHELL=/bin/sh
 PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
 0 */12 * * * root test -x /usr/bin/certbot -a ! -d /run/systemd/system && perl -e 'sleep int(rand(43200))' && certbot -q renew

It runs “At minute 0 past every 12th hour.” See https://crontab.guru/#0_*/12_*_*_*

Bonus Certbot Certificates to be renewed

When we checked for certs to be renewed we found the following under /etc/letsencrypt/renewal :

root@domain-staging:/etc/letsencrypt/renewal# ll
 total 12
 drwxr-xr-x 2 root root 4096 Feb 20 08:44 ./
 drwxr-xr-x 9 root root 4096 Feb 21 03:39 ../
 -rw-r--r-- 1 root root  632 Feb 20 08:44 concept.staging.domain.com.conf
 root@domain-staging:/etc/letsencrypt/renewal# cat concept.staging.domain.com.conf 
 renew_before_expiry = 30 days
 version = 0.31.0
 archive_dir = /etc/letsencrypt/archive/concept.staging.domain.com
 cert = /etc/letsencrypt/live/concept.staging.domain.com/cert.pem
 privkey = /etc/letsencrypt/live/concept.staging.domain.com/privkey.pem
 chain = /etc/letsencrypt/live/concept.staging.domain.com/chain.pem
 fullchain = /etc/letsencrypt/live/concept.staging.domain.com/fullchain.pem
 Options used in the renewal process
 [renewalparams]
 account = xxxxxxxxxxxx
 pref_challs = dns-01,
 server = https://acme-v02.api.letsencrypt.org/directory
 authenticator = manual
 manual_public_ip_logging_ok = True

This is the file Certbot will grab in our case for a renewal called by cron. In your case it may be different based on the command used and for what domain. We used DNS validation

sudo certbot certonly --manual --preferred-challenges dns --server https://acme-v02.api.letsencrypt.org/directory --manual-public-ip-logging-ok -d *.concept.staging.domain.com

On using this setup to add a certificate see also https://dev.to/nabbisen/let-s-encrypt-renew-wildcard-certificate-manually-with-certbot-1jp

You can adjust to change things if you want renewal to work out another way.

Wildcard Renewal Dry Run

When we did a dry run renewal we ran into issues

sudo certbot renew --dry-run
 Saving debug log to /var/log/letsencrypt/letsencrypt.log
 
 Processing /etc/letsencrypt/renewal/concept.staging.domain.com.conf
 
 Cert not due for renewal, but simulating renewal for dry run
 Could not choose appropriate plugin: The manual plugin is not working; there may be problems with your existing configuration.
 The error was: PluginError('An authentication script must be provided with --manual-auth-hook when using the manual plugin non-interactively.',)
 Attempting to renew cert (concept.staging.domain.com) from /etc/letsencrypt/renewal/concept.staging.domain.com.conf produced an unexpected error: The manual plugin is not working; there may be problems with your existing configuration.
 The error was: PluginError('An authentication script must be provided with --manual-auth-hook when using the manual plugin non-interactively.',). Skipping.
 All renewal attempts failed. The following certs could not be renewed:
   /etc/letsencrypt/live/concept.staging.domain.com/fullchain.pem (failure)
 
 ** DRY RUN: simulating 'certbot renew' close to cert expiry
 **          (The test certificates below have not been saved.)
 All renewal attempts failed. The following certs could not be renewed:
   /etc/letsencrypt/live/concept.staging.domain.com/fullchain.pem (failure)
 ** DRY RUN: simulating 'certbot renew' close to cert expiry
 **          (The test certificates above have not been saved.)
 
 1 renew failure(s), 0 parse failure(s)

Main gist was “PluginError (‘An authentication script must be provided with –manual-auth-hook when using the manual plugin non-interactively.’,).”

So that would suggest that cronjob might run but it would fail. Apparently that is the way of the world with wildcard certificates using Certbot . And an LE Community thread seems to confirm this.

For non wildcard ones not requiring a DNS challenge you should be able to run cron and get things renewed however. And if your domain hoster has a neat API you should be able to still automatically renew wildcard certificates. With the proper command that is:

sudo certbot certonly --manual --preferred-challenges dns --server https://acme-v02.api.letsencrypt.org/directory --manual-public-ip-logging-ok -d *.concept.staging.domain.com

And then have the TXT record updated for the check.

NB https://certbot.eff.org/docs/using.html?highlight=renew#modifying-the-renewal-configuration-file

NBB https://serverfault.com/a/934014/101547

Jasper Frumau

Jasper has been working with web frameworks and applications such as Laravel, Magento and his favorite CMS WordPress including Roots Trellis and Sage for more than a decade. He helps customers with web design and online marketing. Services provided are web design, ecommerce, SEO, content marketing. When Jasper is not coding, marketing a website, reading about the web or dreaming the internet of things he plays with his son, travels or run a few blocks.