Subdomains with dns challenge

1. The problem I’m having:

I am trying to have caddy reverse proxy a subdomain and also have it obtain a wildcard certificate via cloudflare dns challenge.

2. Error messages and/or full log output:

{"level":"info","ts":1741501215.5021446,"msg":"using config from file","file":"/etc/caddy/Caddyfile"}
{"level":"info","ts":1741501215.5060084,"msg":"adapted config to JSON","adapter":"caddyfile"}
{"level":"warn","ts":1741501215.5060494,"msg":"Caddyfile input is not formatted; run 'caddy fmt --overwrite' to fix inconsistencies","adapter":"caddyfile","file":"/etc/caddy/Caddyfile","line":2}
{"level":"info","ts":1741501215.507402,"logger":"http.auto_https","msg":"server is listening only on the HTTPS port but has no TLS connection policies; adding one to enable TLS","server_name":"srv0","https_port":443}
{"level":"info","ts":1741501215.5074694,"logger":"http.auto_https","msg":"enabling automatic HTTP->HTTPS redirects","server_name":"srv0"}
{"level":"debug","ts":1741501215.5075252,"logger":"http.auto_https","msg":"adjusted config","tls":{"automation":{"policies":[{"subjects":["pocketbase-testing.aquariuspro.app"]},{}]}},"http":{"servers":{"remaining_auto_https_redirects":{"listen":[":80"],"routes":[{},{}]},"srv0":{"listen":[":443"],"routes":[{"handle":[{"handler":"subroute","routes":[{"handle":[{"handler":"reverse_proxy","upstreams":[{"dial":"127.0.0.1:8002"}]}]}]}],"terminal":true}],"tls_connection_policies":[{}],"automatic_https":{}}}}}
{"level":"info","ts":1741501215.5084465,"logger":"tls.cache.maintenance","msg":"started background certificate maintenance","cache":"0xc0000db000"}
{"level":"info","ts":1741501215.508464,"logger":"tls.cache.maintenance","msg":"stopped background certificate maintenance","cache":"0xc0000db000"}

3. Caddy version:

2.9.0

4. How I installed and ran Caddy:

I built it using xcaddy to get the cloudflare dns module

a. System environment:

Gentoo x64

b. Command:

/etc/init.d/caddy start

c. Service/unit/compose file:

#!/sbin/openrc-run
# Copyright 1999-2023 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2

extra_commands="checkconfig"
extra_started_commands="reload"

description="Caddy web server"
pidfile=${pidfile:-"/run/${RC_SVCNAME}.pid"}
command="/usr/bin/caddy"
command_user="${command_user:-"http:http"}"
caddy_config="${caddy_config:-"/etc/caddy/Caddyfile"}"
command_args="${command_args:-"run --config ${caddy_config}"}"
command_background="true"
logfile="${logfile:-"/var/log/${RC_SVCNAME}/${RC_SVCNAME}.log"}"
start_stop_daemon_args="--user ${command_user%:*} --group ${command_user#*:}
	--stdout ${logfile} --stderr ${logfile}"

: "${supervisor:=supervise-daemon}"
: "${respawn_delay:=5}"
: "${respawn_max:=10}"
: "${respawn_period:=60}"

depend() {
	need net
}

checkconfig() {
    if [ ! -f "${caddy_config}" ] ; then
        ewarn "${caddy_config} does not exist."
        return 1
    fi
    "${command}" validate --config "${caddy_config}" >> "${logfile}" 2>&1
}

start() {
    checkconfig || { eerror "Invalid configuration file !" && return 1; }
	checkpath --directory --mode 755 --owner root "${pidfile%/*}"
	checkpath --directory --mode 755 --owner "${command_user}" "${logfile%/*}"
	default_start
}

reload() {
    if ! service_started "${SVCNAME}" ; then
        eerror "${SVCNAME} isn't running"
        return 1
    fi
    checkconfig || { eerror "Invalid configuration file !" && return 1; }

    ebegin "Reloading ${SVCNAME}"
    "${command}" reload --force --config "${caddy_config}" > /dev/null 2>&1
    eend $?
}

d. My complete Caddy config:

pocketbase-testing.aquariuspro.app {
        tls {
                dns cloudflare {env.CLOUDFLARE_API_TOKEN}
        }

        reverse_proxy 127.0.0.1:8002
}
CLOUDFLARE_API_TOKEN is defined in /etc/conf.d/caddy

For some bizarre reason, when the startup script runs caddy, it runs it as user http and that prevents it from working. From the script, it must run as root.
Second, it appears that the startup config file, /etc/conf.d/caddy is ignored. I had to put the api token in the general config file.

Now I am using my own caddy binary as the gentoo one doesn’t have the added cloudlfare functionality, but I don’t see anything special about my binary that would prevent it from running as user http from inside the script.

The reason for this is the following line in your script:


command_user="${command_user:-"http:http"}"

This means that if you don’t have an environment variable command_user defined, the script defaults to http:http.

You can either define a system variable:


command_user="root:root"

or hardcode that value in your startup script.

Also, keep in mind that only root can bind to ports below 1024.

1 Like

This is there by design. Gentoo intends to run caddy as user http, but when it runs as this user from the script, it fails. It appears to run OK from the command line when run as user http, so this strikes me as bizarre.