1. Caddy version (caddy version
):
v2.3.0 h1:fnrqJLa3G5vfxcxmOH/+kJOcunPLhSBnjgIvjXV/QTA=
2. How I run Caddy:
From docker-compose using the official images on docker hub
a. System environment:
- Ubuntu 20.04.1 LTS bare metal server.
- Docker version 20.10.1, build 831ebea
- docker-compose version 1.25.0, build unknown
b. Command:
From a docker-compose perspective: docker-compose start caddy
; docker launches caddy as caddy --run --config /etc/caddy/Caddyfile --adapter caddyfile
c. Service/unit/compose file:
docker-compose.yml:
caddy:
container_name: "caddy"
image: caddy:2
restart: unless-stopped
environment:
- TZ=Americas/Toronto
ports:
- target: 80
published: 81
mode: host
- target: 443
published: 444
mode: host
networks:
- caddy
volumes:
- /srv/docker/caddy/Caddyfile:/etc/caddy/Caddyfile
- /srv/docker/caddy/site:/srv
- /srv/docker/caddy/caddy_data:/data
- /srv/docker/caddy/caddy_config:/config
Note: i’m using unusual external ports as (other) production servers uses 80/443. I’m setting up and testing caddy using temporary ports to set up things.
d. My complete Caddyfile or JSON config:
{
debug
}
http://md.bilange.duckdns.org {
handle_errors {
@404 {
expression {http.error.status_code} == 404
}
handle @404 {
rewrite * /html/404.html
file_server
}
}
respond /favicon.ico 404 {
body "404"
close
}
import common
root * /srv/md.bilange.duckdns.org
templates
encode gzip
file_server * browse {
hide .git *.ini *.sh *.swp
}
@markdown {
not path /html/*
path_regexp md /.*\.md$
}
rewrite @markdown /html/template.html
@dir {
not path /html/*
path_regexp dir (.*)/$
}
redir @dir {http.regexp.dir.1}/index.md
}
html/template.html (minimal example):
{{$pathParts := splitList "/" .OriginalReq.URL.Path}}
{{$markdownFilename := default "index" (slice $pathParts 2 | join "/")}}
{{$markdownFilePath := printf "/%s.md" $markdownFilename}}
{{$markdownFile := (include .OriginalReq.URL.Path | splitFrontMatter)}}
{{$title := default $markdownFilename $markdownFile.Meta.title}}
{{$body := $markdownFile.Body}}
{{/*not shown: multiples searches and replaces on $body before outputting, should be irrevelant for this issue at this point */}}
<!DOCTYPE html>
<html>
<head>
<!-- skipped for brevity, if needed I can provide them -->
</head>
<body>
<div class="container">
<div class="file-header">
<span class="header-title">
<span class="octicon octicon-file"></span> {{$markdownFilename}}
</span>
</div>
<div class="markdown-body">
{{markdown $body}}
</div>
</div>
</body>
</html>
3. The problem I’m having:
This config snippet above is 99% working, except in one situation: when attempting to access a markdown file that doesn’t exist on disk, caddy will still pass control to the template file, and the `{{include…}}`` line will fail with this error log (below). So I need a solution to either catch them from the caddyfile or from the template, which I am not sure how to proceed.
4. Error messages and/or full log output:
Client-side:
>> curl -i 'http://md.bilange.duckdns.org:81/notfound.md'
HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-Length: 4892
Content-Type: text/html; charset=utf-8
Etag: "qokwxu3rw"
Last-Modified: Mon, 15 Feb 2021 16:39:30 GMT
Server: Microsoft-IIS/10.0
Date: Mon, 15 Feb 2021 16:43:47 GMT
curl: (18) transfer closed with 4892 bytes remaining to read
Server-side (caddy logs):
{"level":"debug","ts":1613407559.1065104,"logger":"http.handlers.rewrite","msg":"rewrote request","request":{"remote_addr":"66.187.114.18:58508","proto":"HTTP/1.1","method":"GET","host":"md.bilange.duckdns.org:81","uri":"/notfound.md","headers":{"User-Agent":["curl/7.68.0"],"Accept":["*/*"]}},"method":"GET","uri":"/html/template.html"}
{"level":"debug","ts":1613407559.1067774,"logger":"http.handlers.file_server","msg":"sanitized path join","site_root":"/srv/md.bilange.duckdns.org","request_path":"/html/template.html","result":"/srv/md.bilange.duckdns.org/html/template.html"}
{"level":"debug","ts":1613407559.106876,"logger":"http.handlers.file_server","msg":"opening file","filename":"/srv/md.bilange.duckdns.org/html/template.html"}
{"level":"error","ts":1613407559.1133502,"logger":"http.log.error","msg":"template: /html/template.html:16:21: executing \"/html/template.html\" at <include .OriginalReq.URL.Path>: error calling include: open /srv/md.bilange.duckdns.org/notfound.md: no such file or directory","request":{"remote_addr":"66.187.114.18:58508","proto":"HTTP/1.1","method":"GET","host":"md.bilange.duckdns.org:81","uri":"/notfound.md","headers":{"User-Agent":["curl/7.68.0"],"Accept":["*/*"]}},"duration":0.006944929,"status":500,"err_id":"atem08igx","err_trace":"templates.(*Templates).executeTemplate (templates.go:315)"}
5. What I already tried:
On the template side, I havent seen any functions either from caddy or sprig that permits me to check for files existence. Trying to pass {{if (os.Stat($markdownFilename))}}
says that os is undefined (on afterthought, I am not sure opening up golang that much is really secure anyway :-). I think it’s possible from Caddyfile to check for file existence (try_files
?), but using try_files
on an existing file sends the raw markdown to the client, without using the configured template.
6. Links to relevant resources:
- The first lines of the template is actually from this thread. The goal of my project is: I wanted to have a small HTTP server serving markdown files as converted HTML files.
7. Notes
- If you need to try the server mentioned in the config, IIRC I believe it’s firewalled so only a few static IPs can connect. Let me know if you actually need to test it and it doesn’t respond.
- I’ve been starting using Caddy very recently (~a week ago), prior knowledge of Golang is minimal AND rusty to say the least Do not hesitate to kindly point me to the right direction if I missed some piece of documentation I should have read.
Thanks for your assistance!