1. The problem I’m having:
Please consider the CaddyTaylor Project (Github). It aims to use Caddy templates in a way that split contents and, well, templates, so you can have your contents on one hand and your themes on the other. CaddyTaylor comes as a docker development environment so you may run it on your side to test.
In this configuration, Caddy serves two directories:
-
subdomains
that stores contents for each subdomains of localhost (currently, sample.localhost, sampleonepage.localhost and sampleonepage2d.localhost, one demo site for each theme I’m working on) -
themes
that stores the themes.
At the same level, you have the index.html
file which is a Caddy template that makes the routing work to inject the contents in the templates. And, yes, it works nearly well.
So the expected behavior is:
- when a file, not a page, is requested, given its full path, it is served:
https://sample.localhost/subdomains/sample/img/caddy-logo.svg
for example — this works ; - when a page is requested, it is handled by the template system: https://sampleonepage.localhost is a working example — there is still problems in some cases and
https://sample.localhost
does not work it the current state of the code, but that’s not the point here ; - when a file, not a page, is requested with out the path to content directory of the subdomain, it SHOULD be provided, so
https://sample.localhost/subdomains/sample/img/caddy-logo.svg
SHOULD be equivalent to https://sample.localhost/img/caddy-logo.svg — but it IS NOT and it DOES NOT work at all, which is my problem.
This behavior is handled by the line 12 of the Caddyfile:
try_files /subdomains/{http.request.host.labels.2}/{path} {path} index.html
If you comment it and uncomment the line 13 which becomes:
try_files /subdomains/sample/{path} {path} index.html
It works, but only for the sample.localhost domain.
So, what’s going wrong ? Considering the error log (see below, point 2), the request IS handled but the template system, but it SHOULD NOT.
How to test:
$ git clone git@github.com:taophp/caddy-tailor.git
$ cd caddy-taylor
$ docker-compose up -d
$ curl -vLk https://sample.localhost/img/caddy-logo.svg
* Trying ::1:443...
* Connected to sample.localhost (::1) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* TLSv1.0 (OUT), TLS header, Certificate Status (22):
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS header, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS header, Finished (20):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.2 (OUT), TLS header, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
* ALPN, server accepted to use h2
* Server certificate:
* subject: [NONE]
* start date: Apr 14 13:38:15 2023 GMT
* expire date: Apr 15 01:38:15 2023 GMT
* issuer: CN=Caddy Local Authority - ECC Intermediate
* SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
* Using HTTP2, server supports multiplexing
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* Using Stream ID: 1 (easy handle 0x556d4bc1e020)
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
> GET /img/caddy-logo.svg HTTP/2
> Host: sample.localhost
> user-agent: curl/7.81.0
> accept: */*
>
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* Connection state changed (MAX_CONCURRENT_STREAMS == 250)!
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* HTTP/2 stream 0 was not closed cleanly: PROTOCOL_ERROR (err 1)
* stopped the pause stream!
* Connection #0 to host sample.localhost left intact
curl: (92) HTTP/2 stream 0 was not closed cleanly: PROTOCOL_ERROR (err 1)
2. Error messages and/or full log output:
$ docker logs caddytailor_caddy_1 # I prettyfied the last output to make it readable... or nearly!
{
"level": "error",
"ts": 1681484819.6419573,
"logger": "http.log.error",
"msg": "template: /index.html:36:12: executing \"/index.html\" at <include $pageTemplate $config>:
error calling include: template: themes/base//index.html:2:6: executing \"themes/base//index.html\" at <include (printf \"/themes/%s/head.html\" $config.theme) $config>:
error calling include: template: /themes/base/head.html:9:17: executing \"/themes/base/head.html\" at <include (printf \"/themes/%s/menu.html\" $config.theme) $config $config.rootdir \"\">:
error calling include: template: /themes/base/menu.html:19:12: executing \"/themes/base/menu.html\" at <include (printf \"/themes/%s/menu.html\" $config.theme) $config (printf \"%s/%s\" $dir $entry) (printf \"%s/%s\" $urldir $entry)>:
error calling include: template: /themes/base/menu.html:19:12: executing \"/themes/base/menu.html\" at <include (printf \"/themes/%s/menu.html\" $config.theme) $config (printf \"%s/%s\" $dir $entry) (printf \"%s/%s\" $urldir $entry)>:
error calling include: template: /themes/base/menu.html:5:17: executing \"/themes/base/menu.html\" at <listFiles $dir>:
error calling listFiles: subdomains/sample/img/caddy-logo.svg is not a directory",
"request": {
"remote_ip": "172.18.0.1",
"remote_port": "49708",
"proto": "HTTP/2.0",
"method": "GET",
"host": "sample.localhost",
"uri": "/img/caddy-logo.svg",
"headers": {
"User-Agent": [
"curl/7.81.0"
],
"Accept": [
"*/*"
]
},
"tls": {
"resumed": false,
"version": 772,
"cipher_suite": 4865,
"proto": "h2",
"server_name": "sample.localhost"
}
},
"duration": 0.004958801,
"status": 500,
"err_id": "7kk2u58ji",
"err_trace": "templates.(*Templates).executeTemplate (templates.go:402)"
}
3. Caddy version:
$ docker exec caddytailor_caddy_1 caddy version
v2.6.4 h1:2hwYqiRwk1tf3VruhMpLcYTg+11fCdr8S3jhNAdnPy8=
4. How I installed and ran Caddy:
a. System environment:
$ docker -v
Docker version 20.10.21, build 20.10.21-0ubuntu1~22.04.2
$ docker-compose -v
docker-compose version 1.29.2, build unknown
$ uname -a
Linux pc-steph 5.15.0-69-generic #76-Ubuntu SMP Fri Mar 17 17:19:29 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
b. Command:
docker-compose up
c. Docker-compose file:
version: "3.7"
services:
caddy:
image: caddy:latest
ports:
- "443:443"
volumes:
- $PWD/Caddyfile:/etc/caddy/Caddyfile
- $PWD/sites:/usr/share/caddy
- $PWD/caddy_data:/data
- $PWD/caddy_config:/config
d. My complete Caddy config:
# To reload use this command : ` docker exec caddytailor_caddy_1 caddy reload --config /etc/caddy/Caddyfile `
{
debug
}
*.localhost {
root * /usr/share/caddy
tls internal
file_server
templates
route {
try_files /subdomains/{http.request.host.labels.2}/{path} {path} index.html
#try_files /subdomains/sample/{path} {path} index.html
}
}
5. Links to relevant resources:
CaddyTaylor repository: https://github.com/taophp/caddy-tailor