How to trigger generating an ssl cert ahead of time (dns challenge)

1. Caddy version (caddy version):

$ caddy version
v2.4.3 h1:Y1FaV2N4WO3rBqxSYA8UZsZTQdN+PwcoOcAiZTM8C0I=

2. How I run Caddy:

systemd provided by apt-get install

a. System environment:

Ubuntu 20.04.2 LTS

b. Command:

sudo systemctl start caddy

c. Service/unit/compose file:

just what is provided by apt-get install...

d. My complete Caddyfile or JSON config:

{
    debug
	on_demand_tls {
		ask http://127.0.0.1:5000/_domain_check
	}
#acme_ca https://acme-staging-v02.api.letsencrypt.org/directory
}

:443 {

    # API RELATED CONFIGS

    # allow password reset
    @api_password_reset {
        header_regexp apihost Host api\.(.*)
        path /password_reset*
    }
    handle @api_password_reset {
        redir https://www.{re.apihost.1}{uri} permanent
    }

    # allow activate
    @api_activate {
        header_regexp apihost Host api\.(.*)
        path /activate*
    }
    handle @api_activate {
        redir https://www.{re.apihost.1}{uri} permanent
    }

    # allow admin
    @api_admin {
        header Host api.*
        path /admin*
    }
    handle @api_admin {
        reverse_proxy 127.0.0.1:5001
    }

    # allow xyz-api-clients
    @api_client {
        header Host api.*
        header User-Agent xyz-api-client
    }
    handle @api_client {
        reverse_proxy 127.0.0.1:5001
    }

    # api static assets
    @api_static {
        header Host api.*
        path /static*
    }
    handle @api_static {
        file_server /static/* {
            root /var/www/cb/api/api/
        }
    }

    # api media assets
    @api_media {
        header Host api.*
        path /media*
    }
    handle @api_static {
        file_server /media/* {
            root /var/www/cb/api/api/
        }
    }

    # send non xyz-api-clients to 403 - must go last!
    @api_the_rest {
        header Host api.*
    }
    handle @api_the_rest {
        header {
            Content-Type "text/html; charset=UTF-8"
        }
        respond "Forbidden 禁止の" 403
    }

    @marketing_app header Host a.xyz.org
    handle @marketing_app {
        reverse_proxy 127.0.0.1:5003
    }

    @www_app header Host xyz.org
    handle @www_app {
        reverse_proxy 127.0.0.1:5002
    }

    # APP RELATED CONFIGS
    @app header Host www.*

    # serve static files
    handle @app {
        file_server /static/* {
            root /var/www/cb/app/
        }
    }

    # proxy to uwsgi server and/or redirect to www
    handle @app {
        reverse_proxy 127.0.0.1:5000
    }

    # send non-www to www
    @needs_www {
        not header Host api.*
    }
    handle @needs_www {
        redir https://www.{host}{uri}
    }


    tls josh.anyan@nope.org {
        on_demand
        dns route53 {
            max_retries 10
            aws_profile "default"
        }
    }

    log {
        output file /tmp/caddy.log {
            roll_size 100MiB
            roll_keep 10
            roll_keep_for 336h
        }
    }
}

3. The problem I’m having:

I’m using DNS-01 challenge for cert gen. Is there a better way to tell caddy to attempt to fetch tls certs than using curl --resolve ? (see full command below)

Ideally there’d be a caddy api I can hit to tell it to simulate receiving a call from a domain.

echo kick_domain.sh
curl -v --resolve "$1":443:11.22.33.44 https://"$1"

used
./kick_domain.sh mydomain.com

That works fine, but it feels a bit brittle to me.

4. Error messages and/or full log output:

none

5. What I already tried:

see above

6. Links to relevant resources:

¯\_(ツ)_/¯ 

I mean, that’s Caddy’s default mode (i.e. not on-demand TLS). On-demand TLS is the opposite of what you are trying to do, it sounds like.

Either you tell Caddy to get a cert for a domain (by putting the domain into the config), or you tell it to get the cert lazily, when first requested (by using on-demand TLS).

I think curl --resolve is pretty much the best way to do it. Ultimately all you’re doing (if I understand your goal) is to just kickstart the TLS issuance, so that the first real user doesn’t get hit by the short delay during the handshake from Caddy triggering issuance they might otherwise get on the first request. You could also just not worry about it and let the first real request trigger the issuance.

As an aside, I’m noticing that many of your matchers all do header Host api.*. You can nest matchers and handle blocks, so you can just have one top-level header_regexp matcher that captures it, then if that matches, do everything else without checking api.* inside a handle. You’ll avoid a lot of extra conditions. Should be slightly faster.

:443 {

	@api header_regexp apihost Host api\.(.*)
	handle @api {
		redir /password_reset* https://www.{re.apihost.1}{uri} permanent
		redir /activate* https://www.{re.apihost.1}{uri} permanent

		reverse_proxy /admin* 127.0.0.1:5001

		@api_client header User-Agent xyz-api-client
		reverse_proxy @api_client 127.0.0.1:5001

		handle /static* {
			root * /var/www/cb/api/api/
			file_server
		}

		...
	}

	...
}
1 Like

thank you to both of you for responding to quickly.

yes, i’m attempting to bootstrap the process so there’s no degradation of service. we have 3 certs to gather before moving a client’s domain over. The $domain, www.$domain, and api.$domain. With how the application works, the first user would trigger a cert on $domain, wait, then get redirected to www.$domain, wait for that cert, then internally the app calls to api.$domain, causing more wait until the final response is generated.

Thanks Francis, I’ll take a look at organizing the Caddyfile from your recommendations.

1 Like

This topic was automatically closed after 30 days. New replies are no longer allowed.