Caddy: Reverse proxy with WebDAV in a subdirectory

This is a quick listing of a working Caddy config for serving files via WebDAV while reverse_proxying other requests to another application. The config is done with the limitations of WebDAV in Windows Explorer in mind, so it should be possible to map it as a drive for example.

I'm going to assume that you've got a vanilla Caddy webserver running, as in, you installed it from the website or your distribution's repository. Your own domain is not a prerequisite, but would enable using this config as-is, including HTTPS with Let's Encrypt.

Prerequisites

The WebDAV handler does not come standard with a normal installation of Caddy. You must compile Caddy with caddy-webdav. I recommend going the xcaddy way. As a general recommendation, since you're compiling Caddy, anyway, you may include caddy-brotli – t enables Brotli compression which can bring down content size even further.

xcaddy build --with github.com/mholt/caddy-webdav --with github.com/ueffel/caddy-brotli

Then stop Caddy and replace the binary. You don't need to start Caddy yet since you'll be editing the config, anyway.

install -uroot -groot -m755 caddy /usr/bin/caddy && rm caddy

Caddyfile

{
        email mail@something.tld
        order webdav before file_server
}

yourdomain.tld {
        tls {
                ciphers TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
                curves x25519 secp256r1 secp384r1
                protocols tls1.2 tls1.3
        }
        header Strict-Transport-Security "max-age=63072000"
        
        # If you compiled with caddy-brotli, otherwise simply delete. The default is "zstd gzip", anyway.
        encode br zstd gzip

        root /var/www/files
        rewrite /files /files/
        handle /files/* {
                webdav {
                        root /var/www/files/
                        prefix /files
                }
                file_server
        }
        handle {
                reverse_proxy localhost:8000
        }
}

The important bits are:

  • order webdav before file_server: WebDAV is a non-standard addition to Caddy, so it's not in the standard handler chain. It must be placed in it, otherwise the handler is never executed, and so WebDAV never served. The alternative is to specify it in an explicit order via route in the server block.
  • tls: If you plan to access it with Windows Explorer, those options are a must. Omit if you're not going to map a drive in Windows. Caddy defaults don't seem to work with Windows Explorer. It was a bit of a fight to figure this out because neither Explorer nor Batch nor PowerShell are clear on what they don't like about them. Courtesy of Mozilla's SSL Config Generator (Intermediate configuration).
  • The handle directives: Technically not necessary as directives with path matchers are ordered from most to least specific, anyway (/files/1/ before /files/ before no matchers = *), but only those who know Caddy may know that and would correctly understand the following example, which is equivalent but assumes one knows that /files/* is matched first, despite the presumed order in the Caddyfile.
file_server
reverse_proxy localhost:8000
webdav /files/* {
    root /var/www/files/
    prefix /files
}

After making sure /var/www/files actually exists, start Caddy. Should Windows Explorer refuse to map the drive, use Batch:

net use Z: https://yourdomain.tld/files

Let the trouleshooting begin. Into the comments, if you would; it's (registration-)free, anyway.