In order to download the certificate, you need to use the client built into openssl like so:
echo -n | openssl s_client -connect $HOST:$PORTNUMBER -servername $SERVERNAME \
| openssl x509 > /tmp/$SERVERNAME.cert
That will save the certificate to /tmp/$SERVERNAME.cert
.
The -servername
is used to select the correct certificate when multiple are presented, in the case of SNI.
You can use -showcerts
if you want to download all the certificates in the chain. But if you just want to download the server certificate, there is no need to specify -showcerts
. The x509
at the end will strip out the intermediate certs, you will need to use sed -n '/-----BEGIN/,/-----END/p'
instead of the x509 at the end.
echo -n
gives a response to the server, so that the connection is released
openssl x509
removes information about the certificate chain and connection details. This is the preferred format to import the certificate into other keystores.
Currently it is possible to perform DNS validation, also with the certbot LetsEncrypt client in manual mode. Automation is possible as well (see below).
Manual plugin
You can either perform a manual verification - with the manual plugin.
certbot -d bristol3.pki.enigmabridge.com --manual --preferred-challenges dns certonly
Certbot will then provide you instructions to manually update a TXT record for the domain in order to proceed with the validation.
Please deploy a DNS TXT record under the name
_acme-challenge.bristol3.pki.enigmabridge.com with the following value:
667drNmQL3vX6bu8YZlgy0wKNBlCny8yrjF1lSaUndc
Once this is deployed,
Press ENTER to continue
Once you have updated the DNS record, press Enter, certbot will continue and if the LetsEncrypt CA verifies the challenge, the certificate is issued as normally.
You may also use a command with more options to minimize interactivity and answering certbot questions. Note that the manual plugin does not yet support non-interactive mode.
certbot --text --agree-tos --email you@example.com -d bristol3.pki.enigmabridge.com --manual --preferred-challenges dns --expand --renew-by-default --manual-public-ip-logging-ok certonly
Renewal does not work with the manual plugin as it runs in non-interactive mode. More info in the official certbot documentation.
Update: manual hooks
In the new certbot version you can use hooks, e.g., --manual-auth-hook
, --manual-cleanup-hook
. The hooks are external scripts executed by certbot to perform the task.
Information is passed in environment variables - e.g., domain to validate, challenge token. Vars: CERTBOT_DOMAIN
, CERTBOT_VALIDATION
, CERTBOT_TOKEN
.
certbot certonly --manual --preferred-challenges=dns --manual-auth-hook /path/to/dns/authenticator.sh --manual-cleanup-hook /path/to/dns/cleanup.sh -d secure.example.com
You can write your own handler or use already existing ones. There are many available, e.g., for Cloudflare DNS.
More info on official certbot hooks documentation.
Automation, Renewal, Scripting
If you would like to automate DNS challenge validation it is not currently possible with vanilla certbot. Update: some automation is possible with the certbot hooks.
We thus created a simple plugin that supports scripting with DNS automation. It's available as certbot-external-auth.
pip install certbot-external-auth
It supports the DNS, HTTP, TLS-SNI validation methods. You can either use it in handler mode or in JSON output mode.
Handler mode
In handler mode, the certbot + plugin calls external hooks (a program, shell script, Python, ...) to perform the validation and installation. In practice you write a simple handler/shell script which gets the input arguments - domain, token and makes the change in DNS. When the handler finishes, certbot proceeds with validation as usual.
This gives you extra flexibility, renewal is also possible.
Handler mode is also compatible with Dehydrated DNS hooks (former letsencrypt.sh). There are already many DNS hooks for common providers (e.g., CloudFlare, GoDaddy, AWS). In the repository there is a README with extensive examples and example handlers.
Example with Dehydrated DNS hook:
certbot \
--text --agree-tos --email you@example.com \
--expand --renew-by-default \
--configurator certbot-external-auth:out \
--certbot-external-auth:out-public-ip-logging-ok \
-d "bristol3.pki.enigmabridge.com" \
--preferred-challenges dns \
--certbot-external-auth:out-handler ./dehydrated-example.sh \
--certbot-external-auth:out-dehydrated-dns \
run
JSON mode
Another plugin mode is JSON mode. It produces one JSON object per line. This enables a more complicated integration - e.g., when Ansible or some deployment manager is calling certbot. Communication is performed via STDOUT and STDIN. Cerbot produces JSON objects with data to perform the validation, for example:
certbot \
--text --agree-tos --email you@example.com \
--expand --renew-by-default \
--configurator certbot-external-auth:out \
--certbot-external-auth:out-public-ip-logging-ok \
-d "bristol3.pki.enigmabridge.com" \
--preferred-challenges dns \
certonly 2>/dev/null
{"cmd": "perform_challenge", "type": "dns-01", "domain": "bs3.pki.enigmabridge.com", "token": "3gJ87yANDpmuuKVL2ktfQ0_qURQ3mN0IfqgbTU_AGS4", "validation": "ejEDZXYEeYHUxqBAiX4csh8GKkeVX7utK6BBOBshZ1Y", "txt_domain": "_acme-challenge.bs3.pki.enigmabridge.com", "key_auth": "3gJ87yANDpmuuKVL2ktfQ0_qURQ3mN0IfqgbTU_AGS4.tRQM98JsABZRm5-NiotcgD212RAUPPbyeDP30Ob_7-0"}
Once DNS is updated, the caller sends the new-line character to STDIN of certbot to signal it can continue with validation.
This enables automation and certificate management from the central management server. For installation you can deploy certificates over SSH.
For more info please refer to the readme and examples on certbot-external-auth GitHub.
EDIT: There is also a new blog post describing the DNS validation problem and the plugin usage.
EDIT: We currently work on Ansible 2-step validation, will be soon off.
Best Answer
Actually, it's possible, and the solution is following:
Navigate to the new folder and run:
sudo certbot certonly --csr /etc/letsencrypt/csr/crs-filename.pem
This command will generate new, valid letsencrypt certificate inside that folder.
Then you have to create fullchain manually by running:
sudo cat filename-cert.pem filename-chain.pem > filename-fullchain.pem
The last step is pointing to that file inside Nginx config (in my case this is Nginx):
sudo nano /etc/nginx/sites-enabled/domain.com.conf
Throw in following lines:
listen 443 ssl; ssl_certificate /home/username/letsencrypt/filename_fullchain.pem; ssl_certificate_key /etc/letsencrypt/archive/domain.com/privkey.pem include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
Restart Nginx by running:
sudo service nginx restart
This will point web server to a new certificate (full chain) while using the old private key.
An original discussion and solution were posted here.