Jump to content

How to issue Let’s Encrypt wildcard certificate with acme.sh and Cloudflare DNS

From Wiki
Note:Starting from August-1st 2021, acme.sh will release v3.0, in which the default CA will use ZeroSSL instead.

Iread your Let’s Encrypt TLS/SSL certificate acme.sh tutorial. But, I need to set up and use Cloudflare DNS with acme.sh. How do I secure my Nginx web server with Let’s Encrypt TLS/SSL certificate issue with Cloudflare DNS?

For wildcard TLS/SSL certificates, the only challenge method Let’s Encrypt accepts is the DNS challenge to authenticate the domain ownership. Therefore, we need to Cloudflare DNS API to add/modify DNS for our domain. This tutorial explains how to generate a wildcard TLS/SSL certificate using Let’s Encrypt client called acme.sh running on Linux or Unix-like systems.

Prerequisite to get Let’s Encrypt wildcard certificate

You need the Nginx server installed and running. For example:

sudo apt install nginx
sudo yum install nginx

Step 1 – Getting Cloudflare API key

  • Head over to Cloudflare control panel and obtain API key:
  • Click on the Create Token > Edit zone DNS > Use template
  • Make sure you set up DNS Permissions to Edit and include zone to your DNS domain name such as kangtain.com
  • Finally click on the Continue to summary to see your Edit zone DNS API token summary.

Finally, copy token displayed on the screen to access the Cloudflare API. Do not share this token with anyone. Keep it secure and secret.

Step 2 – Installing acme.sh client

After getting Cloudflare DNS API key, now set up the acme.sh client. Hence, clone the acme.sh repo using the git command:

cd /tmp/
git clone https://github.com/Neilpang/acme.sh.git

Install the client but first log in as root user using the su command/sudo command:

sudo -i
touch /root/.bashrc
cd /tmp/acme.sh/
acme.sh --install --accountemail your-email-id@domain-here

Step 3 – Issuing Let’s Encrypt wildcard certificate

So far we set up Nginx, obtained Cloudflare DNS API key, and now it is time to use acme.sh to get a wildcard certificate for kangtain.com domain. First set up the CF_Token using export command as follows:

# Export single variable for the CloudFlare DNS challenge to work #
# export CF_Token="Your_Cloudflare_DNS_API_Key_Goes_here"

No need to define shell variable CF_Account_ID and CF_Zone_ID as those will be automatically pulled by the acme.sh. Then request the certificate. Make sure you replace kangtain.com with your domain name:

acme.sh --issue --dns dns_cf --ocsp-must-staple --keylength 4096 -d kangtain.com -d '*.kangtain.com'
acme.sh --issue --dns dns_cf --server letsencrypt --ocsp-must-staple --keylength 4096 -d kangtain.com -d '*.kangtain.com'

If you prefer Elliptic-curve cryptography (ECC/ECDSA) instead of RSA, try:

Although it is possible to configure Nginx to use RSA and ECDSA certificates, I will use RSA here as my LB only supports RSA. But you can serve a dual-cert config too which offers an RSA certificate by default, and a (much smaller) ECDSA certificate to those clients that indicate support

acme.sh --issue --dns dns_cf --ocsp-must-staple --keylength ec-384 -d kangtain.com -d '*.kangtain.com'
[Tue 21 Jul 2020 09:41:22 AM UTC] Creating domain key
[Tue 21 Jul 2020 09:41:22 AM UTC] The domain key is here: /root/.acme.sh/kangtain.com_ecc/kangtain.com.key
[Tue 21 Jul 2020 09:41:22 AM UTC] Multi domain='DNS:kangtain.com,DNS:*.kangtain.com'
[Tue 21 Jul 2020 09:41:22 AM UTC] Getting domain auth token for each domain
[Tue 21 Jul 2020 09:41:23 AM UTC] Getting webroot for domain='kangtain.com'
[Tue 21 Jul 2020 09:41:23 AM UTC] Getting webroot for domain='*.kangtain.com'
[Tue 21 Jul 2020 09:41:23 AM UTC] kangtain.com is already verified, skip dns-01.
[Tue 21 Jul 2020 09:41:23 AM UTC] *.kangtain.com is already verified, skip dns-01.
[Tue 21 Jul 2020 09:41:23 AM UTC] Verify finished, start to sign.
[Tue 21 Jul 2020 09:41:23 AM UTC] Lets finalize the order, Le_OrderFinalize: https://acme-v02.api.letsencrypt.org/acme/finalize/91904709/4305779370
[Tue 21 Jul 2020 09:41:24 AM UTC] Download cert, Le_LinkCert: https://acme-v02.api.letsencrypt.org/acme/cert/0436c4ebf2a5784d099b29e0debb715b9b21
[Tue 21 Jul 2020 09:41:24 AM UTC] Cert success.
-----BEGIN CERTIFICATE-----
MIIEyDCCA7CgAwrBAgISBDbE6/KleE0Jmyng3rrxW5shMA0GCSqGSIb3DQEBCwUA
MDEwMTkwODQxMjNaMBgxFjAUrgNVBAMTDWN5YmVrY2l0aS5iaXowdjAQBgcqhkjO
PQIBBgUrgQQAwgNiAATgsEKKKKZQBxND706rTdaZUwwpb8439jksX4w4eJldr03A
.....
..
RuA8qFmhcftOGw2FZmQibR0m2ReMiwAf4m4dmU4uJ1UNp6AabA6Fj+wTbaLRrQqJ
SFGMqREOsgJxWt4ee+owwZXkpDwUHNqiA7ldyw==
-----END CERTIFICATE-----
[Tue 21 Jul 2020 09:41:24 AM UTC] Your cert is in  /root/.acme.sh/kangtain.com_ecc/kangtain.com.cer 
[Tue 21 Jul 2020 09:41:24 AM UTC] Your cert key is in  /root/.acme.sh/kangtain.com_ecc/kangtain.com.key 
[Tue 21 Jul 2020 09:41:24 AM UTC] The intermediate CA cert is in  /root/.acme.sh/kangtain.com_ecc/ca.cer 
[Tue 21 Jul 2020 09:41:24 AM UTC] And the full chain certs is there:  /root/.acme.sh/kangtain.com_ecc/fullchain.cer

Your Cloudflare DNS API key is sotred in /root/.acme.sh/account.conf file and we can see it using the cat command or grep command:

cat /root/.acme.sh/account.conf
grep '_CF_' /root/.acme.sh/account.conf

Step 4 – Configuring Nginx web server

Make sure you create a Diffie-Hellman key exchange file as follows using the openssl command:

mkdir -pv /etc/nginx/ssl/kangtain.com/
cd /etc/nginx/ssl/kangtain.com/
openssl dhparam -out /etc/nginx/ssl/kangtain.com/dhparams.pem -dsaparam 4096

Then edit your Nginx config file:

vim /etc/nginx/nginx.conf

Edit/update as follows:

# Port 80 config
server {
 listen      80 default_server; # IPv4
 listen [::]:80 default_server; # IPv6
 server_name www.cyberciti.biz;
 access_log  off;
 error_log   off;
 root        /var/www/html;
 return 301 https://$host$request_uri;
}
 
# Port 443 config
server {
 listen 443 ssl http2;                # IPv4
 listen [::]:443 ssl http2;           # HTTP/2 TLS IPv6
 server_name www.cyberciti.biz;  # domain name 
 # Set document root 
 location / {
 root   /var/www/html;
 index  index.html;
 }
 
 # Set access and error log for this vhos
 access_log /var/log/nginx/cyberciti.biz_access.log;
 error_log  /var/log/nginx/cyberciti.biz_error.log;  
 # TLS/SSL CONFIG 
 ssl_certificate /etc/nginx/ssl/cyberciti.biz/cyberciti.biz.fullchain.cer;
 ssl_certificate_key /etc/nginx/ssl/cyberciti.biz/cyberciti.biz.key;
 
 # ECC/ECDSA certificates (dual config)
 #ssl_certificate /etc/nginx/ssl/cyberciti.biz/cyberciti.biz.fullchain.cer.ecc;
 #ssl_certificate_key /etc/nginx/ssl/cyberciti.biz/cyberciti.biz.key.ecc;
 ssl_dhparam  /etc/nginx/ssl/cyberciti.biz/dhparams.pem;
 
 # A little bit of optimization 
 ssl_session_timeout 1d;
 ssl_session_cache shared:NixCraftSSL:10m;
 
 # TLS version 1.2 and 1.3 only
 ssl_session_tickets off;  
 ssl_protocols TLSv1.2 TLSv1.3;
 ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
 ssl_prefer_server_ciphers off;  
 
 # HSTS (ngx_http_headers_module is required)
 # *************************************************************************
 # WARNING - Wrong headers can create problems. Read docs otherwise
 #           all 3rd party scripts/ads won't load and in some case 
 #           browser won't work. Read docs @ https://developer.mozilla.org
 # ************************************************************************* 
 add_header Strict-Transport-Security "max-age=63072000" always;
 add_header X-Content-Type-Options "nosniff" always;
 add_header X-Frame-Options "SAMEORIGIN" always;
 add_header X-Xss-Protection "1; mode=block" always;
 add_header Referrer-Policy  strict-origin-when-cross-origin always;
 add_header Feature-policy "accelerometer 'none'; camera 'none'; geolocation 'none'; gyroscope 'none'; magnetometer 'none'; microphone 'none'; payment 'none'; usb 'none'" always;
 # ***************************************************************************************************
 # WARNING: The HTTP Content-Security-Policy response header allows sysadmin/developers 
 # to control resources the user agent is allowed to load for a given page. 
 # Wrong config can create problems for third party scripts/ad networks. Hence read the following url: 
 # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
 # ****************************************************************************************************
 add_header content-security-policy "default-src https://www.cyberciti.biz:443" always;  # OCSP stapling
 
 # Verify chain of trust of OCSP response using Root CA and Intermediate certs
 ssl_stapling on;
 ssl_stapling_verify on;  
 ssl_trusted_certificate /etc/nginx/ssl/cyberciti.biz/cyberciti.biz.fullchain.cer;  
 
 # Replace with the IP address of your resolver
 resolver 1.1.1.1;
}

Step 5 – Installing Let’s Encrypt wildcard certificate

Install your certificate (replace the systemctl reload nginx command as per your Linux/Unix distro)::

DOMAIN="kangtain.com"
CONFIG_ROOT="/etc/nginx/ssl/${DOMAIN}"
acme.sh -d "$DOMAIN" \
--install-cert \
--reloadcmd "systemctl reload nginx" \
--fullchain-file "${CONFIG_ROOT}/$DOMAIN.fullchain.cer" \
--key-file "${CONFIG_ROOT}/$DOMAIN.key" \
--cert-file "${CONFIG_ROOT}/$DOMAIN.cer"

Install ECC/ECDSA if you need them too (again, replace the systemctl reload nginx command as per your Linux/Unix distro):

acme.sh -d "$DOMAIN" \
--ecc \
--install-cert \
--reloadcmd "systemctl reload nginx" \
--fullchain-file "${CONFIG_ROOT}/$DOMAIN.fullchain.cer.ecc" \
--key-file "${CONFIG_ROOT}/$DOMAIN.key.ecc" \
--cert-file "${CONFIG_ROOT}/$DOMAIN.cer.ecc"

Source