jbjonesjr/letsencrypt-manual-hook

allow bulk entry instead of (or as alternativ to) one by one

qnxor opened this issue · 10 comments

qnxor commented

I've been using your manual hook and it's been useful, so many thanks for it!

One improvement would be to allow multiple domains/subdomains to be treated in bulk rather than one by one. I have 10 subdomains and with your hook I have to enter them one by one and also wait for each of them one by one, which gets a little cumbersome. Why not display all the TXT records for all (sub)domains, ask the user to enter them in DNS, then poll and check all of them in one go?

This is what the https://sslforfree.com GUI is doing, which I've been using until now, but your hook would be preferable as it provides a little more automation.

EDIT: Unless the dehydrated script is the one imposing the sequential treatment...

@qnxor

Unfortunately, as far as I know it is the dehydrated client. Each challenge phrase the client/protocol generates is unique per request, and it blocks until the challenge is verified (or the client connection is broken). To support an asynchronous process, this would have to be resolved.

Now, maybe dehydrated has an async option that I'm not aware of. I'd be happy to include support if you can find me upstream support.

qnxor commented

Indeed. I did have a look myself too and noticed that dehydrated treats (sub)domains sequentailly.

The official certbot client does not. I ended up using that instead as it was quicker for me with 10 subdomains at once. I just made sure to wait 2 minutes before pressing the 10th Enter, to allow for DNS record to propagate. Other than that, it worked just fine:

./certbot-auto certonly --manual --preferred-challenges dns -d domain.tld -d host1.domain.tld [-d ...]

If you have more time than I do then I think for the manual dns challenge case it's worth wrapping certbot more than dehydrated (all that's needed is the loop check for dns txt, even though that's bound to be innacurate unless you use the same NS to do the dns queries as the letsecrypt service does)

Also check out https://www.sslforfree.com/ which is a web gui for certbot and supports DNS challenge too. It has a very nice intermediary step where it gives web links for each dns txt record which you can click to check if it propagated before issuing the certs. Neat.

@jbjonesjr

Thank you very much, I'm also using your manual hook and its realy helpful.

I wonder if it would be possible to support bulk entry by using the HOOK_CHAIN config param from dehydrated. It is described at the following page: https://github.com/lukas2511/dehydrated/blob/master/docs/hook_chain.md

@pc-fan that looks promising. I welcome Pull Requests :) Thanks for brining it to my attention.

Otherwise, i'll see if I can find some time to explore this over the next few weeks.

Ooh, I'd love this, but I don't speak Ruby and it's a significant change.

@rudiedirkx I already use this feature with the code from #15. You can find it in this branch: https://github.com/pc-fan/letsencrypt-manual-hook/tree/hook_chain

Let me know if you need assistance using it.

I'm getting this:

Checking for TXT record for the domain: '_acme-challenge.*.wc18.example.com'.
./dns-hook-manual-chain.rb:20:in `resolved?': undefined local variable or method `txt_challenge' for main:Object (NameError)
        from ./dns-hook-manual-chain.rb:31:in `block in setup_dns'
        from ./dns-hook-manual-chain.rb:29:in `delete_if'
        from ./dns-hook-manual-chain.rb:29:in `setup_dns'
        from ./dns-hook-manual-chain.rb:71:in `<main>'

I'm testing Dehydrated's ACME v2 implementation, hence _acme-challenge.*.wc18.example.com, but I don't think that's the problem..?

I changed #{challenge[txt_challenge]} to #{challenge[:txt_challenge]}, and removed the else in resolved? (because v2 will have multiple relevant TXT records in 1 domain), and fixed wildcard dns domains (acme_domain = "_acme-challenge.#{domain}".sub(/\.\*\./, ".")), and now it works. Cool!

@rudiedirkx thanks for the additional investigation and notes. That's very helpful. Can I get some more feedback on #15 (comment) specifically? It seems that just dropping the else would not be enough, but the code would also have to iterate over the resp.strings array. Is that the case?

/resolved by #15