1. The problem I’m having:
Hi, I have a work flow where i use an external (not Caddy) tool to manage and renew certificates. New certificates are copy into /etc/caddy/certs and then a rc-service caddy reload
is issued.
The issue is that Caddy continues to use the expired certificate and does not reload it from disk. I have to do a full Caddy restart for the certificates to be reloaded.
2. Error messages and/or full log output:
Output from caddy reload
❯ rc-service caddy reload
* Reloading Caddy web server ...
2024/10/08 04:53:10.810 INFO using config from file {"file": "/etc/caddy/Caddyfile"}
2024/10/08 04:53:10.814 INFO adapted config to JSON {"adapter": "caddyfile"}
2024/10/08 04:53:10.814 WARN Caddyfile input is not formatted; run 'caddy fmt --overwrite' to fix inconsistencies {"adapter": "caddyfile", "file": "/etc/caddy/Caddyfile", "line": 45}
[ ok ]
Caddy log from reloading
{"level":"info","ts":1728363190.8160791,"msg":"config is unchanged"}
{"level":"info","ts":1728363190.816102,"logger":"admin.api","msg":"load complete"}
Caddy log from restarting
{"level":"info","ts":1728363190.8160791,"msg":"config is unchanged"}
{"level":"info","ts":1728363190.816102,"logger":"admin.api","msg":"load complete"}
{"level":"info","ts":1728363595.9644585,"logger":"tls.cache.maintenance","msg":"started background certificate maintenance","cache":"0x40001d9580"}
{"level":"info","ts":1728363596.3831325,"logger":"http.auto_https","msg":"automatic HTTPS is completely disabled for server","server_name":"srv0"}
{"level":"info","ts":1728363596.3831723,"logger":"http.auto_https","msg":"automatic HTTPS is completely disabled for server","server_name":"srv1"}
{"level":"info","ts":1728363596.3842432,"logger":"tls.cache.maintenance","msg":"stopped background certificate maintenance","cache":"0x40001d9580"}
{"level":"info","ts":1728363596.393009,"msg":"shutting down apps, then terminating","signal":"SIGTERM"}
{"level":"warn","ts":1728363596.3930478,"msg":"exiting; byeee!! 👋","signal":"SIGTERM"}
{"level":"info","ts":1728363596.3930943,"logger":"http","msg":"servers shutting down with eternal grace period"}
{"level":"info","ts":1728363596.933898,"logger":"admin","msg":"stopped previous server","address":"localhost:2019"}
{"level":"info","ts":1728363596.9339466,"msg":"shutdown complete","signal":"SIGTERM","exit_code":0}
{"level":"info","ts":1728363597.1825402,"logger":"admin","msg":"admin endpoint started","address":"localhost:2019","enforce_origin":false,"origins":["//localhost:2019","//[::1]:2019","//127.0.0.1:2019"]}
{"level":"info","ts":1728363597.1829596,"logger":"tls.cache.maintenance","msg":"started background certificate maintenance","cache":"0x40005f6a80"}
{"level":"info","ts":1728363597.1885035,"logger":"http.auto_https","msg":"automatic HTTPS is completely disabled for server","server_name":"srv0"}
{"level":"info","ts":1728363597.1885386,"logger":"http.auto_https","msg":"automatic HTTPS is completely disabled for server","server_name":"srv1"}
{"level":"info","ts":1728363597.189887,"logger":"http.log","msg":"server running","name":"srv1","protocols":["h1","h2","h2c","h3"]}
{"level":"info","ts":1728363597.1899655,"logger":"http","msg":"enabling HTTP/3 listener","addr":":443"}
{"level":"info","ts":1728363597.1901524,"logger":"http.log","msg":"server running","name":"srv0","protocols":["h1","h2","h2c","h3"]}
{"level":"info","ts":1728363597.1905732,"msg":"autosaved config (load with --resume flag)","file":"/var/lib/caddy/.config/caddy/autosave.json"}
{"level":"info","ts":1728363597.1906176,"msg":"serving initial configuration"}
{"level":"info","ts":1728363597.1922827,"logger":"tls","msg":"storage cleaning happened too recently; skipping for now","storage":"FileStorage:/var/lib/caddy/.local/share/caddy","instance":"e94aeb00-7bee-4fc3-b387-93f6196ddb35","try_again":1728449997.1922803,"try_again_in":86399.99999956}
{"level":"info","ts":1728363597.1924562,"logger":"tls","msg":"finished cleaning storage units"}
3. Caddy version:
v2.8.4 => /opt/caddy/src/git/caddy@(devel)
4. How I installed and ran Caddy:
Install using xcaddy
#!/bin/sh
export XCADDY_GO_BUILD_FLAGS="-ldflags '-w -s'"
export GOARCH="arm64"
export CGO_ENABLED=1
export CGO_CFLAGS="-g -flto -ffat-lto-objects -fPIC"
export CGO_LDFLAGS="-pie"
export GOFLAGS="-buildmode=pie"
extras="--with github.com/caddyserver/caddy/v2=/opt/caddy/src/git/caddy \
--with github.com/caddyserver/transform-encoder \
--with github.com/dunglas/caddy-cbrotli \
--with github.com/WeidiDeng/caddy-cloudflare-ip \
--with github.com/darkweak/souin/plugins/caddy@master \
--with github.com/darkweak/souin@master \
--with github.com/darkweak/storages/go-redis/caddy \
--with github.com/fvbommel/caddy-combine-ip-ranges \
"
/root/go/bin/xcaddy build ${extras}
a. System environment:
Alpine Linux aarch64
b. Command:
rc-service caddy reload
c. Service/unit/compose file:
#!/sbin/openrc-run
supervisor=supervise-daemon
name="Caddy web server"
description="Fast, multi-platform web server with automatic HTTPS"
description_checkconfig="Check configuration"
description_reload="Reload configuration without downtime"
: ${caddy_opts:="--config /etc/caddy/Caddyfile --adapter caddyfile"}
command=/usr/sbin/caddy
command_args="run $caddy_opts"
command_user=caddy:caddy
extra_commands="checkconfig"
extra_started_commands="reload"
capabilities="^cap_net_bind_service"
depend() {
need net localmount netmount
after firewall
}
checkconfig() {
ebegin "Checking configuration for $name"
su ${command_user%:*} -s /bin/sh -c "$command validate $caddy_opts"
eend $?
}
reload() {
ebegin "Reloading $name"
su ${command_user%:*} -s /bin/sh -c "$command reload $caddy_opts"
eend $?
}
stop_pre() {
if [ "$RC_CMD" = restart ]; then
checkconfig || return $?
fi
}
d. My complete Caddy config:
{
# debug
auto_https off
log {
output file /var/log/caddy/caddy_main.log {
roll_disabled
}
format json
}
servers {
metrics
trusted_proxies cloudflare
protocols h1 h2 h2c h3
}
cache {
redis {
configuration {
InitAddress 127.0.0.1:1212
#InitAddress unix://run/redis/redis-caddy.sock
SelectDB 3
Username caddy
Password RedisPass4499
ConnWriteTimeout 5s
#default_cache_control public
}
}
}
}
ip.tnonline.net:443 {
tls /etc/caddy/certs/ip.tnonline.net_cert.pem /etc/caddy/certs/ip.tnonline.net_privkey.pem
log {
output file /var/log/caddy/ip.tnonline.net.log {
roll_disabled
}
format json
}
header Content-Type "text/plain; charset=utf-8"
header Cache-Control "max-age=0, no-store, no-cache, must-revalidate, proxy-revalidate"
@ok path /
respond @ok 200 {
body {client_ip}
close
}
respond 400 {
body "Forbidden!"
close
}