Let’s Encrypt certificates + Nginx + Cloudflare

Categories: Webserver

This is how I have setup automatic certificate renewal on my linux Webserver. I’m using Cloudflare as a DNS provider and are using their API Tokens to verify ownership of my domain, when requesting a certificate from Let’s Encrypt


  • CentOS/RHEL
  • DNS hosted by Cloudflare
  • Software: git nginx curl
  • SSL Folder: create folder ssl in /etc/nginx/

Step 1 - Download and install acme.sh

Note. Zerossl is the default CA in acme.sh version 3.0 and above, so this has to be changed to Let’s Encrypt

git clone https://github.com/acmesh-official/acme.sh.git
cd .acme.sh
./acme.sh --install -m yourmail@domain.com --server letsencrypt
./acme.sh --set-default-ca --server letsencrypt

Step 2 - Verify domain ownership using Cloudflare API

export CF_Token="xxxxx"
export CF_Account_ID="xxxxx"
export CF_Zone_ID="xxxxx" # This is optional and can be used if you got more than one dns zone

The variables are saved in the account.conf file in your .acme.sh folder if you need to modify them later on.

Step 3 - Issuing a cetificate

./acme.sh --issue --dns dns_cf -d YOURDOMAIN.com --ocsp-must-staple # Creates RSA Certificate
./acme.sh --issue --dns dns_cf -d YOURDOMAIN.com --keylength ec-384 --ocsp-must-staple # Optional. Create ECDSA Certificate

Step 4 - Configure Nginx

Add these SSL settings to your server{} block. Change YOURDOMAIN.com to your needs

server {
    listen       443 ssl http2;
    server_name  YOURDOMAIN.com;

    ## RSA Certificates
    ssl_certificate ssl/YOURDOMAIN.fullchain.cer;
    ssl_certificate_key ssl/YOURDOMAIN.key;

    ## ECCC/ECDA Certificates
    ssl_certificate ssl/YOURDOMAIN.fullchain.ecc.cer;
    ssl_certificate_key ssl/YOURDOMAIN.ecc.key;

    ## Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits or higher
    ## Run this command to create the File
    ## openssl dhparam -dsaparam -out /etc/nginx/ssl/dhparam.pem 4096
    ssl_dhparam ssl/dhparam.pem;

    ## disable SSLv3(enabled by default since nginx 0.8.19) since it's less secure then TLS http://en.wikipedia.org/wiki/Secure_Sockets_Layer#SSL_3.0
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers "CHACHA20+POLY1305:EECDH+AESGCM:EDH+AESGCM";
    ssl_prefer_server_ciphers off;

    ## Verify chain of trust of OCSP response using Root CA and Intermediate certs
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_trusted_certificate ssl/YOURDOMAIN.fullchain.cer;

    ## maximum number and size of buffers for large headers to read from client request
    large_client_header_buffers 16 256k;
    client_body_buffer_size     128k;

Step 5 - Install certificate(s) in /etc/nginx/ssl/

export NGINX_SSL="/etc/nginx/ssl"
./acme.sh -d "$YOURDOMAIN" --install-cert --reloadcmd "systemctl reload nginx" --fullchain-file "${NGINX_SSL}/$YOURDOMAIN.fullchain.cer" --key-file "${NGINX_SSL}/$YOURDOMAIN.key" --cert-file "${NGINX_SSL}/$YOURDOMAIN.cer"
./acme.sh -d "$YOURDOMAIN" --ecc --install-cert --reloadcmd "systemctl reload nginx" --fullchain-file "${NGINX_SSL}/$YOURDOMAIN.fullchain.ecc.cer" --key-file "${NGINX_SSL}/$YOURDOMAIN.ecc.key" --cert-file "${NGINX_SSL}/$YOURDOMAIN.ecc.cer"

Step 6 - Enable acme.sh autoupgrade and update it to latest release

./acme.sh --upgrade --auto-upgrade

Step 7 - Configure e-mail notifications

# These are required:
export SMTP_FROM="from@example.com"  # just the email address (no display names)
export SMTP_TO="to@example.com,to2@example.net"  # just the email address, use commas between multiple emails
export SMTP_HOST="smtp.example.com"
export SMTP_SECURE="tls"  # one of "none", "ssl" (implicit TLS, TLS Wrapper), "tls" (explicit TLS, STARTTLS)

# The default port depends on SMTP_SECURE: none=25, ssl=465, tls=587.
# If your SMTP server uses a different port, set it:
export SMTP_PORT="2525"

# If your SMTP server requires AUTH (login), set:
export SMTP_USERNAME="<username>"
export SMTP_PASSWORD="<password>"

# acme.sh will try to use the python3, python2.7, or curl found on the PATH.
# If it can't find one, or to run a specific command, set:
export SMTP_BIN="/path/to/python_or_curl"

# If your SMTP server is very slow to respond, you may need to set:
export SMTP_TIMEOUT="30"  # seconds for SMTP operations to timeout, default 30

./acme.sh --set-notify --notify-hook smtp

For more information visit acme.sh