Is it possible to use multiple directives? (E.g. respond and file_server)

1. My Caddy version (caddy version):

(devel) V2 RC2

2. How I run Caddy:

Manually as a Linux service.

systemctl start caddy

# change Caddyfile...

systemctl reload caddy

a. System environment:

uname -a
Linux 4.19.0-8-amd64 #1 SMP Debian 4.19.98-1 (2020-01-26) x86_64 GNU/Linux

b. Command:

systemctl reload caddy

c. Service/unit/compose file:

# caddy.service
#
# For using Caddy with a config file.
#
# Make sure the ExecStart and ExecReload commands are correct
# for your installation.
#
# WARNING: This service does not use the --resume flag, so if you
# use the API to make changes, they will be overwritten by the
# Caddyfile next time the service is restarted. If you intend to
# use Caddy's API to configure it, add the --resume flag to the
# `caddy run` command or use the caddy-api.service file instead.

[Unit]
Description=Caddy
Documentation=https://caddyserver.com/docs/
After=network.target

[Service]
User=caddy
Group=caddy
ExecStart=/usr/bin/caddy run --environ --config /etc/caddy/Caddyfile
ExecReload=/usr/bin/caddy reload --config /etc/caddy/Caddyfile
TimeoutStopSec=5s
LimitNOFILE=1048576
LimitNPROC=512
PrivateTmp=true
ProtectSystem=full
AmbientCapabilities=CAP_NET_BIND_SERVICE

[Install]
WantedBy=multi-user.target

d. My complete Caddyfile or JSON config:

example.com {
	log {
		output file /var/log/caddy_access.log
	}
	
       respond / "This works"
	
	file_server /test {
		root /srv/www/test
	}
}

3. The problem I’m having:

I’m trying to have this site serve a simple text response on the / path and then have a file_server directive serve a simple index file from the /test path.

The respond directive is working fine: Status 200, the simple body text is returned.

The /test path gives me a 404.

4. Error messages and/or full log output:

No errors.

5. What I already tried:

I’ve tried the following:

Test that the file_server works on the root path:

This works fine, the index.html is served from the /srv/www/test directory when getting the / path.

example.com {
	log {
		output file /var/log/caddy_access.log
	}
	
     root * /srv/www/test
     file_server
}

Test if the file_server directive works with a global root directive and a path matcher

This doesn’t work. I get a 404 on /test and a 200 on / with the respond text.

example.com {
	log {
		output file /var/log/caddy_access.log
	}

     respond / "This works"
     root * /srv/www/test
     file_server /test
}

6. Links to relevant resources:

N/A

Thanks in advance for your help! :sparkles: :bowing_man:

Path matchers in v2 are exact-match, not prefix-match. That means that you need to use /test* or /test/* as your matcher instead.

A request to /test will look for a file named test inside of your /srv/www/test directory, i.e. /srv/www/test/test.

Path matchers in v2 are exact-match, not prefix-match. That means that you need to use /test* or /test/* as your matcher instead.

Thanks for the tip, @francislavoie. I tried updating my Caddyfile to the following, but I still get a 404 on /test:

example.com {
	respond / "Getting there"
	root * /srv/www/test
	file_server /test*
}

Also tried this, which also resulted in a 404:

example.com {
	respond / "Getting there"
	file_server /test* {
              root /srv/www/test
        }
}

Did I misunderstand your suggestion? :thinking:

What does your site structure look like? What files are you actually trying to serve?

Run this and paste the output, it should give us a better idea of what’s going on:

$ cd /srv/www
$ tree

My hunch is that you should be using root * /srv/www instead, because Caddy looks in your filesystem at {root}{path} for files to serve. This means that if your root is /srv/www/test and your request path is /test, then it looks for /srv/www/test/test.

Alternatively, you can rewrite the URL to strip the /test prefix when relevant. For example:

route /test/* {
    root * /srv/www
    uri strip_prefix /test
    file_server
}

Since you seem to want to handle requests specifically to /test as /test/index.html, you’ll need to redirect (preferred) or rewrite the requests to /test exactly to /test/.

redir /test {path}/ 308

This is because if you matched on /test*, it would also match /testasdasd, so it’s better to match /test* and do a redirect to add the final slash.

You’re correct! This was the missing piece of the puzzle. I didn’t pick this up from the documentation, but maybe it’s in there somewhere, or perhaps an example would be helpful.

In any case, here’s the directory structure of /srv/www (it’s very simple):

/srv/www
└── test
    └── index.html

Here’s the Caddyfile that works the way I want (the / path uses the respond directive and the /test path uses the file_server directive to serve the file at /srv/www/test/index.html):

example.com {
  route / {
    respond "Root path"
  }
  root * /srv/www
  file_server /test
}

Thanks for your help, @francislavoie! :sparkling_heart:

1 Like

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