It should be possible to automate this with Let's Encrypt using Certbot, but I'm afraid there's no existing ready for use solution for this. Therefore, it requires some scripting, and you may need to hire someone, as you asked this question.
I would suggest something like this (examples are for the Apache 2.4 web server):
Create a catch-all configuration that points http://*/.well-known/acme-challenge/
to the same directory with any domain and with the default virtual host for the rest. This is possible with a global Alias
that could be placed in /etc/apache2/conf-enabled/acme-challenge.conf
:
<IfModule alias_module>
Alias /.well-known/acme-challenge/ /var/www/letsencrypt/.well-known/acme-challenge/
</IfModule>
Let your customers input their custom domains for validation and save the information somewhere, with a reference to the correct customer. A database would be ideal for that, wouldn't it. Possibly limit this to one custom hostname (& www) per customer.
Instruct your customers to point their domains to the correct IP address. In the case of a subdomain, a CNAME
record will work, but at the domain apex you will need to provide instructions for an A
record.
Here, the examples simply assume every domain has both example.com
and www.example.com
, but you can modify this according to your requirements.
Do not launch HTTP-01 challenge immediately, but create a script launched with a cronjob or a Systemd timer. The script should first check whether the domains waiting for validation points to your server or not, and launch the ACME challenge only for domains that meets the condition. Otherwise, someone could abuse the feature and make your server perform unnecessary Let’s Encrypt validations.
#!/bin/bash
MYSERVERIP="192.0.2.123"
if [ "$#" -ne 1 ]; then
printf "\n%s\n\n" "Usage: $0 example.com" >&2
exit 1
fi
host "$1" 2>&1 > /dev/null
if [ $? -ne 0 ]; then
printf "\n%s\n\n" "The given domain is not a valid FQDN." >&2
exit 1
fi
IPAPEX=$(dig "$1" +short | tail -n 1)
IPWWW=$(dig "www.$1" +short | tail -n 1)
if [ "$IPAPEX" = "$MYSERVERIP" ]; then
if [ "$IPWWW" = "$MYSERVERIP" ]; then
certbot certonly --quiet --webroot -w /var/www/letsencrypt -d $1 -d www.$1
if [ $? -ne 0 ]; then
printf "\n%s\n\n" "Certbot failed with HTTP-01 challenge." >&2
exit 1
fi
else
printf "\n%s\n\n" "Failed: www.$1 is not pointing to $MYSERVERIP." >&2
exit 1
fi
else
printf "\n%s\n\n" "Failed: $1 is not pointing to $MYSERVERIP." >&2
exit 1
fi
Once the validation is completed, the script may also add the configuration to the web server. You might use a macro, e.g. /etc/apache2/conf-enabled/custdomain-macro.conf
:
<Macro CustomWebShopDomain $customer $domain>
<VirtualHost *:80>
ServerName $domain
ServerAlias www.$domain
Redirect permanent / https://$domain/
</VirtualHost>
<VirtualHost *:443>
ServerName $domain
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/$domain/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/$domain/privkey.pem
SSLVerifyClient None
DocumentRoot /path/to/webshop/$customer
</VirtualHost>
<VirtualHost *:443>
ServerName www.$domain
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/$domain/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/$domain/privkey.pem
SSLVerifyClient None
Redirect permanent / https://$domain/
</VirtualHost>
</Macro>
In this case, adding a new customer domain would be simple:
Use CustomWebShopDomain customerid example.com
Your script might add this line to the configuration and then reload the Apache web server:
printf "%s\n" "Use CustomWebShopDomain $2 $1" \
>> /etc/apache2/conf-enabled/custdomain-use.conf
systemctl reload apache2
Be sure to clean out expired domains
Certbot adds all the domains for automatic renewals. If those renewals start to fail, you don't want to keep those domains in the configuration forever. It's best to automate the removal, i.e.
- Remove the Certbot configuration
/etc/letsencrypt/renewal/example.com
- Remove the
Use CustomWebShopDomain customerid example.com
line.