Reverse_proxy, except for one route

1. Caddy version (caddy version):

Docker 2.4.3

2. How I run Caddy:

via official Docker image

a. System environment:

Ubuntu 20

b. Command:

sudo docker exec -w /etc/caddy <id> caddy reload

c. Service/unit/compose file:

Paste full file contents here.
Make sure backticks stay on their own lines,
and the post looks nice in the preview pane.

d. My complete Caddyfile or JSON config:

my.site.com {
        tls admin@thiswebsite.com 
        # everything else works except the next line
        rewrite /showlog /opt/myapp/logs/MyService.log
        reverse_proxy localhost:9990 
        log
}

3. The problem I’m having:

Caddy is working fine reverse-proxying to my application. Thank you.
Now I would like to make one special route /showlog that would NOT go to the application, instead, it would return the logfile located at /opt/myapp/logs/MyService.log
I do not need a full file_server. Just to be able to read the one single file.
I tried inserting a rewrite, but I just get a 404 error, same as any route that my application does not accept.

4. Error messages and/or full log output:

404

5. What I already tried:

added the following line:
rewrite /showlog /opt/myapp/logs/MyService.log

I’ve read the Caddyfile docs and don’t see an alternative command that handles this use case.

6. Links to relevant resources:

A rewrite only changes the request path. It doesn’t serve a file on its own. You need to use the root and file_server directives for this.

Also, it’s not safe to set your root to something wide, because then someone could potentially find a way to traverse your filesystem and get at files they shouldn’t have access to. Just FYI, by default when running in Docker, Caddy’s default root is /srv (i.e. the WORKDIR set in the Docker image.

Also, since you only want to serve one file statically, you’ll need to use handle blocks to override Caddy’s default directive order; Caddy sorts directives according to that predetermined order, so that users don’t have to order things correctly themselves and things should usually work. But you’re unlucky in this case and the order works against you. So handle blocks can be used to make mutually exclusive routing paths.

my.site.com {
	tls admin@thiswebsite.com
	log

	handle /showlog {
		root * /opt/mypp/logs
		rewrite * /MyService.log
		file_server
	}

	handle {
		reverse_proxy:9990
	}
}

Thank you SO MUCH for this @francislavoie , I would not have found the handle command, nor would I have been able to get the config precisely correct.

I want to add, for any future readers, I spent a long while banging my head not getting the above to work. Finally I realized because I’m using Docker, the filepath of the root command was pointing inside the Docker container, not the host. And because previously, I had no static files to serve, I had no need to mount a host path into the container’s /srv. Once I did that (by adding an extra -v /path/to/my/logs:/srv to the docker run command), yes I was able to get it to work. Plus, you don’t need the root directive anymore because the host’s /logs dir is now mounted to the default /srv in the container.

One other tip for future readers: if you want to serve the whole directory, handle /showlog must be handle /showlog/*, and remove the rewrite. The difference is that the URL must contain the file name, i.e. mysite.com/showlog/index.html

Final Caddyfile:

my.site.com {
        tls admin@thiswebsite.com
        log

        handle /showlog {
                rewrite * /MyService.log
                file_server
        }

        handle {
                reverse_proxy localhost:9990
        }

}
1 Like

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