Caddy 2.4.0 beta 1 is now available

All the major features planned for the next release are finished, so Caddy 2.4 beta 1 is now available. Please try it out! We’re still polishing things to make it even better before the release candidates, and documentation will be updated later, but for now you can start using it:

:newspaper: Release notes and :arrow_down: Download

New content for sponsors

If you or your company is sponsoring Caddy, you have access to my new Expert Caddy series of chapters, which goes into depth about Caddy and related topics that will help you make the most of your web server. If you’re not already a sponsor, sign up here:

Thank you for your ongoing support! It will allow me to continue working on Caddy full-time.


The self upgrade feature caught my attention. :star_struck: My reading of the release notes is that it will work with pre-built binaries as well as binaries built from source with additional packages. Is my interpretation correct? And this feature will work on any supported platform?

1 Like

Yeah, the idea is it will read your current binary’s list-modules output to figure out which external modules were compiled in, then it’ll make a request to Download Caddy requesting a new binary with the latest version and the same external modules you already had.

1 Like

Will Caddy still be available throughout the upgrade or is there likely to be an interruption to service at some point during the upgrade?

I’m just wondering if the command should be run manually under controlled conditions, or, running the command automatically on a periodic basis will be fine.

1 Like

No interruption, because all it does is swap out the binary. You will need to restart the Caddy process for the upgrade to take effect. See the code:


If I were to script the upgrade command to run on a periodic basis, would it be possible to implement the following psuedocode?

If caddy was upgraded then restart caddy

If it were possible, what I’m trying to figure out is what status code should I look for after caddy upgrade runs that indicates the command ran successfully and an upgrade actually took place, as opposed to, the command ran successfully, but no new version was installed?

I tried (unsuccessfully!) to figure it out by studying the code, and noticed several error conditions are checked for.

You could do it yourself by assembling a cron job that tries to upgrade, then checks the last updated time of the file to see if it was recently updated, and if so restart.

I don’t think that will be built-in to Caddy because Caddy is cross-platform and the procedure for that is different depending on how you run it.

1 Like

Exit status 0 means success, then caddy version will tell you the new version. If it’s different from before, then a different version was installed.

1 Like

Thanks @francislavoie and @matt. That gives me some ideas to work with.

After a successful caddy upgrade, until Caddy is restarted, wouldn’t caddy version still give me the old version i.e. the Caddy instance that is presently running rather than the version of the binary just replaced?

No. The old binary won’t exist anymore so it will have to run the new one.

1 Like

If you use any commands that use the API, like caddy reload, then it would reload the currently running instance (old binary) by using the new binary to send the reload message, but commands like caddy version that just query the currently available binary, it’ll use the latest.


Here’s a version of a bash script that can be run periodically as a cron job to automatically upgrade Caddy 2.4.0 and above to the most current release of Caddy. It should run on FreeBSD systems and its derivatives like FreeNAS/TrueNAS. It implements the logic discussed in the last few posts of this thread and can probably be adapted for other Unix-like systems that also run Caddy.

ver=$(caddy version)
caddy upgrade
if [ $status -eq 0 ]; then
  if [ "$(caddy version)" != "$ver" ]; then
    service caddy restart
  echo "Something bad happened! Upgrade status=$status"

I installed the 2.4.0-beta.1 static binary and then manually ran caddy upgrade. I had in my mind that the latest tweaks to beta.1 would be applied. The upgrade went through successfully. The only issue was that Caddy was downgraded to 2.3.0 :sob:

[root@wp-basil /usr/local/bin]# caddy version
v2.4.0-beta.1 h1:Ed/tIaN3p6z8M3pEiXWJL/T8JmCqV62FrSJCHKquW/I=
[root@wp-basil /usr/local/bin]# caddy upgrade
2021/03/09 17:19:29.637 INFO    this executable will be replaced        {"path": "/usr/local/bin/caddy"}
2021/03/09 17:19:29.637 INFO    requesting build        {"os": "freebsd", "arch": "amd64", "packages": []}
2021/03/09 17:19:30.381 INFO    build acquired; backing up current executable   {"current_path": "/usr/local/bin/caddy", "backup_path": "/usr/local/bin/caddy.tmp"}
2021/03/09 17:19:30.381 INFO    downloading binary      {"source": "", "destination": "/usr/local/bin/caddy"}
2021/03/09 17:19:42.494 INFO    download successful; displaying new binary details      {"location": "/usr/local/bin/caddy"}

Module versions:

admin.api.load v2.3.0
admin.api.metrics v2.3.0
caddy.adapters.caddyfile v2.3.0
caddy.listeners.tls v2.3.0
caddy.logging.encoders.console v2.3.0
caddy.logging.encoders.filter v2.3.0
caddy.logging.encoders.filter.delete v2.3.0
caddy.logging.encoders.filter.ip_mask v2.3.0
caddy.logging.encoders.json v2.3.0
caddy.logging.encoders.logfmt v2.3.0
caddy.logging.encoders.single_field v2.3.0
caddy.logging.writers.discard v2.3.0
caddy.logging.writers.file v2.3.0 v2.3.0
caddy.logging.writers.stderr v2.3.0
caddy.logging.writers.stdout v2.3.0 v2.3.0
http v2.3.0
http.authentication.hashes.bcrypt v2.3.0
http.authentication.hashes.scrypt v2.3.0
http.authentication.providers.http_basic v2.3.0
http.encoders.gzip v2.3.0
http.encoders.zstd v2.3.0
http.handlers.acme_server v2.3.0
http.handlers.authentication v2.3.0
http.handlers.encode v2.3.0
http.handlers.error v2.3.0
http.handlers.file_server v2.3.0
http.handlers.headers v2.3.0 v2.3.0
http.handlers.metrics v2.3.0
http.handlers.push v2.3.0
http.handlers.request_body v2.3.0
http.handlers.reverse_proxy v2.3.0
http.handlers.rewrite v2.3.0
http.handlers.static_response v2.3.0
http.handlers.subroute v2.3.0
http.handlers.templates v2.3.0
http.handlers.vars v2.3.0
http.matchers.expression v2.3.0
http.matchers.file v2.3.0
http.matchers.header v2.3.0
http.matchers.header_regexp v2.3.0 v2.3.0
http.matchers.method v2.3.0
http.matchers.not v2.3.0
http.matchers.path v2.3.0
http.matchers.path_regexp v2.3.0
http.matchers.protocol v2.3.0
http.matchers.query v2.3.0
http.matchers.remote_ip v2.3.0
http.matchers.vars v2.3.0
http.matchers.vars_regexp v2.3.0
http.reverse_proxy.selection_policies.cookie v2.3.0
http.reverse_proxy.selection_policies.first v2.3.0
http.reverse_proxy.selection_policies.header v2.3.0
http.reverse_proxy.selection_policies.ip_hash v2.3.0
http.reverse_proxy.selection_policies.least_conn v2.3.0
http.reverse_proxy.selection_policies.random v2.3.0
http.reverse_proxy.selection_policies.random_choose v2.3.0
http.reverse_proxy.selection_policies.round_robin v2.3.0
http.reverse_proxy.selection_policies.uri_hash v2.3.0
http.reverse_proxy.transport.fastcgi v2.3.0
http.reverse_proxy.transport.http v2.3.0
pki v2.3.0
tls v2.3.0
pki v2.3.0
tls v2.3.0
tls.certificates.automate v2.3.0
tls.certificates.load_files v2.3.0
tls.certificates.load_folders v2.3.0
tls.certificates.load_pem v2.3.0
tls.handshake_match.sni v2.3.0
tls.issuance.acme v2.3.0
tls.issuance.internal v2.3.0
tls.issuance.zerossl v2.3.0
tls.stek.distributed v2.3.0
tls.stek.standard v2.3.0

v2.3.0 h1:fnrqJLa3G5vfxcxmOH/+kJOcunPLhSBnjgIvjXV/QTA=

2021/03/09 17:19:42.604 INFO    upgrade successful; please restart any running Caddy instances  {"executable": "/usr/local/bin/caddy"}
[root@wp-basil /usr/local/bin]# service caddy restart
Stopping caddy.
Waiting for PIDS: 76788.
[root@wp-basil /usr/local/bin]# caddy version
v2.3.0 h1:fnrqJLa3G5vfxcxmOH/+kJOcunPLhSBnjgIvjXV/QTA=

In addition, although the output from caddy upgrade suggests that the previous version of Caddy would be backed up as /usr/local/bin/caddy.tmp, the backup didn’t occur.

Ha - that probably shouldn’t happen, it shouldn’t fetch an older version than you’re currently running even if you’re running a beta. Mind filing an issue on github?

1 Like

It’s intentional that it upgrades you to the latest stable. Depending on how you define upgrade, changing from a pre-release to a stable release is an upgrade. I dunno. I’m not actually sure that is wrong?

But I can also see arguments for this.