This is a suite of tiny, auditable scripts that you can throw on your server to manage keys, certificate requests and Let's Encrypt certificates using acme-tiny.
git clone https://github.com/mat813/acme-tiny-scripts.git
cd acme-tiny-scripts
cp config.sh.sample config.sh
Edit the values in config.sh
according to your installation. All three path
should be owned by the user running the scripts, the mode of the private path
should be 0711. The durations are in days.
This script is used to generate keys for 1) the account, 2) the certificate and
requests. It takes only one argument, the name associated with the key. The
same name will be used for the certificate request, and the certificate. In
the end, you will get a <name>.crt
When you first run everything, you must generate an account key, it is not used by any certificate, only for communication between the scripts and letsencrypt. Start by:
$ ./gen_key.sh account
Generating RSA private key, 4096 bit long modulus
...................................++
..............++
e is 65537 (0x10001)
$
Now, you can create the key to your first certificate request:
$ ./gen_key.sh example
Generating RSA private key, 4096 bit long modulus
............................++
...........................................++
e is 65537 (0x10001)
$
This script generates a Certificate Signing Request in the private directory. It takes two, or more, arguments, the first is the name, the same as the one used for the key generation, and the other are the domains you need your certificate to have:
$ ./gen_csr.sh example examples.com www.examples.com examples.net www.examples.net
$
You can check that it does contain the right domains with:
$ openssl req -noout -text < /etc/ssl/private/letsencrypt/example.csr |grep DNS
DNS:examples.com, DNS:www.examples.com, DNS:examples.net, DNS:www.examples.net
The script will also generate a /etc/ssl/public/letsencrypt/example.tlsa file
with HTTPS TLSA (_443._tcp.domain.
) records for all the domains passed as
arguments. If you are using the certificates for other purpose than HTTPS, you
will have to change the port number.
This script uses the key and CSR generated during the previous steps and calls acme-tiny.py to get a valid certificate from Let's Encrypt.
At this point, you need to have setup your web server to point the
/.well-known/acme-challenge/
directory to the challenge path of the
configuration file. See configuring your web
server for more informations.
$ ./gen_one.sh example
Parsing account key...
Parsing CSR...
Registering account...
Already registered!
Verifying example.com...
example.com verified!
Verifying www.example.com...
www.example.com verified!
Verifying example.net...
example.net verified!
Verifying www.example.net...
www.example.net verified!
Signing certificate...
Certificate signed!
$
If all went well, you now have a example.crt
file in the public directory.
You can check that it does contain the requested domains:
$ openssl x509 -noout -text -in /etc/ssl/public/letsencrypt/example.crt |grep DNS
DNS:examples.com, DNS:www.examples.com, DNS:examples.net, DNS:www.examples.net
You can now configure the SSL bits of your web web server with that certificate and the associated key.
There are actually two files that are generated, the <name>.crt
that only
contains the certificate, and a <name>.bundle
that contains both the
certificate, and the intermediate certificate from Let's Encrypt. The
intermediate certificate is also stored as intermediate.pem in the public
directory.
First, note that Let's Encrypt will look for the challenge over http not https, so either your web server must be able to give the answer over http, or it must redirect to https, and in that case, the certificate must be valid.
In the following examples, I will describe serving the challenges over http. I prefer this method because it still works if your certificates are invalid, for example, if you let the expire.
To be able to serve the challenge over http, you only need to add an Alias
directive
<VirtualHost *:80>
ServerName www.example.net
Alias /.well-known/acme-challenge/ /usr/local/www/challenges/
<Directory /usr/local/www/challenges/>
Require all granted
</Directory>
[rest of your VirtualHost configuration]
</VirtualHost>
If your VirtualHost
contains a RedirectPermanent / https://www.examples.net/
then you will need to be a bit more subtle with how
you configure things so that the challenges work:
<VirtualHost *:80>
ServerName www.example.net
Alias /.well-known/acme-challenge/ /usr/local/www/challenges/
<Directory /usr/local/www/challenges/>
Require all granted
</Directory>
RedirectMatch 301 ^(?!/\.well-known/acme-challenge/).* https://www.example.net$0
</VirtualHost>
server {
listen *:80;
listen [::]:80;
server_name www.example.net;
location /.well-known/acme-challenge/ {
alias /usr/local/www/challenges/;
try_files $uri =404;
}
[rest of your server configuration]
}
If your server configuration contains a return 301 https://www.example.net$request_uri;
then you will need to bit a bit more
subtle with how you configure things so that the challenges work:
server {
listen *:80;
listen [::]:80;
server_name www.example.net;
location /.well-known/acme-challenge/ {
alias /usr/local/www/challenges/;
try_files $uri =404;
}
location / {
return 301 https://www.example.net$request_uri;
}
}
There are dozens of howtos on how to configure HTTPS, I'm keeping this mostly for my own use :-)
The /etc/ssl/private/dhparam_4096.pem
file is generated with openssl dhparam -out dhparam_4096.pem 4096
.
You must enable ssl_module and socache_shmcb_module.
Listen 443
<IfVersion >= 2.4>
<IfModule socache_shmcb_module>
SSLSessionCache "shmcb:/tmp/ssl_scache(512000)"
SSLSessionCacheTimeout 300
SSLStaplingCache "shmcb:/tmp/stapling_cache(2097152)"
</IfModule>
</IfVersion>
<IfVersion < 2.4>
SSLSessionCache "shmcb:/tmp/ssl_scache(512000)"
SSLSessionCacheTimeout 300
</IfVersion>
SSLProtocol All -SSLv2 -SSLv3
SSLHonorCipherOrder on
SSLCipherSuite "HIGH:!aNULL:!MD5:!3DES:!CAMELLIA:!AES128"
SSLEngine on
<IfVersion >= 2.4>
SSLOpenSSLConfCmd DHParameters "/etc/ssl/private/dhparam_4096.pem"
SSLUseStapling on
</IfVersion>
SSLCertificateFile "/etc/ssl/public/letsencrypt/example.crt"
SSLCertificateKeyFile "/etc/ssl/private/letsencrypt/example.key"
SSLCertificateChainFile "/etc/ssl/public/letsencrypt/intermediate.pem"
Remember to enable ssl and http2:
listen *:443 ssl http2;
listen [::]:443 ssl http2;
ssl_certificate /etc/ssl/public/letsencrypt/example.bundle;
ssl_certificate_key /etc/ssl/private/letsencrypt/example.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers "HIGH:!aNULL:!MD5:!3DES:!CAMELLIA:!AES128";
ssl_dhparam "/etc/ssl/private/dhparam_4096.pem";
ssl_prefer_server_ciphers on;
ssl_session_cache builtin:1000 shared:SSL:10m;
ssl_stapling on;
ssl_stapling_verify on;
ssl_session_timeout 5m;
This script should be run, via cron, every day, to regenerate outdated certificates. Certificates are considered outdated when their expiration date is less than $renew days from now, the default is 20 days.
Before you add a cron entry with 0 0 * * * /some/path/regen.sh
. I said once
a day, not "at midnight". If everybody does that, the Let's Encrypt servers
will be hammered at the top of every hour.
So, add a cron entry, with, say, 15 22 * * * /some/path/regen.sh
, but not
that one either, choose your own.
It also take as arguments the services to reload. (With the service command, that may, or may not, exist, on your OS.) It also uses sudo to run the commands, but you may tinker with the end of that script to fit your needs.
This is a nagios plugin that will check that all the certificates in the public directory have an expiration date of at least $warning days in the future, default 15, give a warning if they have less, and become critical if it goes below $critical days, default 10.
I am a FreeBSD user, so, all this works just fine on FreeBSD, YMMV.
The regen.sh
script is ran from cron, and it runs acme-tiny. The
acme-tiny script's shebang contains /usr/bin/env python
so python must
either be in cron's PATH, or you must change acme-tiny's shebang to point to
the correct python PATH. Also, it runs sudo
, so, sudo must be in the PATH.