How to Use Let's Encrypt TLS Certificates on GoDaddy Shared Hosting
The Goal
I wanted to update a set of web sites
that are hosted on GoDaddy.
The sites had been there for a while, hosted on "Economy Linux"
platforms that had been the standard when
the sites were created.
In the past year or two GoDaddy had moved forward to their
newer "Economy Linux with cPanel" platform.
The newer platform was based on a significantly newer
distribution, meaning security improvements and possibly
performance improvements.
What's more, the price had dropped, no doubt due to the
rise of Google Cloud Platform.
If I was deploying those sites today,
I would go with the Google Cloud Platform.
This happened in September 2017, when Google was warning
that Chrome would start displaying "Insecure" on plain old
HTTP pages within a few weeks, and a lack of HTTPS would
start to hurt you in search result rankings some time
in the coming months.
The business owner of one of the sites had purchased a
TLS certificate from GoDaddy for about US$ 60/year.
On the other sites I went with free
Let's Encrypt
TLS certificates.
And, within a few months, I moved those sites to the
Google Cloud.
GoDaddy wants to sell certificates to make up for
reduced hosting income, so while they don't block the
use of Let's Encrypt certificates, they certainly don't
help you to do it.
But it's not at all hard to do.
Step 1: Upgrade
The old platform was really old.
It had a file /etc/*-release
which revealed
that it was based on CentOS 5.5!
Its version of OpenSSH was so old that it still supported
nothing but the DSA (or ssh-dss) public-key algorithm
for host keys.
OpenSSH 7.0 and later disabled DSA host keys.
That meant that you no longer could connect from reasonably
current platforms without adding a stanza to the bottom
of the /etc/ssh/ssh_config
file
on your clients from which you want to adminster the site.
$ tail /etc/ssh/ssh_config ## GoDaddy only supports the ssh-dss (DSA) public key algorithm ## for host keys. OpenSSH 7.0 and greater disables it. For ## details see: http://www.openssh.com/legacy.html Host example1.com example2.com example3.com example4.com HostkeyAlgorithms ssh-dss
The newer GoDaddy platform, current as of September 2017, is
CloudLinux OS.
It's really stripped down, with neither
os-release
nor lsb-release
in
/etc
.
CloudLinux OS is fully compatible with CentOS/RHEL packages.
It is also really tightened down.
Your home directory is the only subdirectory
of /home
.
You can only see your own processes in /proc
and with ps
and top
.
The /dev/
directory has very few devices
other than the pseudo-ttys.
No disk devices appear!
It uses
CageFS,
making it similar to a container.
The OpenSSH service was version 5.3, two major releases behind the current, but it was new enough to interoperate with an OpenSSH 7.5 client.
$ ssh -vv myusername@example.com uname -a [... output deleted ...] [... here are versions ...] debug1: Local version string SSH-2.0-OpenSSH_7.5 debug1: Remote protocol version 2.0, remote software version OpenSSH_5.3 [... output deleted ...] [... here are server capabilities ...] debug2: peer server KEXINIT proposal debug2: KEX algorithms: diffie-hellman-group-exchange-sha256,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1 debug2: host key algorithms: ssh-rsa,ssh-dss [... and cipher/MAC offers both ways ...] debug2: ciphers ctos: aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc,aes256-cbc,arcfour,rijndael-cbc@lysator.liu.se debug2: ciphers stoc: aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc,aes256-cbc,arcfour,rijndael-cbc@lysator.liu.se debug2: MACs ctos: hmac-md5,hmac-sha1,umac-64@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-ripemd160,hmac-ripemd160@openssh.com,hmac-sha1-96,hmac-md5-96 debug2: MACs stoc: hmac-md5,hmac-sha1,umac-64@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-ripemd160,hmac-ripemd160@openssh.com,hmac-sha1-96,hmac-md5-96 [... output deleted ...] [... here's what they agree upon ...] debug1: kex: algorithm: diffie-hellman-group-exchange-sha256 debug1: kex: host key algorithm: ssh-rsa debug1: kex: server->client cipher: aes128-ctr MAC: umac-64@openssh.com compression: none debug1: kex: client->server cipher: aes128-ctr MAC: umac-64@openssh.com compression: none [... output deleted ...]
I had the usual excellent live help over the phone. That's good, because GoDaddy's graphical panels are mysterious.
A roundabout sequence of clicks, copy, paste, and more clicks can get an authorized public key uploaded. That is, the public key matching the private key of a user identity.
Surprisingly, you still can't log in directly even though
you just uploaded a key that was installed in
~/.ssh/authorized_keys
(and, also,
authorized_keys2
for some reason).
You have to go back to the cPanel web interface and do some
clicking that leads to authorizing that new key identity.
You can't see what's going on, but I'm guessing that
you have to get the newly configured user identity listed as
an AllowUsers entry in the sshd_config
file.
CageFS hides the details, in /etc/ssh
you
only see the filese ssh_config
and
moduli
.
Once you can load your private keys into your SSH agent on your client and then make seamless key-based SSH connections, you're ready to move on.
Credit Where Credit Is Due
I created this page so I will have notes on how to do this even if other sites change or disappear.
The deployment steps in the following are based on those on the great TryingToBeAwesome.com site. Some steps on that page came from other contributors. And finally, all this is built on top of work by the authors of the acme.sh tool. That's a shell script implementing the ACME client protocol. ACME or the Automatic Certificate Management Environment is a protocol for automating interactions with certificate authorities.
There is no need for Python or Go or the official
Let's Encrypt client, as acme.sh
is
a pure shell script.
Nor is there any need for root
access.
This gives us an ACME tool for the shared hosting environment.
Step 2: Install acme.sh
Log in to your GoDaddy shared hosting system and run
the following to download and then install
the acme.sh
tool.
$ cd $ curl https://get.acme.sh | sh -s email=my@example.com $ source .bashrc
Two lines have been added to ~/.bashrc
,
referencing a two-line file that
sets an environment variable and defines an alias:
$ cat ~/.bashrc # .bashrc # Source global definitions if [ -f /etc/bashrc ]; then . /etc/bashrc fi # User specific aliases and functions . "/home/myusername/.acme.sh/acme.sh.env" $ cat ~/.acme.sh/acme.sh.env export LE_WORKING_DIR="/home/myusername/.acme.sh" alias acme.sh="/home/myusername/.acme.sh/acme.sh
Step 3: Get a GoDaddy API Key and Secret String
On your local desktop, start a browser and load https://developer.godaddy.com/keys/.
For some unexplained reason you must first generate a test key/secret pair. It's a single button click. Then you can generate a production key and secret.
I used vim
within my SSH session to edit
~/.acme.sh/keys
and store both pairs.
$ cat ~/.acme.sh/keys Test key: Key: qsLLqQyqhu6Lx1q85ctZbNYT90daRvR25 Secret: Bdx4ap8gi0kK8jOosHD1zf Production key: Key: AHoQgGr+qi1qModOIKZTktXzGak6C1MV0K Secret: mkNmVBf/6ZaWkMx0Bi5sX2
Of course those aren't the actual values!
They're the result of using dd
to send
several bytes from /dev/random
into
the base64
command to provide
appropriately sized examples.
Step 4: Issue a Certificate
Set two environment variables and then you're
ready to issue a certificate.
The --help
option explains the pieces
and suggests other options.
The certificate will be good for the domain itself
plus www.example.com.
$ export GD_Key=AHoQgGr+qi1qModOIKZTktXzGak6C1MV0K $ export GD_Secret=mkNmVBf/6ZaWkMx0Bi5sX2 $ acme.sh --help [... 94 lines of output ...] $ acme.sh --issue \ --domain example.com \ --domain www.example.com \ --webroot ~/public_html --dns dns_gd $ ls ~/.acme.sh/example.com ./ fullchain.cer example.com.csr ../ example.com.cer example.com.csr.conf ca.cer example.com.conf example.com.key
There will be a lot of narrative output, including
multiple countdowns for DNS updates to take effect.
A subdirectory of ~/.acme.sh
named for the
domain will appear, and the key and certificate along with
the intermediate CA certificate, full chain certificates,
certificate signing request, and CSR configuration
will be stored there.
Step 5: Upload the Certificate and Private Key to GoDaddy
We can call the cPanel API from our command line.
First, edit cpanel_uapi.sh
to uncomment the DEPLOY_CPANEL_USER
line and
set the variable to your numeric GoDaddycustomer ID.
$ head ~/.acme.sh/deploy/cpanel_uapi.sh
#!/bin/bash
# Here is the script to deploy the cert to your cpanel using the cpanel API.
# Uses command line uapi. --user option is needed only if run as root.
# Returns 0 when success.
# Written by Santeri Kannisto <santeri.kannisto@2globalnomads.info>
# Public domain, 2017
#export DEPLOY_CPANEL_USER=myusername
export DEPLOY_CPANEL_USER=12345678
Now you can deploy the certificate and key:
$ acme.sh --deploy --domain example.com --deploy-hook cpanel_uapi
You should see a message that the certificate was deployed.
Your site should now be available via HTTPS. Test it!
Step 6: Verify Continuing Renewal
The deployment has set up a nightly cron job, scheduled for a random minute between 0000 and 0100. Mine got 0032:
$ crontab -l 32 0 * * * "/home/myusername/.acme.sh"/acme.sh --cron --home "/home/myusername/.acme.sh" > /dev/null
You can run the cron job manually:
$ acme.sh --cron --home ~/.acme.sh ===Starting cron=== Renew: 'example.com' Skip, Next renewal time is: Sat Nov 25 16:34:49 UTC 2017 Add '--force' to force to renew. Skipped example.com ===End cron===
You will see that your certificate is good for 90 days,
and it will be renewed when 30 days remain.
As the command suggests, you can add --force
to make it happen.
You will see that it generates and installs the private key
and certificate and then deploys them.
Step 7: Set Up Redirection
I want to redirect all requests to the "non-www" hostname,
and redirect all HTTP requests to HTTPS.
That is, all of these URLs:
https://www.example.com/some/path
http://www.example.com/some/path
http://example.com/some/path
should be redirected to:
https://example.com/some/path
Add the following block to the end of
~/public_html/.htaccess
.
Don't repeat "RewriteEngine on" if it's already in the file:
$ tail ~/public_html/.htaccess # Remove "www." and redirect to https RewriteEngine on RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC] RewriteRule ^(.*)$ https://%1/$1 [R=301,L] RewriteCond %{HTTPS} off RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Also change "http" to "https" throughout the rest of your
.htaccess
and sitemap.txt
files.
Test everything and make sure that it's working.
Congratulations, you're done! For now...
Step 8: Stay Up To Date
Some time in April 2018, GoDaddy changed their API.
All at once, acme.sh
failed and the
certificate started to count down to expiration.
Update your acme.sh
code.
$ ~/.acme.sh/acme.sh --upgrade
Upgrading to acme.sh
v2.7.9 solved the
April 2018 problem.
acme.sh
RFC 8555
In June 2021, Let's Encrypt phased out
support for ACMEv1,
having replaced it with the ACMEv2 API as described in
RFC 8555.
You need to update your
acme.sh
client.
Save your old ~/.acme.sh/keys
file and
copy it into the new version:
-
$ mv .acme.sh OLD.acme.sh
- Do "Step 2" above.
-
$ cp OLD.acme.sh/keys .acme.sh
- Now repeat Steps 3-6 above.
$ ~/.acme.sh/acme.sh --version v2.7.9
Further Exploration
You can examine certificate details with the
openssl
command.
For a local file, while you're logged in on the server:
$ openssl x509 -in ~/.acme.sh/example.com/example.com.cer -text -noout | less
Or, from a remote client, use
openssl s_client
to retrieve the certificate and
openssl x509
to interpret and display it.
Do this, replacing cromwell-intl.com
with your domain name:
$ openssl s_client -showcerts -connect cromwell-intl.com:443 < /dev/null | openssl x509 -text Certificate: Data: Version: 3 (0x2) Serial Number: 04:e9:53:64:88:eb:fd:84:9b:63:47:95:a6:3f:39:87:9b:c0 Signature Algorithm: sha256WithRSAEncryption Issuer: C = US, O = Let's Encrypt, CN = R3 Validity Not Before: Apr 7 07:40:13 2024 GMT Not After : Jul 6 07:40:12 2024 GMT Subject: CN = cromwell-intl.com Subject Public Key Info: Public Key Algorithm: id-ecPublicKey Public-Key: (384 bit) pub: 04:d2:ef:ad:da:c1:7e:4d:4b:72:49:cd:e2:d5:94: 94:79:4a:81:09:63:cd:7d:44:07:4e:c3:54:48:fc: 4b:f8:5c:d3:46:3e:54:a1:9a:e3:03:68:24:39:61: 6c:ac:a8:b6:d1:64:fd:2a:b9:af:79:b8:d5:ef:c0: 37:b4:82:28:9a:26:2b:0f:24:85:1f:77:28:9f:e1: f3:ca:77:42:20:49:f7:8c:01:f1:aa:05:66:e4:99: 46:09:0a:ca:c4:7e:eb ASN1 OID: secp384r1 NIST CURVE: P-384 X509v3 extensions: X509v3 Key Usage: critical Digital Signature X509v3 Extended Key Usage: TLS Web Server Authentication, TLS Web Client Authentication X509v3 Basic Constraints: critical CA:FALSE X509v3 Subject Key Identifier: 1F:F4:A0:89:41:AA:65:09:49:F9:BF:AF:72:BF:7A:41:01:72:F9:7A X509v3 Authority Key Identifier: 14:2E:B3:17:B7:58:56:CB:AE:50:09:40:E6:1F:AF:9D:8B:14:C2:C6 Authority Information Access: OCSP - URI:http://r3.o.lencr.org CA Issuers - URI:http://r3.i.lencr.org/ X509v3 Subject Alternative Name: DNS:alt.cromwell-intl.com, DNS:cromwell-intl.com, DNS:www.cromwell-intl.com X509v3 Certificate Policies: Policy: 2.23.140.1.2.1 CT Precertificate SCTs: Signed Certificate Timestamp: Version : v1 (0x0) Log ID : 48:B0:E3:6B:DA:A6:47:34:0F:E5:6A:02:FA:9D:30:EB: 1C:52:01:CB:56:DD:2C:81:D9:BB:BF:AB:39:D8:84:73 Timestamp : Apr 7 08:40:14.161 2024 GMT Extensions: none Signature : ecdsa-with-SHA256 30:46:02:21:00:AA:CD:F2:83:5D:8F:66:04:1E:0E:1D: E1:27:33:84:0B:45:C1:4D:CA:B4:B7:30:D4:B5:A8:DC: 81:1A:3E:F8:48:02:21:00:EB:50:6F:8E:3E:64:16:81: 0C:59:BB:EE:C6:62:D5:0F:A3:DD:61:22:27:10:52:C2: CC:AB:88:F5:21:0A:FB:AA Signed Certificate Timestamp: Version : v1 (0x0) Log ID : EE:CD:D0:64:D5:DB:1A:CE:C5:5C:B7:9D:B4:CD:13:A2: 32:87:46:7C:BC:EC:DE:C3:51:48:59:46:71:1F:B5:9B Timestamp : Apr 7 08:40:14.163 2024 GMT Extensions: none Signature : ecdsa-with-SHA256 30:45:02:21:00:DF:04:CE:73:08:DF:76:4E:36:14:F2: E2:B9:BF:89:49:4D:73:3D:92:B6:C1:B2:0B:89:0A:1E: 55:EF:5C:8F:A9:02:20:52:08:35:C0:95:5D:45:63:A8: C4:30:85:4C:E6:94:14:53:07:ED:3E:0F:F6:2F:7D:78: 65:33:4F:73:BC:E6:22 TLS Feature: status_request Signature Algorithm: sha256WithRSAEncryption Signature Value: 42:4b:f7:02:f2:01:53:4f:bc:e4:53:0b:3d:ef:ee:f9:5a:5a: 63:a2:69:dc:4f:eb:e4:38:d7:5f:06:d9:73:1d:8f:d8:2b:ae: 17:29:d5:36:6c:94:7f:13:12:94:26:09:d1:38:f2:ed:2e:b4: 2f:7f:85:fe:5e:37:01:d1:5f:00:ab:98:bf:37:8f:a7:1b:6e: 89:a1:fa:85:d8:0b:99:c6:f3:99:af:d0:9f:ba:ff:7e:ea:7d: 2e:c9:63:ae:aa:6e:22:87:2b:5a:4c:6b:32:d4:e5:bd:ff:14: b4:81:0e:c3:a3:6a:5d:23:dc:2b:17:d6:35:51:06:a2:1a:c3: a8:d8:4f:88:2d:88:b4:c6:2b:0d:d4:5f:3d:92:3c:00:ed:8d: ea:c5:b9:bc:12:c0:11:8d:81:03:79:2f:c7:7b:ea:1d:e3:bf: eb:2c:d4:67:11:6b:a2:31:38:18:35:be:75:0d:5c:05:59:95: 97:49:1f:b7:eb:5c:cb:cc:63:c1:29:4f:ba:37:fa:13:c7:ce: 98:b5:4d:0d:b4:d5:8f:71:40:23:9c:14:19:f8:a6:c1:d0:e6: 2f:9a:02:12:5c:93:7c:7c:4f:d3:15:22:f8:95:01:55:bd:b5: c0:e6:82:03:ed:ba:96:08:68:eb:90:b2:dd:f1:ac:90:fa:67: bc:81:20:80 -----BEGIN CERTIFICATE----- MIIEgzCCA2ugAwIBAgISBOlTZIjr/YSbY0eVpj85h5vAMA0GCSqGSIb3DQEBCwUA MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD EwJSMzAeFw0yNDA0MDcwNzQwMTNaFw0yNDA3MDYwNzQwMTJaMBwxGjAYBgNVBAMT EWNyb213ZWxsLWludGwuY29tMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE0u+t2sF+ TUtySc3i1ZSUeUqBCWPNfUQHTsNUSPxL+FzTRj5UoZrjA2gkOWFsrKi20WT9Krmv ebjV78A3tIIomiYrDySFH3con+HzyndCIEn3jAHxqgVm5JlGCQrKxH7ro4ICVTCC AlEwDgYDVR0PAQH/BAQDAgeAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD AjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBQf9KCJQaplCUn5v69yv3pBAXL5ejAf BgNVHSMEGDAWgBQULrMXt1hWy65QCUDmH6+dixTCxjBVBggrBgEFBQcBAQRJMEcw IQYIKwYBBQUHMAGGFWh0dHA6Ly9yMy5vLmxlbmNyLm9yZzAiBggrBgEFBQcwAoYW aHR0cDovL3IzLmkubGVuY3Iub3JnLzBKBgNVHREEQzBBghVhbHQuY3JvbXdlbGwt aW50bC5jb22CEWNyb213ZWxsLWludGwuY29tghV3d3cuY3JvbXdlbGwtaW50bC5j b20wEwYDVR0gBAwwCjAIBgZngQwBAgEwggEFBgorBgEEAdZ5AgQCBIH2BIHzAPEA dwBIsONr2qZHNA/lagL6nTDrHFIBy1bdLIHZu7+rOdiEcwAAAY63txpRAAAEAwBI MEYCIQCqzfKDXY9mBB4OHeEnM4QLRcFNyrS3MNS1qNyBGj74SAIhAOtQb44+ZBaB DFm77sZi1Q+j3WEiJxBSwsyriPUhCvuqAHYA7s3QZNXbGs7FXLedtM0TojKHRny8 7N7DUUhZRnEftZsAAAGOt7caUwAABAMARzBFAiEA3wTOcwjfdk42FPLiub+JSU1z PZK2wbILiQoeVe9cj6kCIFIINcCVXUVjqMQwhUzmlBRTB+0+D/YvfXhlM09zvOYi MBEGCCsGAQUFBwEYBAUwAwIBBTANBgkqhkiG9w0BAQsFAAOCAQEAQkv3AvIBU0+8 5FMLPe/u+VpaY6Jp3E/r5DjXXwbZcx2P2CuuFynVNmyUfxMSlCYJ0Tjy7S60L3+F /l43AdFfAKuYvzePpxtuiaH6hdgLmcbzma/Qn7r/fup9LsljrqpuIocrWkxrMtTl vf8UtIEOw6NqXSPcKxfWNVEGohrDqNhPiC2ItMYrDdRfPZI8AO2N6sW5vBLAEY2B A3kvx3vqHeO/6yzUZxFrojE4GDW+dQ1cBVmVl0kft+tcy8xjwSlPujf6E8fOmLVN DbTVj3FAI5wUGfimwdDmL5oCElyTfHxP0xUi+JUBVb21wOaCA+26lgho65Cy3fGs kPpnvIEggA== -----END CERTIFICATE-----