A look at Caddy - A simple and fast web server

We’ve all used Apache and NGNIX when we have had to host a website and they are fin but let’s be honest, I’ve never gotten along with their config. And that is what bought me to Caddy. Lets take a look at what Caddy has to offer.

Caddy

Caddy is a unique (at least I think) web server with a modern feature set. You can use it as reverse proxy and load balancer. Host your PHP apps with it.. And I almost forgot one of the best features; automatic HTTPS, with certificates using acme providers like Lets Encrypt and ZeroSSL.

Cool, Right?

Caddy is available as a single executable, a docker image or as usual via a package manager. Today we’ll be using Debian. But the if you use another OS their docs should have you covered.

bash

sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddy

Once installed the service will run automatically and serve the default welcome page on port 80. Caddy can then be configured using the file Caddyfile in /etc/caddy

As said above caddy can be configured using the file Caddyfile in /etc/caddy. In this file we give it directives to either be a reverse proxy, web server, php front, etc. Caddy can also be configured using its REST API if that’s something that interests you.

Let’s say you had an app running on port 9999 that you wanted to reverse proxy to 443 (HTTPS). The config file would look like so:

json

demo.app.com {
    reverse_proxy 127.0.0.1:9999
    encode gzip
}

For caddy to reload the Caddyfile we just need to run a systemctl reload caddy, Caddy will then reload the config file, request a certificate for demo.app.com and then serve your app over HTTPS1.

Okay a reverse proxy is nice but my website (this one) is static and generated by Hugo, how could we serve it using caddy? Again only 4 lines of config is enough.

json

demo.website.com {
    # where our static files are stored
    root * /var/www/demo.droapp.com/public
    file_server 
}

A quick systemctl reload caddy later and Caddy is serving your static files over HTTPS1 at demo.website.com

You would usually use Nginx as a front for PHP-fpm, well Caddy can do that too. And again with a simple config file.

json

demo.website.com {
        # where our files are stored
        root * /var/www/demo.website.com
        # we tell caddy where to find the php-fpm socket
	    php_fastcgi /run/php/php8.2-fpm.sock	
        file_server
        encode gzip
}

Again a quick systemctl reload caddy and we are now fronting a php app over HTTPS1.

Caddy is also often run with Docker Compose and is still as simple. Here is a simple docker-compose.yml and we can use any example Caddyfile from above.

yml

version: "3.7"

services:
  caddy:
    image: caddy:<version>
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"
    volumes:
      - $PWD/Caddyfile:/etc/caddy/Caddyfile
      - $PWD/caddy_data:/data
      - $PWD/caddy_config:/config
      - $PWD/site:/srv # If we wanted to serve static files in $PWD/site
Docs
Caddy has some of the best documentation I’ve seen in a while. There are plenty of other functions that I’ve not covered here.

And with that, I think I have covered the basics of using Caddy. Do you use it? Tell me how and what you think.

Cheers - Designated Survivor

Original Feature photo by Valery Sysoev at Unsplash


  1. Caddy will only succeed at requesting a certificate if you have ports 80 and 443 open on your server. You can also disable the certificate request if not needed. Other options like local HTTPS can also be used ↩︎ ↩︎ ↩︎

Related Content