summaryrefslogtreecommitdiff
path: root/content/blog/2020/email-server-extras.md
diff options
context:
space:
mode:
Diffstat (limited to 'content/blog/2020/email-server-extras.md')
-rw-r--r--content/blog/2020/email-server-extras.md225
1 files changed, 225 insertions, 0 deletions
diff --git a/content/blog/2020/email-server-extras.md b/content/blog/2020/email-server-extras.md
new file mode 100644
index 0000000..cf3b597
--- /dev/null
+++ b/content/blog/2020/email-server-extras.md
@@ -0,0 +1,225 @@
++++
+title = "Setting up an email server in 2020 with Dovecot and OpenSMTPD: extras"
++++
+
+#
+
+This sequel to my earlier [guide](/blog/2020/email-server/) discusses
+extra tips and tricks to extend your email setup.
+This page will be updated continuously as I come up with ideas.
+
+Last updated 2020-04-27.
+
+
+## General
+
+### Multiple domains
+
+You can generalize your setup to handle multiple domains
+with very little effort. In the following,
+I'll assume that your two domains are called `foo.com` and `bar.com`.
+
+
+#### DNS records
+
+There should be MX, SPF, DKIM and DMARC records for both domains,
+as explained in the previous guide. Fortunately, all these records
+can have completely identical contents for both domains!
+
+However, it remains essential that the mail server's mailname
+and reverse DNS domain name match up exactly,
+so you should create MX records with that in mind.
+Therefore, if the email server for both domains has `mx1.foo.com`
+as reverse DNS name, the MX records should look like this:
+```sh
+foo.com. MX 42 mx1.foo.com.
+bar.com. MX 42 mx1.foo.com.
+```
+This is perfectly valid: the only thing that matters is that
+what your SMTP server calls itself agrees with what reverse DNS
+says that the server is actually called.
+
+
+#### Dovecot
+
+To make Dovecot aware of multiple domains,
+you only need to update the `/etc/dovecot/users` file
+to add accounts for both domains.
+However, in the original guide, I said to only write `user`
+in the file, without the `@foo.com`, for an address `user@foo.com`.
+Unsurprisingly, that isn't an option when handling multiple domains,
+so you must put the full address in `/etc/dovecot/users`.
+
+Then update `/etc/dovecot/dovecot.conf` to reflect that change,
+by replacing `%n` with `%u` in `username_format`:
+```sh
+userdb {
+ driver = passwd-file
+ args = username_format=%u /etc/dovecot/users
+ override_fields = uid=vmail gid=vmail home=/home/vmail/%d/%n
+}
+```
+Also note the change in the `home` setting:
+the inbox of a user `user@foo.com` will now be stored
+in `/home/vmail/foo.com/user`.
+That's all you need to change.
+
+
+#### OpenSMTPD
+
+For OpenSMTPD, create a new file `/etc/smtpd/domains`,
+and in there put all desired domains on their own line:
+```sh
+foo.com
+bar.com
+```
+And as I mentioned when discussing the DNS records,
+you should check that `/etc/smtpd/mailname` agrees
+with your server's reverse DNS.
+
+Then, in the main configuration file, tell OpenSMTPD to
+use the new domains file when deciding whether to accept an message,
+by declaring a new table and changing the `match` line for inbound mail:
+```sh
+table domains "/etc/smtpd/domains"
+# ...
+match from any for domain <domains> action "RECV"
+```
+In theory, that's it! You should now have a working
+multi-domain email server.
+
+
+
+## Dovecot
+
+### Catchall inbox
+
+In Dovecot, you can create a catch-all inbox that will accept all
+emails sent to your domain that don't match anyone in `/etc/dovecot/users`.
+Just add another `userdb` block *after* the first:
+```sh
+userdb {
+ driver = static
+ args = uid=vmail gid=vmail home=/var/vmail/catchall allow_all_users=yes
+}
+```
+The `static` driver means there is no table file:
+all configuration is directly within this `userdb` block.
+If we don't specify `allow_all_users=yes`, then Dovecot
+will check whether users exist using the `passdb` table,
+and will conclude that the recipient is invalid.
+
+
+
+
+## OpenSMTPD
+
+### Client certificates
+
+You can configure OpenSMTPD to request a client certificate
+for sending emails, in addition to or as a subsitute for passwords.
+In this guide I'll use it for subsitution.
+
+This is especially useful if you created a catch-all inbox,
+since this approach allows you to send messages from arbitrary names,
+as long as the client can present a valid certificate.
+It also allows you to get rid of the awkward duplication
+of user credentials between Dovecot and OpenSMTPD.
+
+
+#### Creating certificates
+
+We need to start with some cryptography to create and verify certificates.
+I recommend that you do all of this on your trusted *client* device,
+and only copy the necessary files to the server later.
+
+DISCLAIMER:
+All the keys and certificates that we'll generate in this section are
+for **private use** only, to handle a small number of trusted clients.
+I'm not a cryptography expert, so you should **not** listen to me
+for large-scale systems that may involve untrusted devices.
+
+The first step is to set up a private Certificate Authority (CA),
+which issues the client certificates and can be used to verify them.
+Start by generating an RSA private key,
+which you should store in a safe place and not share with anyone:
+```sh
+$ openssl genrsa -out mailca.key 2048
+```
+Extract a public certificate from this key as follows.
+Because we're lazy, we give it a lifetime of 36500 days:
+```sh
+$ openssl req -new -x509 -days 36500 -key mailca.key -out mailca.crt
+```
+When running this command, OpenSSL will ask you some questions
+about who this certificate is intended for.
+Since this is for personal use, your answers don't matter,
+so just use the defaults.
+Some fields (I think only *Country Name* and *Organization Name*)
+cannot be empty, but the others can.
+
+Moving on to the client, once again generate an RSA private key:
+```sh
+$ openssl genrsa -out mailclient.key 2048
+```
+From this private key, create a Certificate Signing Request (CSR)
+as follows, where you'll be asked the same questions as before:
+```sh
+$ openssl req -new -key mailclient.key -out mailclient.csr
+```
+By feeding this CSR to the CA, we can create a signed client certificate
+that can be verified using the CA's public certificate.
+```sh
+$ openssl x509 -req -in mailclient.csr -out mailclient.crt \
+ -days 36499 -CA mailca.crt -CAkey mailca.key
+```
+If you want to create multiple distinct client certificates,
+just repeat the last few steps for each one.
+
+
+#### Server configuration
+
+OpenSMTPD needs to verify the validity of client certificates
+using the CA's public certificate, so you should copy that
+to somewhere on the server, e.g. `/etc/smtpd/mailca.crt`,
+and declare it to OpenSMTPD by adding this near the top of the file:
+```sh
+ca "mailca" cert "/etc/smtpd/mailca.crt"
+```
+Then replace the entire configuration for outbound mail as follows.
+Note that this removes SMTPS support, leaving only STARTTLS,
+and that it also removes the need to enter a password:
+```sh
+# Outbound
+listen on eth0 port 587 tls-require verify pki "example.com" ca "mailca" filter "rspamd" tag "VALID"
+action "SEND" relay srs
+match from any tag "VALID" for any action "SEND"
+```
+The magic word here is "`verify`", which tells OpenSMTPD
+to ask for a client certificate and to verify it using the given CA.
+The `tag "VALID"` at the end is to clarify that all emails
+that successfully pass through the first line are from trusted senders,
+because they presented a valid client certificate.
+
+
+#### Client configuration
+
+Now you won't be able to send emails if your client doesn't
+present its certificate to the server!
+Unfortunately, not all mail clients support this; personally
+I use [Thunderbird](https://www.thunderbird.net/) with success.
+I won't include any client-specific configuration here,
+but I will say this:
+
+For some clients (like Thunderbird), you'll have an easier time
+importing your client certificate if you encode it in the
+[PKCS #12](https://en.wikipedia.org/wiki/PKCS_12) storage format:
+```sh
+$ openssl pkcs12 -export -in mailclient.crt -inkey mailclient.key \
+ -certfile mailca.crt -out mailclient.pfx
+```
+OpenSSL will ask you to set a password, which you'll need to
+enter again when importing the certificate into the client.
+
+
+