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.
- Enable the letsencrypt=1 option in the directadmin.conf
- If you want wildcard domain SSL certificate support via Let's Encrypt, ensure dns_ttl=1 is set in the directadmin.conf.
- Remote DNS providers are now supported via LEGO.
- Restart DirectAdmin:
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 script 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 Encrypt 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 here.
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-Limit 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 post 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 script.
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 here
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.