Two months ago I started to “Serve The Web Like It’s 2016”, and I’m still loving Caddy!

Caddy?

Wooha, hold your horses, what is Caddy?! Caddy is a web server like Apache or Nginx, but different:

  • Caddy is a modern web server (supporting HTTP/2) with elegant and easy configuration. It comes with automated HTTPS (with Let’s Encrypt) and a growing number of extensions (including Git support).
  • It’s open source software, written in Go, and driven by an awesome community.
  • Well documented
  • Cross-platform: available for Linux, Mac OS X, FreeBSD, Windows, OpenBSD and Android.
  • All this in just one binary executable!

Caddy logoCaddyfile

Configuration for Caddy is done using a Caddyfile, which is a new language specifically for Caddy (ok, this seems odd at first sight). But by using a domain specific language, configuration becomes very simpel and to-the-point.

Caddy is very powerful (and easy at the same time), which I will demonstrate with Caddyfile snippets for some of my real-world situations.

Configuring Caddy can be very easy for most sites:

denbeke.be {
    root sites/denbeke.be
}

Look, I just created the config for a static website with a document root. This site is automatically served over HTTPS, and HTTP traffic is automatically redirected to HTTPS1.

Dynamic PHP websites are of course also supported. Simply use PHP-FPM as you would do with Nginx:

denbeke.be {
    root sites/denbeke
    fastcgi / unix:/var/run/php/php7.0-fpm.sock php
}

But Caddy is not only easy, it comes packed with a lot of features, which support a lot of use cases.

My personal WordPress blog runs perfectly with only 12 lines of code:

www.denbeke.be {
    redir https://denbeke.be{uri}
}

denbeke.be {

    root sites/denbeke
    log sites/logs/denbeke.be.access.log
    errors sites/logs/denbeke.be.error.log

    fastcgi / unix:/var/run/php/php7.0-fpm.sock php

    # Routing for WordPress
    rewrite /blog {
        to {path} {path}/ /blog/index.php?{query}
    }

    gzip
    header /blog/wp-content/ Cache-Control "max-age=2592000"
    header /blog/wp-includes/js/ Cache-Control "max-age=2592000"

}

I have a redirect from www.denbeke.be to denbeke.be, redirect from HTTP to HTTPS (note that non-HTTPS traffic is automatically redirected to HTTPS with Caddy by default1), error and access logging, and PHP with routing for WordPress. I also compress all content with gzip and set caching headers to optimize used bandwidth.

For my Git server, I have a reverse proxy to Gogs. Again, Caddy takes care of HTTPS… The Caddyfile for this is again trivial:

git.denbeke.be {
    proxy / http://localhost:3000
}

My last example is the website for a group project, where the complete website is put in a Git repo, so all contributors can edit the website. The following directive will clone the complete repo on initial setup, and pull changes every hour:

oakstrong.be {
    root sites/oakstrong
    git https://bitbucket.org/oakstrong/oakstrong.be.git
}

It’s all very easy, isn’t it?

And this is just a subset of Caddy’s capabilities, Caddy supports a lot more, like automated Hugo publishing (French blogpost), running Caddy on Android, or any other PHP CMS or static site generator. Caddy also has a growing number of add-ons/modules, which add a variety of features to Caddy, like Prometheus metrics, IP filtering, search, Cross Origin Resource Sharing, JSONP, …

Running Caddy as a service…

… is easy! (and others, including myself, already made configuration files and tutorials about it)

Caddy in production: rock solid!

But have you tried running Caddy in production? Is this new and young web server stable enough? Doesn’t it sometimes crash?
Simple answer Yes it’s stable, and No it hasn’t crashed yet.

Pingdom Uptime report Caddy webserver

At the beginning of February 2016 I made the switch from Nginx to Caddy (together with the switch from PHP 5 to PHP 7) on my home server and my production server. Two months later Caddy already served thousands of visitors on various websites.2 Caddy hasn’t crashed ever since, and I currently have 100% uptime on my production server.3

Does this mean that Caddy is perfect and bug-free? Of course not!
I started using Caddy in production after a stupid FastCGI bug was fixed (which caused requests to block). While moving to production I submitted a few pull requests and issues on GitHub to fix some important and less important bugs. But I can confirm Caddy now perfectly works with WordPress, Piwik, ownCloud, Vanilla Forums, SMF, and all self-written PHP stuff.

If you take a look at the issues, pull requests, or Gitter, you’ll quickly notice that Caddy is a very active project, in which bugs got fixed very swiftly by a growing community. Caddy currently has 67 70 contributors.

Conclusion

Caddy is awesome! And getting better every day!


  1. If you don’t want to use automated HTTPS certificates, you can specify your own certificates (or disable HTTPS) using the tls directive.
  2. I must admit that I’m not serving high traffic websites, but Matt Holt got this reply from ‘a guy’:

    I got this email from a user that has sometimes has ~100 concurrent users on his site (that uses PHP), and switched from nginx to Caddy:

    The server has been performing well and server resources are the most free that they’ve been in months.

  3. Something else to admit… right after I wrote this blogpost, my MySQL server crashed, so I can’t speak of a 100% uptime anymore. But this doesn’t change the fact that Caddy hasn’t caused any problems (yet).