V2: How to serve files with rewrite?

1. Caddy version (caddy version):


2. How I run Caddy:

a. System environment:

Ubuntu 18.04 with systemd 237

b. Command:

systemctl start caddy

c. Service/unit/compose file:

The same as provided in the documentation.

d. My complete Caddyfile or JSON config:

localtest.com {
    rewrite /A/* /B/*
    route /B/* {
        root * /mnt/Data/projects/frontends/B

    reverse_proxy /api/*

3. The problem I’m having:

What I’m trying to do is to serve the files (some HTML files) in root, but by using the path prefix /A/ instead of the actual directory name B. Also I don’t want to expose /B/ to the outside world.

Basically this is to provide consistent path prefix, since the directory name (B) might change in the future, but I don’t want the path to change for my clients. Also this prevent users from knowing the actually directory name.

But I’m always getting 404 response, caddy seems to think the files does not exist.

This used to be working with Caddy V1 with a little hack: Mark /B/ as internal, and respond with X-Accel-Redirect header:

localtest.com {
    root /mnt/Data/projects/frontends
    internal /B/
    proxy /A/ { transparent } 
    # Here: 1. the backend respond with `X-Accel-Redirect: /B/my_file.html`, and
    # 2. caddy intercepts this header, serving `/mnt/Data/projects/frontends/B/my_file.html` to the client.

    reverse_proxy /api/*

4. Error messages and/or full log output:

5. What I already tried:

6. Links to relevant resources:

It seems like I can do this:

localtest.com {
    handle /A/* {
        uri replace /A/ /B/
        root * /mnt/Data/projects/frontends
        file_server /B/*
    # And I need to manually block the access to /B/* directly, otherwise caddy respond with an empty 200
    respond /B/* 404

    reverse_proxy /api/*

Not sure how I missed it. However this is much more confusing to read (at least for me). I wonder if anyone has a better idea.

Welcome Nop –

It looks like the /B directory is already part of your root path, so that will never need to appear in the URI, since the URI is just appended to the root when opening files.

To serve files out of /mnt/Data/projects/frontends/B with a path prefix of /A (stripped, so that it doesn’t append /A when trying to access the actual file), this is all you need:

root * /mnt/Data/projects/frontends/B
uri strip_prefix /A

Thanks for your quick reply. It seems really easy once I understand the logic.

1 Like

For more fun with route composition, read our latest wiki article: Composing in the Caddyfile

1 Like

This topic was automatically closed after 30 days. New replies are no longer allowed.