Enabling HTTPS on websites can deal with “HTTP hijacking” by ISPs. In most cases, using a free SSL certificate is sufficient.

ZeroSSL and Let’s Encrypt are two common CAs (Certificate Authorities). They both offer free SSL certificates with a 90-day validity period. The advantages are as follows:

  • Support Wildcard Certificates (like *.example.com ).
  • Support ECC certificate (ECC certificate is smaller than RSA under the same security).
  • Can be issued through API, no need to apply manually.

It is recommended to use acme.sh as a certificate issuance tool. It supports ACME v2, pure shell implementation, no other dependencies, and can be used on Linux / BSD.

Install Acme.sh

curl https://get.acme.sh | sh -s email=[email protected]

Some Linux distributions do not have cron installed by default, which prevents the installation from completing. For distributions such as Alpine Linux, Arch Linux, you can install cronie and run the above script again.

The scripts will do 3 things:

  • Copy acme.sh to ~/.acme.sh/
  • Create alias :acme.sh=~/.acme.sh/acme.sh
  • Create a daily cronjob 。

Setting Up Acme.sh

Wildcard Certificate requires domain name authentication. Acme.sh supports dozens of DNS providers. Let’s take Cloudflare DNS as an example.

Edit ~/.acme.sh/account.conf, add CF_Key and CF_Email from Cloudflare.

ACCOUNT_EMAIL="[email protected]"
export CF_Key="My Cloudflare API Key"
export CF_Email="[email protected]"

Get Cloudflare API Key:“Cloudflare Dashboard - Profile - Global API Key - View API Key”。

Other DNS configuration references How to use DNS API.

Issue Certificate

acme.sh --issue -d example.com -d '*.example.com' -k ec-256 --dns dns_cf --dnssleep 60

Parameter description:

  • --issue: issue certificate.
  • -d: followed by the domain name, wildcard domain names need to be enclosed in single quotes.
  • example.com: Replace it with your domain.
  • -k ec-256: issue ECC certificate (-k is equal to --keylength).
  • --dns dns_cf: Indicates to use Cloudflare DNS API.
  • --dnssleep 60: wait for 60 seconds after dns update.

Because the issued certificate is ECC, the generated certificate folder is example.com_ecc.

After successful issuance, there will be similar prompts as follows:

Your cert is in  /PATH/.acme.sh/example.com_ecc/examplecom.cer
Your cert key is in  /PATH/.acme.sh/example.com_ecc/example.com.key
The intermediate CA cert is in  /PATH/.acme.sh/example.com_ecc/ca.cer
And the full chain certs is there:  /PATH/.acme.sh/example.com_ecc/fullchain.cer

Install Certificate

Modify the server configuration, specify the certificate path.

# Caddy Server
tls /srv/ssl/example.com_fullchain.cer /srv/ssl/example.com.key

# nginx
ssl_certificate     /srv/ssl/example.com_fullchain.cer;
ssl_certificate_key /srv/ssl/example.com.key;
acme.sh --install-cert \
        -d example.com --ecc \
        --key-file /srv/ssl/example.com.key \
        --fullchain-file /srv/ssl/example.com_fullchain.cer \
        --reloadcmd "rc-service caddy reload"

Parameter description:

  • --install-cert: Specify the path to which the certificate needs to be copied.
  • --ecc: For ecc certificate, corresponding to -k ec-256 when issuing.
  • --key-file: specify the path of the key.
  • --fullchain-file: specify the path of fullchain cert.
  • --reloadcmd: Execute the command after copying is complete. This code is for “reload caddy”, if you are using nginx you can use systemctl restart nginx or nginx -s reload.

Please adjust the certificate path and reload command according to your needs.

Automatic Renew

Acme.sh can use crontab to periodically check if the certificate has expired and renew it. The crontab file is usually located in the /var/pool/cron/ or /etc/crontabs directory.

  • crontab -l: Show cron jobs.
  • crontab -e: Edit cron jobs。

Understanding Crontab syntax:

# Minute(0-59) Hour(0-23) Day Mon Week(0-6) Command
17 02 * * * "/PATH/.acme.sh"/acme.sh --cron --home "/PATH/.acme.sh" > /dev/null

The cronjob above indicates checking the certificate for expiration at 02:17 am every day. The default setting is to renew the certificate 30 days before it expires.

If the cronjob was not successfully added during installation, you can manually add it using acme.sh --install-cronjob.

Renew Certificate Manually

# Renew a cert
acme.sh --renew -d example.com --ecc

# Renew all the certs.
acme.sh --renew-all

# Run cron job to renew all the certs. 
# (Can be used to check if the cronjob command is correct)
acme.sh --cron

When renew certificates, it will automatically skip unexpired ones. Use --force for forced updates.


# The default CA is zerossl, Can switch to letsencrypt.
acme.sh --set-default-ca --server letsencrypt

# Use staging environment to test issuance and prevent IP from being blocked due to exceeding limits.
acme.sh --staging --issue -d example.com -d '*.example.com' -k ec-256 --dns dns_cf --dnssleep 60

# Update account email.
acme.sh --update-account --accountemail '[email protected]'

# Use --config-home to specify the configured directory, if multiple DNS API keys need to be used simultaneously.
# It's required for 'issue, install-cert, cronjob' etc
acme.sh --config-home '/PATH/TO/CONFIG_DIR' --issue -d example.com -d '*.example.com' -k ec-256 --dns dns_cf --dnssleep 60

# Review certificate
openssl x509 -text -noout -in fullchain.cer