After switching from NGINX to Caddy on all of my websites, I have come to the conclusion that Caddy is the best webserver in existence. With automatic HTTPS, a simple configuration file, and more, Caddy is just the best webserver overall for general use.

Built-in automatic HTTPS link icon

Caddy can fetch certificates from Let’s Encrypt and ZeroSSL out of the box. HTTPS is enabled by default for eligible domains1, unless you explicitly tell it not to.

Incredible cipher security link icon

Caddy has incredible defaults for TLS/SSL ciphers. Any site you host on Caddy gets a perfect score from Qualys SSL Labs out of the box.2

Dead simple configuration files: Caddy vs NGINX link icon

Caddy’s configuration file format is the easiest out of all the main webserver. The best way for me to demonstrate this simplicity is to compare it to one of the most popular webservers: NGINX.

Serving some static files link icon

The most essential feature you can use a webserver for.

Caddy link icon

caddyfile
Copy
1
2
3
4
example.com {
  root * /var/www/example.com
  file_server
}

NGINX link icon

nginx
Copy
1
2
3
4
5
6
7
8
9
server {
    listen 80;
    server_name example.com;
    index index.html index.txt;
    root /var/www/example.com;
    location / {
        try_files $uri $uri/ =404;
    }
}

As you can see, the Caddy config is a lot simpler than the NGINX one. But wait, there’s more! This NGINX config is unencrypted HTTP only, but the Caddy one will automatically request a certificate from Let’s Encrypt, enable HTTPS, and even redirect unencrypted HTTP to HTTPS.

From now on, for the sake of simplicity, I’ll be ignoring HTTPS for the NGINX configs.

PHP (PrivateBin) link icon

The Caddy config for this example is the same as the one used for bin.boba.best. I’ve stripped it down a bit by removing the custom error pages, HSTS, zstd compression, and logging.

Caddy link icon

caddyfile
Copy
1
2
3
4
5
6
7
bin.boba.best {
    encode gzip

    root * /var/www/bin.boba.best
    php_fastcgi unix//run/php/php-fpm.sock
    file_server
}

NGINX link icon

nginx
Copy
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
server {
    listen 80;
    server_name bin.boba.best;
    index index.html index.txt index.php;
    root /var/www/bin.boba.best;
    gzip on;

    location / {
        try_files $uri $uri/ =404;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php-fpm.sock;
    }
}

Reverse proxy + static files (Gitea) link icon

This last example is based on git.bbaovanc.com. Just like the last example, I’ve stripped off the custom error pages, HSTS, zstd compression, and logging.

Caddy link icon

caddyfile
Copy
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
git.bbaovanc.com {
    encode gzip

    handle_path /_/static/assets/* {
        root * /var/www/git.bbaovanc.com/public
        file_server
    }

    handle {
        reverse_proxy localhost:81 {
            header_up X-Real-IP {remote_host}
        }
    }
}

NGINX link icon

nginx
Copy
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
server {
    listen 80;
    server_name git.bbaovanc.com;
    gzip on;

    location /_/static/assets {
        alias /var/www/git.bbaovanc.com/public/;
    }

    location / {
        proxy_pass http://localhost:81;
        proxy_set_header X-Real-IP $remote_addr;
    }

Although in this case the NGINX config was slightly shorter, I find the Caddy one a lot more clear and easy to understand. With NGINX, I find it weird how adding a trailing slash or not defines whether the prefix (/_/static/assets in this case) is stripped before searching the filesystem. In Caddy, you can use the handle_path directive, instead of just a regular handle directive.

You can read more about how handle and handle_path work in Caddy on the Caddy docs.

The smaller details link icon

These features might not matter to you, but this is my blog, and I care about them, so I’ll be including them.

Go templates link icon

Caddy is written in Go and supports Go templates. This means you can make simple dynamic content while only using Caddy!

In fact, the official Caddy website is generated entirely using Caddy’s and Go templates!3

Error pages using HTTP Cats link icon

I use this snippet on both bbaovanc.com and boba.best to make custom error pages using images from HTTP Cats. It uses Caddy’s template support to generate some simple HTML to show the error code, name, and cat image.

Beautiful autoindex file browser link icon

Apache and NGINX both have an optional “autoindex” feature which generates a list of files in a directory when there’s no page there. However, it looks very ugly. Caddy, on the other hand, still has a simple index page, but looks a thousand times better.

Coincidentally, it matches the theme of my website very well, so I have to put a border around the image.

Caddy's gorgeous directory list page.
Caddy’s gorgeous directory list page.


  1. For the rules on what domains have automatic HTTPS by default, see “Hostname requirements” on the Caddy documentation↩︎

  2. SSL Labs caps the score to an A if HSTS isn’t enabled. After enabling it, then you get a perfect A+ score. See my website’s score (archived) for an example (bbaovanc.com). ↩︎

  3. See more info about templating on the Caddy docs ↩︎