(If you are unfamiliar with the abbreviation “TLS“: it is the successor to SSL but works one the same principle.)
The internet is the best invention since sliced bread but it has become an evil place more than ever. We are dealing with script kiddies, out-of-control secret services and organized crime on a large scale. It is completely out of the question to run any unencrypted services over the internet. I even consider any password immediately wasted that went through the internet in plain text. So we need to create an encryption key and a certificate for Postfix (SMTP), Dovecot (IMAP/POP3) and Roundcube (Webmail/HTTPS).
You may argue that using encrypted connections between a users’s computer and the mail server is futile. After all the email is forwarded to other mail servers in plain text. While this may be true for some mail servers most administrators strive to enable TLS for the server-to-server communication, too. You cannot rely on it for confidential correspondence but it’s better than nothing. Fun fact: not very long ago a couple of large german freemail providers founded an “email made in Germany” alliance. Guess what cool thing they did to make the world a better place… they enabled TLS. 🙂
Caveat: do not use different certificates for Postfix and Dovecot. At least the MacOS mail client would refuse your connection with confusing error messages.
What makes mail clients trust a certificate?
Just like with your favorite web browser there is a list of “trusted” certificate authorities in the world. Yes, your browser trusts companies you probably have never heard of. And so does your mail client. Decades ago companies managed to convince browser developers to make their browser trust all certificates that were cryptographically signed by them. Those certificates were technically the same as self-signed certificates. They just had a signature that was created by a computer of a certain company. Most of the time there isn’t even a human checking the signing request. I consider today’s certification system broken.
In the previous tutorial for Debian Jessie I had a lengthy comparison of self-signed certificates, company PKIs, LetsEncrypt and paid certificates. Let’s cut it short – we will use LetsEncrypt. There is no reason to pay the certificate mafia money any more. Why do I consider them mafia-like? Because it is plain wrong to exchange money for trust. And the recent history of awkward failures shows that they deserve no trust. Even my preferred good old certificate authority StartSSL (because they issued certificates for free) has failed so badly that all major browsers now consider their certificates untrustworthy. Just recently they even shut down their business.
LetsEncrypt is a not-for-profit project run by a Californian corporation called ISRG (Internet Security Research Group). They managed to set up an infrastructure that finally allows everyone in the world to get trusted certificates for free. Their authority’s certificate is nowadays installed as trusted by most web browsers and other software – like mail clients. If your boss asks… their certificates are technically just as secure as a self-signed certificates. And, no, there is no reason to ever pay for a certificate again. Why do others still do that? Likely because they are victims of marketing and FUD.
The certificate will be used in three places:
- the webmail interface (driven by Apache)
- Postfix (for authentication during SMTP communication with your users)
- Dovecot (for authentication during IMAP communication)
Preparing the Apache web server for HTTP
Let’s start with the Apache. Your server may serve multiple name-based virtual hosts. That just means that your web server can distinguish which files it is supposed to send to the client depending on the host name used in the URL. As an example I will assume that you want to offer a host name webmail.example.org to your users. Of course your server will have another name in a domain that you control. I will use that example throughout the tutorial though and keep that name printed in bold letters to remind you that you have to use your own host name everywhere.
First you need a web root directory for that host name:
mkdir /var/www/webmail.example.org
Next you will have to create a virtual host configuration file. Apache on Debian uses a neat system to manage virtual hosts:
- /etc/apache2/sites-available/*.conf contains two configuration files by default. “000-default.conf” is a HTTP virtual host and “default-ssl.conf” is a HTTPS virtual host configuration. You can create arbitrary files here. Apache will not consider them automatically.
- /etc/apache2/sites-enabled/*.conf contains symbolic links (“symlinks”) pointing to configuration files in the /etc/apache2/sites-available directory. Only *.conf links in this directory will be loaded by Apache.
This system allows you to enable and disable virtual hosts without having to destroy any configuration. Debian ships with the “a2ensite” (short for “apache2 enable site”) and “a2dissite” commands. In addition to some sanity checks those commands essentially create or remove symlinks between “sites-available” and “sites-enabled”.
(Note: Configuration files must have a “.conf” suffix or else they will get ignored.)
You may remove the default symlinks in /etc/apache2/sites-enabled/* unless you use them already.
Create a new virtual host configuration file /etc/apache2/sites-available/webmail.example.org-http.conf and make it contain:
<VirtualHost *:80> ServerName webmail.example.org DocumentRoot /var/www/webmail.example.org </VirtualHost>
The simple configuration makes Apache handle HTTP requests (on the standard TCP port 80) if a certain line in the request from the browser reads “Host: webmail.example.org”. So the browser actually tells your Apache web server which server name it is looking for. That allows for multiple web sites on a single IP address. (By the way: this works on HTTPS, too, nowadays, thanks to Server Name Indication.)
Enable the site:
a2ensite webmail.example.org-http
You will be told:
To activate the new configuration, you need to run: systemctl reload apache2
Do that.
Let’s check if the configuration works. Put a test file into your web root directory:
echo "Just a test" > /var/www/webmail.example.org/test
Now when you open the URL http://webmail.example.org/test in your browser you should see the text “Just a test”.
This is enough setup to make LetsEncrypt issue a certificate for you.
Getting a LetsEncrypt certificate
Debian Stretch contains the most common tool to manage LetsEncrypt certificates – certbot. Install it:
apt install certbot
To get a certificate for your domain run:
certbot certonly --webroot --webroot-path /var/www/webmail.example.org -d webmail.example.com
The first time you do that you will get asked for your email address so LetsEncrypt can send you reminders if your certificate would expire. You will also have to agree to their terms of service.
If everything worked well you should get output like:
Saving debug log to /var/log/letsencrypt/letsencrypt.log Obtaining a new certificate Performing the following challenges: http-01 challenge for webmail.example.org Using the webroot path /var/www/webmail.example.org for all unmatched domains. Waiting for verification... Cleaning up challenges Generating key (2048 bits): /etc/letsencrypt/keys/0049_key-certbot.pem Creating CSR: /etc/letsencrypt/csr/0049_csr-certbot.pem IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at /etc/letsencrypt/live/webmail.example.org/fullchain.pem. Your cert will expire on 2018-04-01. To obtain a new or tweaked version of this certificate in the future, simply run certbot again. To non-interactively renew *all* of your certificates, run "certbot renew" - If you like Certbot, please consider supporting our work by: Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate Donating to EFF: https://eff.org/donate-le
Do you wonder what actually happened? Well, the Certbot created the private/secret key (that only your server must know). It then placed a certain file into /var/www/webmail.example.org/.well-known/… and had it verified by the LetsEncrypt service that visited your web site. That was proof enough that you own the domain (because you are in control of the DNS zone) and that you have access to the web server.
Apache and HTTPS
Unencrypted HTTP communication is not an option any more nowadays. And now that you have a certificate let’s add a virtual host that can handle HTTPS.
Create a new file /etc/apache2/sites-available/webmail.example.org-https.conf containing:
<VirtualHost *:443> ServerName webmail.example.org DocumentRoot /var/www/webmail.example.org SSLEngine on SSLCertificateFile /etc/letsencrypt/live/webmail.example.org/fullchain.pem SSLCertificateKeyFile /etc/letsencrypt/live/webmail.example.org/privkey.pem </VirtualHost>
This virtual host configuration looks suspiciously similar to the HTTP virtual host above. It just listens on port 443 (standard port for HTTPS) instead of port 80. It enables the “SSLEngine” that handles encryption and gets information about the certificate for your web server (that is shown to your users) and the private key (that the web servers uses to decrypt the user’s communication).
Enable the SSL module in Apache:
a2enmod ssl
Then enable the virtual host for HTTPS:
a2ensite webmail.example.org-https
And reload the configuration again:
systemctl reload apache2
Now when you point your web browser to https://webmail.example.org your browser should tell you that it trusts the web site’s certificate:
(Yes, sorry, this is not webmail.example.org. But I do not own the example.org domain and thus cannot get a valid certificate for it. This is my own site.)
So should you keep the HTTP virtual host? Yes. Use it to redirect your users to the HTTPS site if they forget to put “https://” in front of the URL. And HTTP is always required for LetsEncrypt. So what is the solution?
Automatic renewal
Getting a certificate is only half the battle. LetsEncrypt’s certificates expire after 90 days. So renewing certificates automatically and in time is vital. The certbot package adds an automatic cron job in /etc/cron.d/certbot for that purpose. It is run twice a day and after a random delay (so that the LetsEncrypt service is not getting too many requests at the same time) checks if certificates are due for renewal. That is done by calling “certbot -q renew”. The “-q” stands for “quiet” and prevents that you get two emails per day telling you what the certbot did.
There is one puzzle piece missing though. Even when the renewal worked it will only update the certificate files. But the software components – Postfix, Dovecot and Apache – will not notice the change. So we need to add a so called post-hook to certbot that triggers a restart of all processes thereafter.
Create a simple shell script in /usr/local/bin/certbot-post-hook that contains:
#!/bin/sh service postfix restart 2>/dev/null service dovecot restart 2>/dev/null service apache2 restart 2>/dev/null
Make that script executable:
chmod u+x /usr/local/bin/certbot-post-hook
Run it as a test:
/usr/local/bin/certbot-post-hook
It will not output anything. It should just run without error and restart all three services that will use the certificate. You will need to add that script by running “certbot renew” with the option “–post-hook /usr/local/bin/certbot-post-hook”.
Now it depends on whether the renewal is triggered by cron or by systemd. If you are using Debian Jessie or Debian Stretch your system uses systemd. Certbot handles both cases but there is a caveat that may make add the mentioned option in the wrong place. Check out the /etc/cron.d/certbot file:
0 */12 * * * root test -x /usr/bin/certbot -a \! -d /run/systemd/system && perl -e 'sleep int(rand(3600))' && certbot -q renew
The highlighted part means that the cron job checks if you are using systemd. If you do it would not run the renewal here and leave the work for systemd. In this case you may want to edit the /lib/systemd/system/certbot.service file instead:
[Unit] Description=Certbot Documentation=file:///usr/share/doc/python-certbot-doc/html/index.html Documentation=https://letsencrypt.readthedocs.io/en/latest/ [Service] Type=oneshot ExecStart=/usr/bin/certbot -q renew PrivateTmp=true
You may be tempted to simply change the ExecStart line here. But with the next update of certbot your changes will be overwritten. Instead copy that file to /etc/systemd/system/
cp /lib/systemd/system/certbot.service /etc/systemd/system/
Change the ExecStart line to:
ExecStart=/usr/bin/certbot -q --post-hook /usr/local/bin/certbot-post-hook renew
Now reload systemd:
systemctl daemon-reload
You can also verify your overriden service using:
systemctl cat certbot
To be sure that the renewal will work you can simulate the process by running
certbot --dry-run --post-hook /usr/local/bin/certbot-post-hook renew
Well done. You have implemented LetsEncrypt for all your services now. Let’s go on.
a2enmod webmail.example.org-https -> a2ensite webmail.example.org-https
a2enmod ssl
Thanks, fixed.
I would probably also run a2enmod before a2ensite, as you otherwise get
Reloading Apache httpd web server: apache2 failed!
The apache2 configtest failed. Not doing anything. … (warning).
Output of config test was:
AH00526: Syntax error on line 4 of /etc/apache2/sites-enabled/webmail.example.org-https.conf:
Invalid command ‘SSLEngine’, perhaps misspelled or defined by a module not included in the server configuration
Action ‘configtest’ failed.
Right, thanks. Just changed the order.
Thumbs up for using the “http-01” challenge 🙂
Not a choice anymore. TLS-SNI validation is no longer allowed for issuing new LetsEncrypt certificates.
I’m confused. Is there anything wrong with http-01?
No there is nothing wrong with http-01 but TLS-SNI-01 is broken.
https://community.letsencrypt.org/t/2018-01-09-issue-with-tls-sni-01-and-shared-hosting-infrastructure/49996
Why not to use –post-hook option of certbot ?
I mean in the cron job.
I mentioned that. Or how do you mean?
Ah, sorry. I haven’t noticed that the new certbot creates automatic cron job.
I think you also want to request `imap.example.org` in this part of the guide, as this imap address is used later in the guide (and “required” for external mail clients to avoid SSL warnings).
In addition `smtp.example.org` might be worth adding as well (as commonly used).
I think there’s a step I’m missing… going to example.org/test yields “this is just a test”, but the site cannot be found for “webmail.example.org/test”. Do I need to make some adjustments to my domain settings first?
I use webmail.example.org in my examples everywhere. Do you use both “webmail.example.org” and “example.org” in your configuration?
My configuration is as in the first “Preparing the Apache web server for HTTP” section:
ServerName webmail.example.org
DocumentRoot /var/www/webmail.example.org
I’ve removed the other symlinks in /etc/apache2/sites-enabled as you mentioned (only 000-default.conf was symlinked there).
example.org is replaced by my domain name. I’ve added “webmail.example.org” as a subdomain in the interface of my hoster (1&1), so now I can reach /var/www/webmail.example.org via “webmail.example.org”. However I can still reach it from example.org as well?
Thanks for your quick reply!
Enabling 000-default.conf with “a2ensite 000-default” resulted in “example.org” displaying something else (the welcome screen). I’m a bit mystified why in the absence of this symlink it would simply show what’s on the “webmail.example.org” subdomain…
And to solve my own question: from the linked Apache document
If no matching ServerName or ServerAlias is found in the set of virtual hosts containing the most specific matching IP address and port combination, then the first listed virtual host that matches that will be used.
The certbot command seems to be stuck on running the post-hook
aving debug log to /var/log/letsencrypt/letsencrypt.log
——————————————————————————-
Processing /etc/letsencrypt/renewal/webmail.example.org.conf
——————————————————————————-
Cert not due for renewal, but simulating renewal for dry run
Renewing an existing certificate
Performing the following challenges:
http-01 challenge for webmail.example.org
Waiting for verification…
Cleaning up challenges
Generating key (2048 bits): /etc/letsencrypt/keys/0006_key-certbot.pem
Creating CSR: /etc/letsencrypt/csr/0006_csr-certbot.pem
** DRY RUN: simulating ‘certbot renew’ close to cert expiry
** (The test certificates below have not been saved.)
Congratulations, all renewals succeeded. The following certs have been renewed:
/etc/letsencrypt/live/webmail.example.org/fullchain.pem (success)
** DRY RUN: simulating ‘certbot renew’ close to cert expiry
** (The test certificates above have not been saved.)
Running post-hook command: /usr/local/bin/certbot-post-hook
However, running /usr/local/bin/certbot-post-hook works as expected
/usr/local/bin# /usr/local/bin/certbot-post-hook
Stopping Postfix Mail Transport Agent: postfix.
Starting Postfix Mail Transport Agent: postfix.
Restarting IMAP/POP3 mail server: dovecot.
Restarting Apache httpd web server: apache2.
Thanks for the great guide, I’ve been using it for years, without any problems.
Just a small hint: Since Debian 9 uses systemd, why not use “systemctl restart postfix” (and dovecot and apache2) instead of “service postfix restart”? I don’t actually like systemd, but it’s the new standard in Debian, and you already use systemctl to reload the apache2 configuration.
I believe the guide uses “systemctl”, but only in this section of the guide. Since debian still supports sysvinit, I’d rather argue to replace these instances with “service” which works with both init systems while systemctl obviously only does with systemd.
As far as I can tell, on first apply. it checks to see if there is a page at http://webmail.example.com/ as your example puts a page at http://webmail.example.com/test should that test be index.html?
Forget that!! The validation cant find the files it is hunting for, but its not index.html.. I am now guessing that the script doesn’t have the permissions to write to the www/mydomain folder.. as its returning a 404 in the validation, and there are no files other than test in there.. yet a dns must be active for me to see http://mydomain/test
Great tutorial! I used it few times (making 4 or 5 mail servers) in past 4 years.
I guess, I should put some feedback.
Try replace certbot with acme.sh, it use less resources and never ask about root privilages
The certbot needs port 80,so stop apache2 with option –pre-hook
#!/bin/sh
service nginx stop
Test:
certbot –dry-run –pre-hook /usr/local/bin/certbot-pre-hook –post-hook /usr/local/bin/certbot-post-hook renew
No, that’s not how it works. Apache keeps running on port 80 and places a challenge file into the webroot that is verified by Certbot. Look above for “well-known”.
Hi Christoph,
Thank you for the guide. Very thorough! I actually was able to set one up fully functional for my company.
I do have a question though. Regarding tls certificate for each domain, how can that be done in Postfix to securely authenticate user? Right now only one of my domain is tls enabled, others, due to the difference in domain name, don’t receive the same protection. If only they don’t show me those annoying security exception popup whenever I set an email up in a mail client, I would not be this paranoid.
Any input is much appreciated!
Yeah, training your users to ignore certificate warnings is an evil thing to do.
The usual solution is to let everybody use the mail server under the same name and not as something like mail.EACHCOMPANY.com. If the companies should not know of each other perhaps you can get another domain with an independent name like mail.ourservice.org or something like that.
Many thanks, now looking back at how other mail provider doing it, like 1and1 or godaddy, they are also using their own domain name for incoming and outgoing email server. I was totally overlooking that.
Again, great tutorial!
Hi @Chris,
I enjoy reading your detailed article. Let me thank you first for doing this and helping us. Why not use NGINX instead of Apache?
Thanks for the feedback. So… why stay with Apache…
1. It has been Apache for many years and if I change things I need to have a reason. Most mail server admins are lazy and don’t want to follow crazy ideas for no gain.
2. Apache works well with PHP (Roundcube) out of the box. Nginx needs PHP-FPM which is less trivial to set up. Nginx works very well for static pages and advanced needs like throttling or caching but less good for moderate demands that rely on PHP.
3. Sophisticated sysadmins will find it easy to move to Nginx. 🙂
Yup. I’ve been using nginx with ISPmail since the Wheezy version with zero issues. It’s not difficult at all if you’ve ever worked with nginx before (as would be the case if you have a preference for nginx over Apache in the first place). Even if you have zero experience with nginx but want to give it a try with ISPmail, it shouldn’t be a major issue.
Hi Christoph,
thanks for that guide!
Why are you still using “service” in the post-hook script?
“systemctl” FTW! 🙂
Stefan
Laziness. “service” is easier to type than “systemctl”. 🙂 And the service indirectly comes from the systemd installation anyway. At least I’m not proposing to use /etc/init.d/* any more…
The certbot command line points to /var/www/webmail.example.org but references the URL of webmail.example.com.
Hi Christoph,
Has said by Lee Bosch there is a typo in this command line :
certbot certonly –webroot –webroot-path /var/www/webmail.example.org -d webmail.example.com
it should be :
certbot certonly –webroot –webroot-path /var/www/webmail.example.org -d webmail.example.org
Hmm.. my server doesn’t seem to run the certbot-post-hook script after renewal of the certificate.
It does however simulate it when running the dry-run.
In the dry run I get the following at the end:
“Running post-hook command: /usr/local/bin/certbot-post-hook”
But looking into the logs from when it actually had to renew the certificate it just ends with:
“2018-08-25 10:36:44,140:DEBUG:certbot.renewal:no renewal failures”
No signs of running the certbot-post-hook at all.
I discovered that this was an issue, when my email clients starting complaining about the certificate being expired, so I restarted postfix manually and the issue was resolved.
No idea where to even start…?
Okay, I’ve been doing a little research.
It seems like a systemd timer is also installed, when installing certbot.
Its location is: /etc/systemd/system/timers.target.wants/certbot.timer
The timer is run twice per day and if it reaches the renewal time before the cron job (/etc/cron.d/certbot) the post-hook will never be run.
So I’ve now deleted the timer (/etc/systemd/system/timers.target.wants/certbot.timer) and will see in a couple of months, if that resolves the issue.
Hope it helps anyone with the same issue!
Source: https://github.com/certbot/certbot/issues/5034
Took me a while to figure that out, too. Those *.timer files are the “cron job equivalent” of systemd. Pretty nice actually. But you need to know that any post-hooks need to be put there.
I have updated this page to reflect the systemd part correctly.
Please provide clarification on which file I edit for the automated Let’s Encrypt to work. You advised,
“In this case you may want to edit the /lib/systemd/system/certbot.service file instead:
[Unit]
Description=Certbot
Documentation=file:///usr/share/doc/python-certbot-doc/html/index.html
Documentation=https://letsencrypt.readthedocs.io/en/latest/
[Service]
Type=oneshot
ExecStart=/usr/bin/certbot -q renew
PrivateTmp=true
You may be tempted to simply change the ExecStart line here. But with the next update of certbot your changes will be overwritten. Instead copy that file to /etc/systemd/system/
cp /lib/systemd/system/certbot.service /etc/systemd/system/cerbot.service”
The use of the word may confuses me. The former may suggest that this may be good to do. The the latter says, maybe it’s not so good to do. So, do I edit /lib/systemd/system/certbot.service or /etc/systemd/system/certbot.service for the changes not to be overwritten during updates? Please advise.
Due to a bug, certbot hangs with –post-hook if stderr is not closed:
https://github.com/certbot/certbot/issues/5424
So cerbot-post-hook should look as follows:
#!/bin/sh
service postfix restart 2>/dev/null
service dovecot restart 2>/dev/null
service apache2 restart 2>/dev/null
Thanks for the hint. I haven’t come across that yet but it can’t hurt. Just added that.
Hi all and thank you to Christoph, for these great tutorials, and to the other for the help.
If I want to host also my website on the same server, how can I create a wildcard certificate with let’s encrypt? Now let’s encrypt support the wildcard certificates.
If it’s only two servers I would suggest to just get to single certificates from LetsEncrypt.
If you really want a wildcard certificate then it’s a bit more complicated because the normal “certbot” does not support it in Debian yet. The simplest solution for me was using the Docker container/image to use the most recent certbot version.
To install Docker:
https://docs.docker.com/install/linux/docker-ce/debian/#set-up-the-repository
To get a new wildcard certificate:
docker run -it –rm –name certbot \
-v “/etc/letsencrypt:/etc/letsencrypt” \
-v “/var/lib/letsencrypt:/var/lib/letsencrypt” \
certbot/certbot certonly –server https://acme-v02.api.letsencrypt.org/directory \
-d *.my.domain -d my.domain \
–manual \
–preferred-challenges dns
You will need to create a certain DNS record in your DNS zone which is shown in the process.
For renewing the certificate I have a cron job:
@daily docker run -i –rm –name certbot -v “/etc/letsencrypt:/etc/letsencrypt” -v “/var/lib/letsencrypt:/var/lib/letsencrypt” certbot/certbot renew –server https://acme-v02.api.letsencrypt.org/directory –standalone
However renewing also requires that you update the DNS record. In your renewal config you can mention a script to run that updates your DNS record…
[renewalparams]
authenticator = manual
account = asdfhcapsofduhcnpasfvnhpadi
manual_public_ip_logging_ok = True
server = https://acme-v02.api.letsencrypt.org/directory
pref_challs = dns-01,
manual_auth_hook = /usr/local/sbin/mydomainprovider-letsencrypt.rb
pre_hook = service nginx stop
post_hook = service nginx start
The /usr/local/sbin/mydomainprovider-letsencrypt.rb script takes environment variables “CERTBOT_DOMAIN” and “CERTBOT_VALIDATION” and must do some magic to update the DNS zone. How to update the zone very much depends on how you manage your domains. Fortunately my domain hoster has an API that I can use.
Maybe I should write a seperate article about that because it took me a day to collect all that information. 🙂
Thank you Christoph for the quick answer!
Actually for a few certificates, you do not have to run the bot multiple times nor have two or more certificates. You can avoid the hassle of a wildcard by specifying the domains of your domains like this:
certbot –nginx -d mainsite.com -d http://www.mainsite.com -d secondsite.com -d sub.secondsite.com
I checked with up to 18 domains, and it created (one!) certificate which is valid for all of them. When ran again (with more domains), the bot was smart enough to detect it and ask if I wanted to (E)xpand the certificate. Complete renewal seems to be limited to once a day or so.
A wildcard certificate is probably useful only if you want to automate the creation of lots of subdomains, and if you have an API at your registrar to automate the handling of your DNS records as well.
Hi Christoph,
Thank you for your huge work on explaining all commands, it helps me a lot!
I have just one suggestion about the way you restart all processes after cert renewal. Why do not use the “/etc/letsencrypt/renewal-hooks” folder to put our post script? This way we would not have to rewrite the cron job of certbot (and of course, in case of certbot update of this cron job file, we would automatically follow the new commands to renew certs). What do you think?
Just in case, this feature is documented here: https://certbot.eff.org/docs/using.html#renewing-certificates
Thank you again for your articles 🙂
Good find. Also, it probably avoids having two concurrent cron jobs renew the certificate (as long as the stock one is not disabled)! Ie. just create `/etc/letsencrypt/renewal-hooks/post/certbot-post-hook` in place of `/usr/local/bin/certbot-post-hook` + cron.
Hi Christoph and Friends,
relatively the part concerning the generation of certificates,
Some days ago I had opened a post on LetsEncrypt forum about Prosody certs reneval procedure and “jmorahan” (and not just him) had explained to me that is never necessary to edit the certbot cron in order to add specific options, in fact, it is sufficient to execute certbot with the option you want so that it is automatically memorized and repeated at the next scheduling:
jmorahan: “If you use the –deploy-hook option when requesting the certificate originally, or when renewing it manually with –force-renewal, then the command you supply will be stored in the renewal configuration file for that certificate (in /etc/letsencrypt/renewal/) and any future certbot renew command, including the one in the default crontab or systemd timer, will run it again automatically when that certificate is renewed. You do not need to modify the crontab itself.”
And using “–deploy-hook” instead to –post-hook will run only if certificate acquisition successfully
So the first time command will become:
certbot certonly –webroot –webroot-path /var/www/webmail.example.org –deploy-hook /usr/local/bin/certbot-post-hook -d webmail.example.com
What do you think about?
This is the entire conversation on the forum: https://community.letsencrypt.org/t/prosody-xmpp-jabber-how-automatize-every-3-month-certificate-update/85022/2
Many thanks for your great guide!
Interesting. Does that change the /etc/letsencrypt/renewal/… files? Because I’m currently experimenting with rather changing the renewal configuration than the systemd service.
The official certbot documentation (see https://certbot.eff.org/docs/using.html#id23) suggests to put hook files beneath the /etc/letsencrypt/renewal-hooks/[hooktype] folder hierarchy, as this will run hooks automatically when invoking certbot.
Also, using a deploy hook instead of a post hook seems to be the better option, since a deploy hook is only run after a successful renewal, while a post hook is also run for failed renewals.
So I think /etc/letsencrypt/renewal-hooks/deploy should be the ideal spot for placing the hook file.
Thank you very much for the great guide!
Sorry, that link should actually be https://certbot.eff.org/docs/using.html#renewing-certificates
I suppose of yes, reading what jmorahan writes: “…then the command you supply will be stored in the renewal configuration file for that certificate (in /etc/letsencrypt/renewal/) and any future certbot renew command, including the one in the default crontab or systemd timer, will run…”
systemd/crontab
And again jmorahan writes: “…–post-hook is mostly useful for undoing the effects of –pre-hook. For example, if you needed to temporarily open a port in your firewall before the renewal attempt, and close it again afterwards – you would want both things to happen whether the renewal actually succeeded or not. –deploy-hook on the other hand is for things you want to do only after a successful renewal, such as reloading a mail or chat server that will use the newly renewed certificate”
If I understood your question correctly 🙂
Yes, sorry. I did not read the comment thoroughly.
Great guide thank you!
I always force everything over HTTPS in the server config and I thought you were going to as well when you said:
> Unencrypted HTTP communication is not an option any more nowadays.
I normally work with nginx so I’m not that familiar with Apache, but every successful https redirect I have tried breaks the certbot renewal. I know it might be outside the scope of the guide, but IMO if SSL is important enough to register a cert, it’s important enough to make sure all traffic goes through it.
Thanks again, it’s amazing that you have been keeping this up-to-date for so long!
The danger of commenting too early…I see you address this later.
I have been running an ISPMAIL based server for years now (Thanks again for such a great guide). In January I build a new Stretch server using the latest guide and migrated mail, etc. All was running great but I noticed today that the cert was not renewing, it was getting authentication errors of some sort (there check back was not finding the .known files). I thought it was the redirect stuff. I started editing sites-enabled/mydomain.-http.conf file and now redirect is totally broken. I swear I have put back what was originally there, reboot, restarted, etc. Now if you go to my domain, you see the default apache site, but if you go to HTTPS:mysite, you get roundcube. Has anyone else had problems with redirect in stretch?
Hi Patrick. Glad to have you in the ISPmail community. 🙂 I assume that you have a virtual host configuration in /etc/apache2/sites-enabled/… that is having precedence. The files in that directory are sorted in alphabetical order. And if no “VirtualHost” configuration really matches the exact host name your entered in the browser… then the alphabetically first entry is taken whether it matches or not. You may want to check if there is any “000-default” entry there maybe. And check if the host name is set correctly.
…Christoph
Thanks Christoph for the fast reply. Why yes there is a 000-file and in fact that is the one that has a DocumentRoot pointing to the default Apache Web page I am not getting for my site. Of course part of what has been driving me nuts is that all was working fine before. OMG, THANK YOU THANK YOU. I a2dissite 000 and BOOM! All is working. My cert if finally renewed. Life is good. A note for others, one of the big problems I kept fighting here is that I would make a change on the server and then go test on a client only to see no difference. When you realize that NOTHING is now pointing to the file you see on screen it dawns on you to **CLEAR YOUR CACHE** LOL. Again thanks for your help and for the wonderful guide.
Glad you figured it out. Such things can be annoying.