Hello,
I do not know whether it is possible at the moment; at least I was not able to find the following functionality:
When generating an SSL cert using certbot via the command line, it is possible to complete the DNS-01 challenge with Cloudflare like so:
certbot certonly --dns-cloudflare --dns-cloudflare-credentials API-Key -d example.com,*.example.com
Is it possible to do that automatically in Virtualmin instead of the HTTP-01 challenge?
Thanks a lot,
fred
Hi, Fred!
There is no direct support in Virtualmin for Cloudflare, so far. I was thinking of a work arounds and here is what I got for you.
- Create custom
certbot-cf.sh
(chmod +x) script under/usr/local/bin
(should be on the PATH and usually is) - Add this script to Webmin module configuration:
- Add to the custom script file:
certbot --dns-cloudflare --dns-cloudflare-credentials API-Key
Tell us if it works. In case it doesnât, please provide the exact command that works for you to get LE SSL certificate, while using Cloudflare, and I talk to Jamie about enrolling it.
It seems very easy to do.
Hi, Ilia!
Thank you for your reply, I too think it should be easy to integrate Cloudflare DNS (at least into LE SSL validation).
I now get this error:
The exact command that works for me is:
certbot certonly --dns-cloudflare --dns-cloudflare-credentials PATH_TO_FILE_CONTAINING_CREDENTIALS -d *.domain.tld
The referenced file contains the following information:
Cloudflare API credentials used by Certbot
dns_cloudflare_email = cloudflare@example.com
dns_cloudflare_api_key = 0123456789abcdef0123456789abcdef01234567
I got the info from here: Welcome to certbot-dns-cloudflareâs documentation! â certbot-dns-cloudflare 0 documentation
Best, fred
This is what I get using the proposed work-around when not requesting a wildcard cert:
This is the log file:
2020-01-04 14:55:50,081:DEBUG:certbot.main:certbot version: 0.27.0
2020-01-04 14:55:50,082:DEBUG:certbot.main:Arguments: [ââdns-cloudflareâ, ââdns-cloudflare-credentialsâ, âPATH_TO_CREDENTIALS_FILEâ]
2020-01-04 14:55:50,082:DEBUG:certbot.main:Discovered plugins: PluginsRegistry(PluginEntryPoint#dns-cloudflare,PluginEntryPoint#manual,PluginEntryPoint#null,PluginEntryPoint#standalone,PluginEntryPoint#webroot)
2020-01-04 14:55:50,090:DEBUG:certbot.log:Root logging level set at 20
2020-01-04 14:55:50,091:INFO:certbot.log:Saving debug log to /var/log/letsencrypt/letsencrypt.log
2020-01-04 14:55:50,092:DEBUG:certbot.plugins.selection:Requested authenticator dns-cloudflare and installer None
2020-01-04 14:55:50,092:DEBUG:certbot.plugins.selection:Single candidate plugin: * dns-cloudflare
Description: Obtain certificates using a DNS TXT record (if you are using Cloudflare for DNS).
Interfaces: IAuthenticator, IPlugin
Entry point: dns-cloudflare = certbot_dns_cloudflare.dns_cloudflare:Authenticator
Initialized: <certbot_dns_cloudflare.dns_cloudflare.Authenticator object at 0x7f314f751be0>
Prep: True
2020-01-04 14:55:50,093:DEBUG:certbot.plugins.selection:Selected authenticator <certbot_dns_cloudflare.dns_cloudflare.Authenticator object at 0x7f314f751be0> and installer None
2020-01-04 14:55:50,093:INFO:certbot.plugins.selection:Plugins selected: Authenticator dns-cloudflare, Installer None
2020-01-04 14:55:50,115:DEBUG:certbot.main:Picked account: <Account(RegistrationResource(body=Registration(key=None, contact=(), agreement=None, status=None, terms_of_service_agreed=None, only_return_existing=None, external_account_binding=None), uri=âhttps://acme-v02.api.letsencrypt.org/acme/acct/75087857â, new_authzr_uri=None, terms_of_service=None), 2615a565d5a2d4e815382320219b15cf, Meta(creation_dt=datetime.datetime(2020, 1, 3, 18, 22, 25, tzinfo=), creation_host=âexample.domain.tldâ))>
2020-01-04 14:55:50,116:DEBUG:acme.client:Sending GET request to https://acme-v02.api.letsencrypt.org/directory.
2020-01-04 14:55:50,118:DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): acme-v02.api.letsencrypt.org
2020-01-04 14:55:50,646:DEBUG:urllib3.connectionpool:https://acme-v02.api.letsencrypt.org:443 âGET /directory HTTP/1.1â 200 658
2020-01-04 14:55:50,647:DEBUG:acme.client:Received response:
HTTP 200
Server: nginx
Date: Sat, 04 Jan 2020 13:55:50 GMT
Content-Type: application/json
Content-Length: 658
Connection: keep-alive
Cache-Control: public, max-age=0, no-cache
X-Frame-Options: DENY
Strict-Transport-Security: max-age=604800{
âeXkOJGoCPEgâ: âAdding random entries to the directory - API Announcements - Let's Encrypt Community Supportâ,
âkeyChangeâ: âhttps://acme-v02.api.letsencrypt.org/acme/key-changeâ,
âmetaâ: {
âcaaIdentitiesâ: [
âletsencrypt.orgâ
],
âtermsOfServiceâ: âhttps://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdfâ,
âwebsiteâ: âhttps://letsencrypt.orgâ
},
ânewAccountâ: âhttps://acme-v02.api.letsencrypt.org/acme/new-acctâ,
ânewNonceâ: âhttps://acme-v02.api.letsencrypt.org/acme/new-nonceâ,
ânewOrderâ: âhttps://acme-v02.api.letsencrypt.org/acme/new-orderâ,
ârevokeCertâ: âhttps://acme-v02.api.letsencrypt.org/acme/revoke-certâ
}
2020-01-04 14:55:50,648:DEBUG:certbot.display.ops:No installer, picking names manually
2020-01-04 14:55:50,655:INFO:certbot.main:Obtaining a new certificate
2020-01-04 14:55:50,730:DEBUG:certbot.crypto_util:Generating key (2048 bits): /etc/letsencrypt/keys/0007_key-certbot.pem
2020-01-04 14:55:50,732:DEBUG:certbot.crypto_util:Creating CSR: /etc/letsencrypt/csr/0007_csr-certbot.pem
2020-01-04 14:55:50,733:DEBUG:acme.client:Requesting fresh nonce
2020-01-04 14:55:50,733:DEBUG:acme.client:Sending HEAD request to https://acme-v02.api.letsencrypt.org/acme/new-nonce.
2020-01-04 14:55:50,864:DEBUG:urllib3.connectionpool:https://acme-v02.api.letsencrypt.org:443 âHEAD /acme/new-nonce HTTP/1.1â 200 0
2020-01-04 14:55:50,866:DEBUG:acme.client:Received response:
HTTP 200
Server: nginx
Date: Sat, 04 Jan 2020 13:55:50 GMT
Connection: keep-alive
Cache-Control: public, max-age=0, no-cache
Link: https://acme-v02.api.letsencrypt.org/directory;rel=âindexâ
Replay-Nonce: 0102ygXcEclVLBxECyFrhVp61hSj2xbRx3sqGgAKY4hc1is
X-Frame-Options: DENY
Strict-Transport-Security: max-age=6048002020-01-04 14:55:50,866:DEBUG:acme.client:Storing nonce: 0102ygXcEclVLBxECyFrhVp61hSj2xbRx3sqGgAKY4hc1is
2020-01-04 14:55:50,866:DEBUG:acme.client:JWS payload:
bâ{\n âidentifiersâ: [\n {\n âtypeâ: âdnsâ,\n âvalueâ: âaâ\n }\n ]\n}â
2020-01-04 14:55:50,871:DEBUG:acme.client:Sending POST request to https://acme-v02.api.letsencrypt.org/acme/new-order:
{
âprotectedâ: âeyJhbGciOiAiUlMyNTYiLCAia2lkIjogImh0dHBzOi8vYWNtZS12MDIuYXBpLmxldHNlbmNyeXB0Lm9yZy9hY21lL2FjY3QvNzUwODc4NTciLCAibm9uY2UiOiAiMDEwMnlnWGNFY2xWTEJ4RUN5RnJoVnA2MWhTajJ4YlJ4M3NxR2dBS1k0aGMxaXMiLCAidXJsIjogImh0dHBzOi8vYWNtZS12MDIuYXBpLmxldHNlbmNyeXB0Lm9yZy9hY21lL25ldy1vcmRlciJ9â,
âsignatureâ: âLrOCC2pBJKfgGi_1iibPP7OPyo9hzyA_nux5m5oFds2oeVALLo7gQ5g7QSMwHSkdBy12fzsi5JOBgIC7Me0ElNP0pFBAqC5HU839EFpJGIXT7ChWUCkLmsCY7TNcm8YOMMTp6xH6BrNo33RX47MY4qI7_NtQLkJt5sjhshORrTNgavhb6oTvwPwmYwz6X701Wywszp20GslSI32gDHeLbWOwUgDvn8r8fCvNnvhuAZrehIXrgkGx_Inf8u3e6F3P-EGv4dViZ5gdb2JJfku3vulcezKpiWMRRlHQjjCbsTsNe6vZz7yqFUTChGUOefmyRS0Zx5lq8zuk3yNJKQVafAâ,
âpayloadâ: âewogICJpZGVudGlmaWVycyI6IFsKICAgIHsKICAgICAgInR5cGUiOiAiZG5zIiwKICAgICAgInZhbHVlIjogImEiCiAgICB9CiAgXQp9â
}
2020-01-04 14:55:51,017:DEBUG:urllib3.connectionpool:https://acme-v02.api.letsencrypt.org:443 âPOST /acme/new-order HTTP/1.1â 400 180
2020-01-04 14:55:51,017:DEBUG:acme.client:Received response:
HTTP 400
Server: nginx
Date: Sat, 04 Jan 2020 13:55:50 GMT
Content-Type: application/problem+json
Content-Length: 180
Connection: keep-alive
Boulder-Requester: 75087857
Cache-Control: public, max-age=0, no-cache
Link: https://acme-v02.api.letsencrypt.org/directory;rel=âindexâ
Replay-Nonce: 01025v91jD9NiQBHp3SBHD98aoV3Mdhp4Wgs3zanYgdwtvE{
âtypeâ: âurn:ietf:params:acme:error:rejectedIdentifierâ,
âdetailâ: âError creating new order :: Cannot issue for "a": Domain name needs at least one dotâ,
âstatusâ: 400
}
2020-01-04 14:55:51,018:DEBUG:certbot.log:Exiting abnormally:
Traceback (most recent call last):
File â/usr/bin/certbotâ, line 11, in
load_entry_point(âcertbot==0.27.0â, âconsole_scriptsâ, âcertbotâ)()
File â/usr/lib/python3/dist-packages/certbot/main.pyâ, line 1364, in main
return config.func(config, plugins)
File â/usr/lib/python3/dist-packages/certbot/main.pyâ, line 1254, in certonly
lineage = _get_and_save_cert(le_client, config, domains, certname, lineage)
File â/usr/lib/python3/dist-packages/certbot/main.pyâ, line 120, in _get_and_save_cert
lineage = le_client.obtain_and_enroll_certificate(domains, certname)
File â/usr/lib/python3/dist-packages/certbot/client.pyâ, line 391, in obtain_and_enroll_certificate
cert, chain, key, _ = self.obtain_certificate(domains)
File â/usr/lib/python3/dist-packages/certbot/client.pyâ, line 334, in obtain_certificate
orderr = self._get_order_and_authorizations(csr.data, self.config.allow_subset_of_names)
File â/usr/lib/python3/dist-packages/certbot/client.pyâ, line 366, in _get_order_and_authorizations
orderr = self.acme.new_order(csr_pem)
File â/usr/lib/python3/dist-packages/acme/client.pyâ, line 889, in new_order
return self.client.new_order(csr_pem)
File â/usr/lib/python3/dist-packages/acme/client.pyâ, line 672, in new_order
response = self._post(self.directory[ânewOrderâ], order)
File â/usr/lib/python3/dist-packages/acme/client.pyâ, line 96, in _post
return self.net.post(*args, **kwargs)
File â/usr/lib/python3/dist-packages/acme/client.pyâ, line 1204, in post
return self._post_once(*args, **kwargs)
File â/usr/lib/python3/dist-packages/acme/client.pyâ, line 1218, in _post_once
response = self._check_response(response, content_type=content_type)
File â/usr/lib/python3/dist-packages/acme/client.pyâ, line 1073, in _check_response
raise messages.Error.from_json(jobj)
acme.messages.Error: urn:ietf:params:acme:error:rejectedIdentifier :: Error creating new order :: Cannot issue for âaâ: Domain name needs at least one dot
2020-01-04 14:55:51,019:ERROR:certbot.log:An unexpected error occurred:
2020-01-04 14:55:51,019:ERROR:certbot.log:Error creating new order :: Cannot issue for âaâ: Domain name needs at least one dot
What do you set on the previous page? Can you share the screenshot?
Regardless of what I set, the outcome is always as above.
Oh, wait, you are not adding $@
to the end of the script line, to pass the other arguments from Webmin core?
certbot --dns-cloudflare --dns-cloudflare-credentials API-Key $@
I now traced down the problem why it is not working. It is now simply passing too many arguments to certbot (mainly the concomittant use of ââdns-cloudflareâ and â- a webrootâ). Any idea how to fix that?
ââagree-tosâ, ââdns-cloudflareâ, ââdns-cloudflare-credentialsâ, âSOME_PATHâ, ââregister-unsafely-without-emailâ, â-aâ, âwebrootâ, â-dâ, âexample.tldâ, â-dâ, âwww.example.tldâ, â-dâ, âmail.example.tldâ, ââwebroot-pathâ, â/home/example/public_htmlâ, ââduplicateâ, ââforce-renewalâ, ââmanual-public-ip-logging-okâ, ââconfigâ, â/tmp/.webmin/SOMENUMBERS_letsencrypt.cgiâ, âârsa-key-sizeâ, â2048â, ââcert-nameâ, âexample.tldâ]
Yep. It was expected. I just wanted you to give it a try.
Okay, I will talk once more with Jamie, will see when we could added it.
Wait. Can you try DNS validation on Webmin Configuration/SSL certificate page?
Thank you for your awesome work!
When you requested certificate with your command in console, you didnât do any manual modifications to DNS records on CloudFlare, as everything is done by cerbot
command, right?
Can you provide successful output of such command (when run in console)?
Of course!
user@servername:~$ sudo certbot certonly --dns-cloudflare --dns-cloudflare-credentials PATH_TO_CREDENTIALS -m someone@example.tld -d *.example.tld
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator dns-cloudflare, Installer None
Obtaining a new certificate
Performing the following challenges:
dns-01 challenge for example.tldWaiting 10 seconds for DNS changes to propagate
Waiting for verificationâŠ
Cleaning up challenges
IMPORTANT NOTES:
-
Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/example.tld-0001/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/example.tld-0001/privkey.pem
Your cert will expire on 2020-04-07. To obtain a new or tweaked
version of this certificate in the future, simply run certbot
again. To non-interactively renew all of your certificates, run
âcertbot renewâ -
If you like Certbot, please consider supporting our work by:
Donating to ISRG / Letâs Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le
We will most likely factor out Letâs Encrypt into a separate module, away from Webmin Configuration to make more sense, and then we will add more features into it.
For now, you could easily use custom built scripts, to make things work for you automatically.
@Jamie Do you think we could do it a bit sooner?
Separate module sounds great!