🚀 A new era: Kirby 4 Get to know
Skip to content

Kirby meets Caddy

Kirby is compatible with many different web servers. However, in reality it is mostly Apache and sometimes nginx which are being used as webservers to run Kirby on. But there is also another, modern and very easy-to-configure alternative in the webserver world: Caddy.

Caddy: No support for .htaccess

Just like nginx, the Caddy webserver does not use the famous and project-specific .htaccess files that Kirby ships with. So instead of using this file, you'll have to configure the webserver manually through a special configuration file called Caddyfile. Caddy tries to load this file from the current directory, so run Caddy from the same folder that contains your Caddyfile or pass the path manually with caddy run --config /path/to/Caddyfile.

Configuration via Caddyfile

Caddy uses its own configuration file format and syntax. These Caddyfiles are typically very short and efficient and allow you to configure a webserver with a low number of lines. This is also due to the fact that Caddy uses a lot of very good and modern defaults compared to older webservers like Apache. Therefore Caddy makes it very easy to host websites with very little configuration and something like TLS only requires a single line in a Caddy configuration.

Web server configuration is a very big topic and there are many things to consider for every individual use case. We can only offer a starting point for a good config and we can't cover every aspect in this article. So this article will not cover every aspect of webserver configuration (e.g. performance-related optimizations).

Boilerplate config

(common) {
    php_fastcgi php:9000 # Adjust to your setup
    file_server
    encode zstd gzip
}

(kirby) {
    @blocked {
        path /content/* /site/* /kirby/* /.*
    }
    error @blocked "Not found" 404
    handle_errors {
        rewrite * /error # This should reference your Kirby error page
        import common
    }
}

mydomain.com { # Adjust to your setup
    import common
    import kirby
    root * /usr/share/caddy # Adjust to your setup
    tls name@user.com # Adjust to your setup
}

Line-by-line explanation

(common) {
    ...
}

(kirby) {
    ...
}

We're creating two custom snippets here with the names common and kirby. Snippets are blocks of configuration directives, which we can later reference and reuse. It's good style to put application-specific settings into their own snippets to know why given settings were initially put in place. So we're splitting our settings into a common snippet and kirby snippet.

php_fastcgi php:9000

This is the line that does the handover to the PHP interpreter. We're using the modern FastCGI interface for this handover. The php_fastcgi directive takes a network address or unix socket as a parameter, where a PHP-FPM process is listening and waiting for scripts to be run. So this setting depends on your specific setup. If you're using Docker, you can set the name and port of your FPM container (e.g. php:9000). If you're running PHP-FPM on the same system, you can use localhost followed by the port number.
The php_fastcgi directive also comes with a lot of good default values for PHP-specific configuration values (e.g. it automatically sets try_files to look for an index.php file – so a request gets forwarded to PHP when there is no file with a specific name)

file_server

This directive will make sure Caddy serves all static assets, e.g. all of the JavaScript, font files, icons, images, etc. Without this directive, only PHP files would be served/interpreted.

encode zstd gzip

We'll enable compression to reduce the transferred file size. This will make your site faster and has been supported by all major browsers for many years.

@blocked {
    path /content/* /site/* /kirby/* /.*
}
error @blocked "Not found" 404

Here we are doing some Kirby-specific error handling. First, we're defining a custom matcher – which is a statement that we can then use in multiple locations as an argument for other directives. Our matcher is called @blocked – because we're defining paths which should not be accessible by website visitors: everything in the content, site or kirby folders, as well as hidden files. In the following line, we're returning a 404 HTTP error, when any of these files are being requested.

handle_errors {
    rewrite * /error # This should reference your Kirby error page
    import common
}

The error we're returning from the line before will result in the browser showing an empty page – which is typically not what we want. Instead, we want to show Kirby's error page, which is served under the /error path by default. So we're rewriting all the requests coming into this error handler to the Kirby error page. And we also need the common block here, so PHP will be executed as well (because Kirby's error page is not a static HTML file, but is dynamically generated via PHP).

mydomain.com {
    ...
}

This is a site block, which is the top level component of a Caddyfile. The block begins with the address of our server. We're defining the domain so that Caddy can route incoming requests to the site and generate a certificate for it. Instead you can also put an IP address or a port number here (like :80), depending on your server setup.

import common
import kirby
root * /usr/share/caddy

Here, we're importing/using the two snippets we defined earlier. Also we're setting the root folder for this server, which should point to the absolute filesystem path, where your Kirby files are located.

tls name@user.com

This directive will take care of your TLS certificate. If you want to use a free certificate from Let's Encrypt, enter your email address here and you're done. If you want to run your Kirby site locally, use tls internal for a self-signed certificate.

Author