Using Templates together with a Reverse Proxy

1. Caddy version (caddy version):

2.5.1

2. How I run Caddy:

with docker

a. System environment:

Windows & Docker

b. Command:

I run the docker container for 2.5.1 so I guess it uses whatever command that does because when I bring the stack up caddy is already running.

c. Service/unit/compose file:

Here is the docker compose file

version: "3.9"

services:
  caddy:
    image: caddy:2.5.1
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./www-data:/var/www
      - ./config:/etc/caddy
  db:
    image: mysql:8.0
    volumes:
      - db_data:/var/lib/mysql
    restart: always
    env_file:
      - db-variables.env
  wordpress:
    depends_on:
      - db
    image: wordpress:6.0
    restart: always
    env_file:
      - wp-variables.env
    volumes:
      - ./www-data:/var/www/html
volumes:
  www-data:
    driver: local
    driver_opts:
      type: "none"
      o: "bind"
      device: "./www-data"
  db_data: {}

d. My complete Caddyfile or JSON config:

3. The problem I’m having:

I have been working on a little project to merge a bunch of websites together that don’t have a CMS and control the new site via Caddy Templates, and Wordpress together. Just about everything works but I am having some difficulties getting the reverse proxy and templates to work together.

If I remove the reverse_proxy to wordpress templates work fine. While I am using the reverse_proxy templates do not work. I believe this is because of the issue mentioned in this thread {{ Templates }} are not working for me that the basic reverse proxy does not have any added functionality like templates.

I read through the documentation on this, but I still couldn’t find a way to get the two things to work together. Is it possible to reverse proxy to my wordpress container, and still use templates. If so, how?

4. Error messages and/or full log output:

I don’t get an error message I just see the

{{include "/includes/header.html"}}

on the webpage instead of the content that I wanted to include. And again this is only if I have the reverse proxy running, if I comment it out in my Caddyfile and then reload the templates work fine.

5. What I already tried:

I don’t even know where to start. I read this page

and the options there went over my head.

6. Links to relevant resources:

Github Repo

I’m not sure I understand what you’re trying to do frankly. Could you explain?

Seems strange to be mixing file_server with reverse_proxy, especially because if you don’t use a matcher to tell Caddy when to use each. The reverse_proxy handler will “shadow” the file_server one with your current config, because it’s higher in the directive order:

Templates should work with reverse_proxy though. Maybe your upstream isn’t returning the right content type? The templates handler will only run on particular allow-listed values of the Content-Type header. See the docs for template:

Try to make the requests with curl -v, what do you see? Show us what the response looks like.

1 Like

Thank you for the response.

You asked:

I’m not sure I understand what you’re trying to do frankly. Could you explain?

I want to reverse proxy to a wordpress instance, and I want templates to be running also; so that publishers of the website will have the option to use either Wordpress CMS or Caddy Templates.

You mentioned:

The reverse_proxy handler will “shadow” the file_server one with your current config, because it’s higher in the directive order

If I changed the directive order so that it was a file_server first, I think it would deliver a PHP file from wordpress in a way that does not run PHP properly because it would not be reverse proxying to a running PHP process.

I could solve the problem easy by using 2 subdomains

But the aim of this project is to make this work using sub-folders.

Do you have any suggestions how I could make that work?

Then in that case you should do this:

mywebsite.com {
	handle_path /templates* {
		root * /www-data
		try_files {path}.html {path}
		templates
		file_server
	}

	handle {
		reverse_proxy wordpress:80
	}
}

That way, all requests to the path /templates will get served by Caddy’s file server with template post-processing, and anything else will hit your WordPress server.

Thank you!

I tried this and the browser gives me a 404 error for the templates path. I double checked and there is definitely a folder templates and an index file. I also tried requesting templates/index.html. And I still get a 404. I don’t see the request on the caddy logs. Anything under the templates subdirectory gives me a 404.

Every other path on the server works fine. Also if I request any other path it does show up on the caddy logs. So “handle_path” is redirecting things perfectly it is just not finding the right directory.

Do you have any idea why it is not finding it?

What did you set root to? The handle_path directive strips the path prefix from the request before handling the request, so if your root is /www-data and the request was /templates/index.html, and you configured handle_path /templates* then it’ll look for /www-data/index.html on disk. You probably want to set root to /www-data/templates I guess.

I just tried setting the root to /www-data/templates. That didn’t work either. For some reason I am not getting this on the logs for the docker container. I only get logs for requests outside of the /templates path. Is there another place I can find the logs?

Turn on the debug global option, and add the log directive to your site. Then look at Caddy’s stdout output for the logs. Run docker-compose logs caddy to see them. Put this at the top of your Caddyfile:

{
	debug
}

wow this is interesting. It seems to be looking in the right place as you suggested. here is the message

{"level":"debug","ts":1655744357.116185,"logger":"http.log.error","msg":"{id=ehqva2kkh} fileserver.(*FileServer).notFound (staticfiles.go:511): HTTP 404","request":{"remote_ip":"192.168.80.1","remote_port":"44130","proto":"HTTP/1.1","method":"GET","host":"wordpresssite.com","uri":"/templates","headers":{"Cache-Control":["max-age=0"],"Upgrade-Insecure-Requests":["1"],"Cookie":[],"Connection":["keep-alive"],"User-Agent":["Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36"],"Accept":["text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"],"Accept-Encoding":["gzip, deflate"],"Accept-Language":["en-US,en;q=0.9"]}},"duration":0.0002768,"status":404,"err_id":"ehqva2kkh","err_trace":"fileserver.(*FileServer).notFound (staticfiles.go:511)"}

Any suggestions on anything else I can try?

Just an update. And thank you Francis for all of your patience. I found the problem. It was not in your instructions or anything wrong with Caddy, everything you told me was correct. The problem was not in the Caddyfile but in the docker-compose.yml file. You can see it here

version: "3.9"

services:
  caddy:
    image: caddy:2.5.1
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./www-data:/var/www
      - ./config:/etc/caddy

I created 2 volumes one to copy the Caddyfile from my repository into the container, and another to copy the web content. While copying the webcontent I did not match the naming convention. So caddy was looking for the file in /www-data when it should have been looking in /var/www as the docker-compose file created that directory and dumped the content there.

Thanks again Francis, for all of your help. Everything works exactly like I wanted it to now.

2 Likes