It seems that the certbot, the recommended script to install and update the LetsEncrypt certificates requires root permissions. Well, I found several tutorials and forums where people claimed that they ran it without root permissions but they all said they needed root permissions to do something else for certbot to work and then I ran this simple command:
1 2 3 |
$./certbot-auto --help Requesting to rerun ./certbot-auto with root privileges... [sudo] password for eleni: |
and decided to give up and search for an alternative method. π
So, here’s what I finally did (Disclaimer: I am not really into security or system administration so, I don’t know if this method is the best or the most secure out there but I’ve found it quite simple and I liked that it doesn’t require weird package installations, root permissions, systemd or any other “easy”, “automated” params that create paths and files everywhere. At the end you will end up with only one directory where you can find your certificates and copy them where you like.):
Step 1: downloaded the acme.sh
I cloned the acme.sh script from github:
1 |
git clone https://github.com/Neilpang/acme.sh.git |
Step 2: issued the certificates
I issued my certificates using the acme.sh script:
1 2 |
cd acme.sh/ ./acme.sh --issue -d domain -w path |
domain
is the domain name for the site (for example for this site it could beeleni.mutantstargoat.com
if I wanted to use the certificates on my vhost ormutantstargoat.com
if I wanted to use it everywhere)path
is the path to the site content (it could be~/public_html
for example)
Then the acme.sh script created a directory ~/.acme.sh/
with the following contents:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
. βββ account.conf βββ ca βΒ Β βββ acme-v01.api.letsencrypt.org βΒ Β βββ account.json βΒ Β βββ account.key βΒ Β βββ ca.conf βββ βΒ Β βββ ca.cer βΒ Β βββ .cer βΒ Β βββ .conf βΒ Β βββ .csr βΒ Β βββ .csr.conf βΒ Β βββ .key βΒ Β βββ fullchain.cer βββ http.header |
Step 3: certificates installation
I’ve created a certificates/
directory in my home folder and ran the following command to install the certificates in ~/certificates/
:
1 |
$ ./acme.sh --install-cert -d domain --cert-file ~/certificates/cert.pem --key-file ~/certificates/key.pem --fullchain-file ~/certificates/fullchain.pem |
I ended up having these 3 files:
1 2 3 4 |
certificates/ βββ cert.pem βββ fullchain.pem βββ key.pem |
Step 4: apache configuration
The Apache webserver has a sites-enabled/website
file in /etc/apache2
where I had a VirtualHost configuration similar to this one:
1 2 3 4 5 6 |
VirtualHost *:80; ServerAdmin me@domain DocumentRoot /home/user/public_html ServerName domain [...] |
I enabled ssl and the mod_headers (the command must have been something like: a2enmod mod_ssl mod_headers
) and I added a second virtualhost for 443:
1 2 3 4 5 6 7 8 9 10 11 |
VirtualHost *:443; SSLEngine on SSLCertificateFile /etc/apache2/certificates/cert.pem SSLCertificateKeyFile /etc/apache2/certificates/key.pem SSLCertificateChainFile /etc/apache2/certificates/fullchain.pem # HSTS (mod_headers is required) (15768000 seconds = 6 months) Header always set Strict-Transport-Security "max-age=15768000" DocumentRoot /home/user/public_html ServerName your_domain [...] other settings I had in the non-ssl VirtualHost configuration |
I symlinked the ~/certificates/*.pem
to /etc/apache2/certificates
(that’s why the path is not ~/certificates
above, you should use the path to your certificates directory)
Restarted Apache!
Step 5: how I renew the certificates
I have my apache2 certificates in a directory ~/certificates
and I have a symlink to each one in /etc2/apache2/certificates/
.
I’ve written a script:
1 2 |
#!/usr/bin/bash ./acme.sh/acme.sh --renew -d <domain> --force |
(well I could had used the command directly)
and put it in a cronjob (as a user) that runs every month, the first day at 6:00 am:
1 |
crontab -e |
1 |
0 6 1 * * /bin/bash <path>/renew-certs.sh |
Then I added another cronjob in /etc/crontab
to reload the apache configuration files 1 hr later:
1 |
0 7 1 * * root apache2ctl graceful |
And problem solved. π
[UPDATE 2021]: acme-v1 API stopped being updated!
Around the end of 2021 the acme-v1
API stopped being updated. As a result my certificates weren’t automatically updated and my attempts to manually renew the certificates resulted in errors. My workaround:
- I modified the configuration files to use v02 instead of v01. In my
~/.acme.sh/<domain>/ directory there was a file:
<domain>.conf (for example:
eleni.mutantstargoat.com.conf
). In that file I replaced all references to v01 with v02, so that url: https://acme-v01.api.letsencrypt.org/directory becomes https://acme-v02.api.letsencrypt.org/directory. - I updated the acme.sh script by pulling the most recent version of master and then running: ./acme.sh --upgrade.
- I set the default CA to be letsencrypt by running:
./acme.sh --set-default-ca --server letsencrypt. I also edited the
.acme.sh/account.conf
file and added this extra line:DEFAULT_CA='https://acme-v02.api.letsencrypt.org/directory'
(I am not sure the second was required). - As I was persistently getting the curl error 60 (https://curl.se/libcurl/c/libcurl-errors.html: The remote server’s SSL certificate or SSH md5 fingerprint was deemed not OK. This error code has been unified with CURLE_SSL_CACERT since 7.62.0. Its previous value was 51.) I decided to run
acme.sh
with the option--use-wget
and I’ve modified theacme.sh
script as follows:12345678910111213diff --git a/acme.sh b/acme.shindex d2e8b04..e2fbb29 100755--- a/acme.sh+++ b/acme.sh@@ -1806,7 +1806,7 @@ _inithttp() {fiif [ -z "$_ACME_WGET" ] && _exists "wget"; then- _ACME_WGET="wget -q"+ _ACME_WGET="wget --no-check-certificate -q"if [ "$ACME_HTTP_NO_REDIRECTS" ]; then_ACME_WGET="$_ACME_WGET --max-redirect 0 "fi
After those changes I ran:
./acme.sh --renew-all --force --use-wget and my certificates were renewed without errors. As a last step I restarted Apache and checked that when I visit my blog with chromium, or firefox the connection appears to be secure (valid certificates).
Hi, i just find this tutorial about acme.sh.
My question is: what if:
– a want to use another default port than 80 and 443
– i have document root at /var/www but my cgi script is another directory..
Thnx in advance