132 lines
5.8 KiB
Text
132 lines
5.8 KiB
Text
---
|
||
title: TLS certificate
|
||
lastUpdated: 2025-11-01
|
||
slug: ispmail-trixie/tls-certificate
|
||
sidebar:
|
||
order: 158
|
||
---
|
||
|
||
import StepListReceive from "../../../components/StepListReceive.astro";
|
||
import { Aside } from "@astrojs/starlight/components";
|
||
|
||
<StepListReceive currentStep={2} />
|
||
|
||
Your mail server can't work properly without a valid TLS certificate. It will be used in three places:
|
||
|
||
1. the **webmail** interface (driven by the Apache web server)
|
||
2. **Postfix** (to encrypt SMTP communication with other mail servers on the internet where possible)
|
||
3. **Dovecot** (to encrypt IMAP/POP3 communication)
|
||
|
||
Your mail server will be able to host email addresses for many domains. But a TLS certificate is usually issued for a
|
||
single [FQDN](https://en.wikipedia.org/wiki/Fully_qualified_domain_name) like `mail.example.org`. That _common name_ is
|
||
an important part of the certificate. It must match the name your users use to talk to the server.
|
||
|
||
**Correct**: Your mail server is addressed as `mail.example.org`. The TLS certificate was also issued to
|
||
`mail.example.org`.
|
||
|
||
**Wrong**: Your mail server is addressed as `smtp01.example.com`. But the TLS certificate was issued to
|
||
`mail.example.org`.
|
||
|
||
So choose an FQDN for your mail server. For example I use `webmail.workaround.org` for my personal server.
|
||
|
||
## Certbot
|
||
|
||
You already have the `certbot` software and the `apache2` web server installed. Requesting a certificate from Let's
|
||
Encrypt is as simple as running the next command.
|
||
|
||
<Aside type="danger" title="Important">
|
||
|
||
Please replace `mail.example.org` by the FQDN you chose.
|
||
|
||
</Aside>
|
||
|
||
```sh title="Run this on your server"
|
||
certbot --apache --register-unsafely-without-email --agree-tos -d mail.example.org
|
||
```
|
||
|
||
<details class="collapsible">
|
||
<summary>Click here to learn what the options mean…</summary>
|
||
|
||
- **--apache**: Use the [HTTP challenge](https://letsencrypt.org/docs/challenge-types/) to verify that you are actually
|
||
in control of the FQDN. The certbot plugin will add some configuration to intercept HTTP requests to
|
||
`/.well-known/acme-challenge/…` on your web server. This is a fully automatic process that does not even have to stop
|
||
your web server.
|
||
- **--register-unsafely-without-email**: Do not ask for an email address to send to Let's Encrypt. Before June 2025
|
||
Let's Encrypt used that address to inform you if your certificate is about to expire and the automatic renewal failed.
|
||
Nowadays they do not need an email any more. But for historical reasons they still ask for it by default.
|
||
- **--agree-tos**: Confirm that you have read Let's Encrypt's terms and conditions. Let's be honest – nobody reads that.
|
||
- **-d**: The domain that the certificate will be issued to. This has to be the exact FQDN of your server.
|
||
|
||
</details>
|
||
|
||
The output should look like:
|
||
|
||
```
|
||
Saving debug log to /var/log/letsencrypt/letsencrypt.log
|
||
Requesting a certificate for mail.example.org
|
||
|
||
Successfully received certificate.
|
||
Certificate is saved at: /etc/letsencrypt/live/mail.example.org/fullchain.pem
|
||
Key is saved at: /etc/letsencrypt/live/mail.example.org/privkey.pem
|
||
This certificate expires on 2025-11-22.
|
||
These files will be updated when the certificate renews.
|
||
Certbot has set up a scheduled task to automatically renew this certificate in the background.
|
||
|
||
Deploying certificate
|
||
Successfully deployed certificate for mail.example.org to /etc/apache2/sites-available/000-default-le-ssl.conf
|
||
Congratulations! You have successfully enabled HTTPS on https://mail.example.org
|
||
|
||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||
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
|
||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||
```
|
||
|
||
<details class="collapsible">
|
||
<summary>Click here to learn which files have been created…</summary>
|
||
|
||
In /etc/letsencrypt/live/**mail.example.org** you will find a couple of files now:
|
||
|
||
- **cert.pem**: the certificate file
|
||
- **chain.pem**: the _chaining_ or _intermediate_ certificate. This certificate provides information how the LetsEncrypt
|
||
certificates are linked to other known certificate authorities. It is generally a good idea to always send this
|
||
certificate along with your own for clients who may not know LetsEncrypt properly yet.
|
||
- **fullchain.pem**: this file contains a concatenation of the _cert.pem_ and the _chain.pem_. This is the preferred
|
||
file to use when a piece of software asks where to find the _certificate_.
|
||
- **privkey.pem**: the private key file. Keep it secret.
|
||
|
||
Well, actually those are not files but _symbolic links_ pointing to the "archive" directory. But don't worry about that.
|
||
|
||
</details>
|
||
|
||
## Renewal
|
||
|
||
Your new certificate is only valid for 3 months. Fortunately the renewal is happening automatically. A _systemd timer_
|
||
checks your certificate frequently and triggers a renewal one month before it expires.
|
||
|
||
It is important that services that use the certificate load the new certificate after an automatic renewal. This shell
|
||
command will create a file `/etc/letsencrypt/cli.ini` that handles it:
|
||
|
||
```sh title="Run this on your server"
|
||
echo > /etc/letsencrypt/cli.ini "post-hook = systemctl reload postfix dovecot apache2"
|
||
```
|
||
|
||
Perfect. You won't have to worry about the certificate again.
|
||
|
||
<details class="collapsible">
|
||
<summary>Click here to learn how the renewal works…</summary>
|
||
|
||
These commands will show you the definition and status of the timer and the renewal service:
|
||
|
||
```sh title="Run this on your server"
|
||
systemctl status certbot.timer
|
||
systemctl cat certbot.timer
|
||
systemctl status certbot.service
|
||
systemctl cat certbot.service
|
||
```
|
||
|
||
_Systemd timers_ are similar to cron jobs. They require more work to set up but have some nice features and make you
|
||
look cooler.
|
||
|
||
</details>
|