Let's Encrypt For Domains

How to Enable Let's Encrypt and Install an SSL for a Domain

Let's Encrypt is a free SSL tool that lets you install a very basic free SSL Certificate with 1 click. It supports multiple domains, sub-domains, and wildcards, and will auto-renew automatically before it expires after it's ~90 day lifespan.

To enable this feature in DirectAdmin, ensure you have DirectAdmin 1.50.1 or newer.

echo "action=directadmin&value=restart" >> /usr/local/directadmin/data/task.queue; /usr/local/directadmin/dataskq d2000
  • Add the /.well-known Alias:
cd /usr/local/directadmin/custombuild
./build rewrite_confs

Users should then be able to see the Let's Encrypt option in their panel via User Level -> SSL Certificates and be able to use this option to enable SSLs for their domains.

Select the Let's Encrypt option, review the subdomain/wildcard selections, adjust as desired, then proceed to request the SSL to be installed.

To install a Let's Encrypt SSL for a domain via SSH, you can use the letsencrypt.sh scriptopen in new window located at /usr/local/directadmin/scripts/letsencrypt.sh:

usage:

./letsencrypt.sh request|renew|revoke domain.com 4096 (/path/to/csr-request-config-file)

but you shouldn't need to run it manually, as DA will call it automatically when the User triggers it through DA.

Note, when you run it through DA, the domain.com.san_config will have more details than if you run it from ssh (.san_config will be created, but with less info).

LEGO: Remote DNS Providers with Let's Encrypt

LEGO is a LetsEncrypt client and ACME library written in Go, hence the name LEGO. This useful library facilitates the use of 3rd-party, remote DNS providers with Let's Encrypt by utilizing those providers' APIs to complete domain validation checks via DNS, thus permitting the issuance of LE SSLs for domains using remote DNS.

Wildcard certificates for LetsEncrypt require DNS confirmation. If you're running at some remote DNS provider that is not currently supported by the Multi-Server Setup, then this tool lets you use wildcard certs with those DNS providers.

This document will use Cloudflare as the example remote DNS provider.

INSTALL

Ensure that wildcard domain SSL certificate support via Let's Encryptopen in new window is enabled via dns_ttl=1 in the directadmin.conf.

GUI USAGE

This feature is only available in the Evolution Skin as of November 2020. You may access it via the User level Dashboard > Account Manager > SSL Certificates.

Click the option Free & automatic certificate from Let's Encrypt, where, when creating the cert, once the Wildcard option is selected, a new field (below) will appear, defaulting to Dns Provider = Local.

You can then pick a new DNS provider, say "CloudFlare", and enter your user/key + extra bits, as specified by that provider.

Once these details are entered and you trigger the request, the ENVs are passed to the new letsencrypt.sh script and your request will run in the background.

Once completed, you'll be notified in the Message System.

We'll be adding fixes/improvements as we go, so ensure you have the updated script if you encounter any issues!

JSON

To get the list of supported DNS providers, include &dnsproviders=yes in the request, e.g., CMD_SSL?domain=domain.com&dnsproviders=yes&json=yes

As the file is somewhat large, only load it if the given skin knows how to use it.

It will be loaded in a top-level array called:
dnsproviders["data"] = { "version" : "3.7.0", "acme-dns": ...}

Any info about the current domain settings will be in: dnsproviders["dnsprovider"] where the dnsprovider (singular) is a dump of the domain.com.dnsprovider file, used to auto-fill the pre-selected choice. If this file contains inherit=creator or inherit=global, it will use the respective dnsprovider.conf file.

INHERIT DNS PROVIDER

An Admin/Creator can set up 2 possible inherit files:

  • Global: /usr/local/directadmin/data/admin/dnsprovider.conf
  • Creator: /usr/local/directadmin/data/users/resellerbob/dnsprovider.conf

Should either of these exist, where creator=resellerbob is in the given User's user.conf, they'll be included in the list of dnsproviders["data"] output as:

dnsproviders["data"]["inherit-creator"]
dnsproviders["data"]["inherit-global"]

where each would still have the correct "Name", but the type is prefixed, e.g., dnsproviders["data"]["inherit-creator"]["name"] = "Inherit Creator : Cloudflare"

"Inherit Creator : " or "Inherit Global" would be prefixed beside the name from the used provider, Cloudflare in this example, for that inherited dnsprovider.conf type.

The inherit-creator or inherit-global arrays will have an empty credentials array, and zero credentials are allowed to be passed if the master (including inherited configs) have zero creds.

If the "dnsprovider" is empty (nothing picked yet), check for:
dnsproviders["settings"]["default"]
to know which selection should be used by default. It should be either local, inherit-creator, or inherit-global.

The Global/Creator dnsprovider.conf files may contain one of the following:

default=inherit-creator
default=inherit-global
default=local

which is what specifies the default value for a User to have pre-selected.

RESELLERS/ADMINS: SETTING THE INHERITED VALUES

Resellers/Admins can set an inherit-creator dnsprovider.conf file. Admins can also set the inherit-global dnsprovider.conf file.

VIEW

Either can view that config (if it exists) via: CMD_SSL?action=dnsprovider&json=yes

or: CMD_SSL?action=dnsprovider&json=yes&type=global

which provides a similar array, e.g.,

dnsproviders["data"]
dnsproviders["dnsprovider"]
dnsproviders["type"] = "creator" | "global"

SAVE

CMD_SSL
method: POST
action=dnsprovider
default=local|inherit-global|inherit-creator   (optional)
dnsprovider=cloudflare
(type=global|creator)
CLOUDFLARE_EMAIL=foo@bar.com
CLOUDFLARE_API_KEY=sdgsd7681afn

where the last 3 depend on which "dnsprovider" was selected, similar to below for Users. The default is optional and is used to tell the User which default selection to use. Saved in the creator/reseller dnsprovider.conf.

If no type is passed, creator is used. A Reseller is not allowed to set type=global.

RESET

CMD_SSL
method: POST
action=dnsprovider
dnsprovider_reset=yes
(type=global|creator)

which simply deletes the given Admin/Reselelr dnsprovider.conf file.

USERS: POST PARAMETERS FOR SPECIFYING A DNSPROVIDER VS INHERITING

When saving data for a LetsEncrypt request for Users, include dnsprovider=NAME to activate the rest of the checks, e.g.,

CMD_SSL
method: POST
domain=domain.com
action=save
background=auto
type=create
request=letsencrypt
name=domain.com
wildcard=yes
keysize=secp384r1
encryption=sha256
le_wc_select0=domain.com
le_wc_select1=*.domain.com
submit=Save

dnsprovider=cloudflare
CLOUDFLARE_EMAIL=foo@bar.com
CLOUDFLARE_API_KEY=sdgsd7681afn

for example, assuming cloudflare is the desired remote dnsprovider.

Note, for an inherited dnsprovider, do not pass in a dnsprovider= parameter, else it will override the inherited value with the passed value.

ONLY SAVE DNSPROVIDER INFO

If you wish to only save the dnsprovider info, use:

CMD_SSL
method: POST
domain=domain.com
action=save
type=dnsprovider
dnsprovider=cloudflare
CLOUDFLARE_EMAIL=foo@bar.com
CLOUDFLARE_API_KEY=sdgsd7681afn
RESET

To remove the domain.com.dnsprovider file (thus resetting the dnsprovider to Local), include: dnsprovider_reset=yes to either of the above requests. Neither dnsprovider= nor its related fields are needed when dnsprovider_reset=yes is passed.

For example,

CMD_SSL
method: POST
domain=domain.com
action=save
type=dnsprovider
dnsprovider_reset=yes

USER / DOMAIN DATA FILES AND CONTENT

When a selection is made by a User (or via a creator's default choice), the domain's DNS settings will be stored in: /usr/local/directadmin/data/users/USERNAME/domains/DOMAIN.COM.dnsprovider

Sample data:

dnsprovider=cloudflare
CLOUDFLARE_EMAIL=foo@bar.com
CLOUDFLARE_API_KEY=sdgsd7681afn

OR:

inherit=yes

(or something similar),

This is loaded into the ENV and passed onto the letsencrypt.sh script.

Automatically redirect domain/pointer to SSL

Since a lot of domains use .htaccess for SSL redirection this feature is disabled by default to prevent loops. However, DirectAdmin SSL redirection comes directly from webserver so it will be faster than using .htaccess. Each user may individually enable redirection under:

User Level -> Domain Setup -> domain.com -> Force Redirect

Available redirection options:

  • www
  • non-www
  • none

Pointers will also use this setting. You may find more information about this feature hereopen in new window.

Automatically set up Let's Encrypt SSL for all domains that do not currently have a certificate

The new Let's Encrypt feature is a great way to easily secure your website connections at no cost. If you already have many websites that you want to secure all at once, you can use the autoletsencrypt.sh script to do this.

After you've enabled Let's Encrypt on the system, you can install certificates for all domains using the following script:

cd /root
wget -O autoletsencrypt.sh http://files.directadmin.com/services/all/letsencrypt/autoletsencrypt.sh
chmod 755 autoletsencrypt.sh
./autoletsencrypt.sh

Note that if you have too many domains, you might hit the Let's Encrypt Rate-Limitopen in new window so if that happens, you should be able to wait until the time window has passed, run it again, which should continue where it left off.

Swapping cPanel SSLs on Domains Transferred from cPanel for Let's Encrypt SSLs Managed by DirectAdmin

If you've recently migrated from cPanel to DirectAdmin, you will need to convert your cPanel/Sectigo SSLs to Let's Encrypt SSLs.

A script from a DirectAdmin forum postopen in new window will create all necessary files so that DirectAdmin can manage automatic Let's Encrypt SSL renewals for your migrated domains.

Running the script in the post will create all necessary files needed for DirectAdmin to manage the SSLs. You may also want to go ahead and proceed with ensuring all domains have valid SSLs by using the aforementioned autoletsencrypt.sh script from the above guide. You may also want to check that the hostname SSL is valid and will be autorenewed as well.

Combine every check into one single script that you can run following a migration from cPanel to DirectAdmin like so:

#!/bin/bash
#Convert cPanel SSLs to Let's Encrypt SSLs Managed by DirectAdmin
for i in `cat /etc/virtual/domainowners | cut -d: -f1`; do { 
    USER=`grep "^${i}:" /etc/virtual/domainowners | awk '{print $2}'`;
    CERT_PATH=/usr/local/directadmin/data/users/${USER}/domains/${i}.cert
    if [ -s ${CERT_PATH} ]; then
        if openssl x509 -issuer -in ${CERT_PATH} -noout | grep -m1 -q "cPanel"; then
            CERT_DATE="`openssl x509 -startdate -in ${CERT_PATH} -noout | cut -d= -f 2`"
            TIMESTAMP="`date --date=\"${CERT_DATE}\" +%s`"
            TIMESTAMP_LENGTH="`echo \"${TIMESTAMP}\" | wc -c`"
            if [ ! -s /usr/local/directadmin/data/users/${USER}/domains/${i}.cert.creation_time ]; then
                echo "Setting up ${i} (owned by ${USER}/) for autorenewal..."
                if [ ${TIMESTAMP_LENGTH} -gt 10 ]; then
                    echo "${TIMESTAMP}" > /usr/local/directadmin/data/users/${USER}/domains/${i}.cert.creation_time
                else
                    echo "0" > /usr/local/directadmin/data/users/${USER}/domains/${i}.cert.creation_time
                fi
            fi
            if [ ! -s /usr/local/directadmin/data/users/${USER}/domains/${i}.san_config ]; then
                SAN_CN="`openssl x509 -noout -subject -in ${CERT_PATH} | cut -d= -f3`"
                SAN_NAMES="`openssl x509 -noout -text -in ${CERT_PATH} | grep -m1 -A1 'Subject Alternative Name' | grep -o 'DNS:.*'`"
                cat <<< "
[ req ]
default_bits        = 4096
default_keyfile        = keyfile.pem
distinguished_name    = req_distinguished_name
attributes        = req_attributes
output_password        = bogus


[ req_distinguished_name ]
CN            = ${SAN_CN}
[ req_attributes ]
[ SAN ]
subjectAltName=${SAN_NAMES}" > /usr/local/directadmin/data/users/${USER}/domains/${i}.san_config
            fi
        fi
    fi
}; 
done


#run autoletsencrypt.sh for all domains to ensure any needed SSLs are installed as should be.
printf "Ensuring all migrated domains have valid SSLs installed...\n"
wget -O /root/autoletsencrypt.sh http://files.directadmin.com/services/all/letsencrypt/autoletsencrypt.sh
chmod 755 /root/autoletsencrypt.sh
sh /root/autoletsencrypt.sh


#enable hostname SSL if not present or expired
printf "Ensuring the hostname SSL is valid and will be autorenewed...\n"
HOSTCACERT=`/usr/local/directadmin/directadmin config | grep 'cacert.pem' | cut -d= -f2`

#request hostname SSL (note: doesn't affect self-signed SSLs, so another check would be needed for this)
if [[ `openssl x509 -checkend 0 -in $HOSTCACERT` != "Certificate will not expire" ]];then
  /usr/local/directadmin/scripts/letsencrypt.sh server_cert
fi

#ensure creation_time file exists for hostname autorenewal...
if [ ! -s $HOSTCACERT.creation_time ]; then
  echo "Setting up the hostname SSL for autorenewal..."
  echo "0" > $HOSTCACERT.creation_time
fi

exit 0

Save the script as ssl.sh, make executable and run it:

chmod 755 ssl.sh
./ssl.sh

Create new User with ssl on, but with ssl off for the new domain

In some cases, you might want to create a new User and allow that User the ability to use SSL and SSL certificates, but don't want it turned on by default for the domain, to keep the VirtualHost count down.

This can be done with the user_create_post_confirmed.sh scriptopen in new window.

So create /usr/local/directadmin/scripts/custom/user_create_post_confirmed.sh with code:

#!/bin/sh
CONF=/usr/local/directadmin/data/users/$username/domains/$domain.conf
if [ -s $CONF ]; then
   perl -pi -e 's/ssl=ON/ssl=OFF/' $CONF
   echo "action=rewrite&value=httpd&user=$username" >> /usr/local/directadmin/data/task.queue
fi
exit 0;

and make it executable:

chmod 755 /usr/local/directadmin/scripts/custom/user_create_post_confirmed.sh

This will shut off SSL for the new domain after the User is created, and rewrite their httpd.conf file up to 1 minute later via task.queue (in case you're wondering why the 443 VH might still be added immediately after User creation).

Enforcing ssl=ON for all Users, Resellers and their packages

For the modern age, websites should be using SSL for their websites. This guide provides a means to enforce enabling it for all Users/Resellers, their domains, and the packages used to create them.

First, we'll setup the enforcement for actions in the GUI.

Saving a package

Create the directory and script:

/usr/local/directadmin/scripts/custom/package_write_pre/enforce_ssl.sh

with code:

#!/bin/sh
if [ "${ssl}" = "OFF" ]; then
   echo "SSL must be enabled";
   exit 1;
fi
exit 0;

Account creation/modification

Create both:

/usr/local/directadmin/scripts/custom/user_create_pre/enforce_ssl.sh

and

/usr/local/directadmin/scripts/custom/user_modify_pre/enforce_ssl.sh

with the same code as above.
Chmod all scripts to 755:

chmod 755 /usr/local/directadmin/scripts/custom/*/enforce_ssl.sh

Change all Users, domains, and packages to use ssl=ON:

cd /usr/local/directadmin/data
perl -pi -e 's/^ssl=OFF/ssl=ON/' users/*/user.conf
perl -pi -e 's/^ssl=OFF/ssl=ON/' users/*/domains/*.conf
perl -pi -e 's/^ssl=OFF/ssl=ON/' users/*/reseller.conf
perl -pi -e 's/^ssl=OFF/ssl=ON/' admin/packages/*.pkg
perl -pi -e 's/^ssl=OFF/ssl=ON/' users/*/packages/*.pkg

Follow up with a rewrite of the webserver configs to use the values:

cd /usr/local/directadmin/custombuild
./build rewrite_confs

Let's Encrypt weekly domain rate limit

LetsEncrypt has a rate limit of 50 requests per week, per main domain. Read more hereopen in new window

DirectAdmin has this directadmin.conf option:

letsencrypt_max_requests_per_week=200

The 50 LE limit is only requests that make it that far. The letsencrypt.sh script has some prechecks which could fail before the LE limit, so the 200 limit is used to err on the side of caution to reach the actual LE 50 limits.

In effect, the letsencrypt_max_requests_per_week=200 value is mainly for a last-resort limit on "far too many requests", vs trying to predict the true LE 50 limit.

DISABLE

You can fully disable the DA limit enforcement by setting:

/usr/local/directadmin/directadmin set letsencrypt_max_requests_per_week 0
service directadmin restart

FILES

/usr/local/directadmin/data/admin/letsencrypt_rate_limits/DOMAIN.COM/weekly_domain_count

which will be a JSON file, storing each request attempt.

Future requests will read, reduce old entries, and add new ones as needed. If there are 200 or more entries after reduction, the request will not happen and the new request will not be added to the file.

NIGHTLY TALLY

Each tally will see if the age of the weekly_domain_count for each main domain is older than 1 week and will fully remove the domain.com directory if it is.

USERS

These are cross-User files, meaning, if

  • User bob has domain.com
  • User fred has sub.domain.com

both Users will have their counts stored in the same domain.com/weekly_domain_count file.

If you run many subdomains on the system, it would be highly advisable to request a wildcard for domain.com, so that sub.domain.com does not need to create any requests, as the limit would be reached quite quickly.

Last Updated: