2024-11-19 18:37:47 +00:00
|
|
|
+++
|
|
|
|
date = '2024-11-19T16:29:01Z'
|
|
|
|
draft = true
|
|
|
|
title = 'How to Set up a Mail Server on Alpine Linux with Postfix and Dovecot'
|
2024-11-20 21:24:28 +00:00
|
|
|
tags = ['mail server', 'alpine linux', 'postfix', 'dovecot']
|
2024-11-19 18:37:47 +00:00
|
|
|
+++
|
|
|
|
|
|
|
|
# About mail servers
|
|
|
|
|
|
|
|
Simply put, a mail server sends and receives email. When `ruby@protonmail.com` emails `klaasje@gmail.com`, Protonmail's
|
|
|
|
mail server's <abbr title="Mail Transfer Agent">MTA</abbr> sends the email to Google's mail server's MTA. Google's
|
|
|
|
MTA then passes the email on to Google's <abbr title="Mail Delivery Agent">MDA</abbr>, which is responsible for storing
|
|
|
|
the email. MDAs also run <abbr title="Internet Message Access Protocol">IMAP</abbr> or <abbr
|
|
|
|
title="Post Office Protocol 3">POP3</abbr> servers so you can read your emails and send emails with an email client.
|
|
|
|
IMAP and POP3 are protocols for email retrieval over [TCP/IP](https://en.wikipedia.org/wiki/Internet_protocol_suite).
|
|
|
|
For sending email, you would use [<abbr
|
|
|
|
title="Simple Mail Transfer Protocol">SMTP</abbr>](https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol).
|
|
|
|
|
|
|
|
Or visualise it like this:
|
|
|
|
|
|
|
|
Ruby's email client via SMTP -> Protonmail's MTA -> Google's MTA -> Google's MDA -> Klaasje's email client via IMAP
|
|
|
|
|
|
|
|
A mail server is software which can be run on any computer, including yours. You can host a mail server on a server you
|
|
|
|
already own that is hosting other services, so long as those other services aren't using any of the [mail
|
2024-11-19 20:51:30 +00:00
|
|
|
ports](#unblock-your-ports).
|
2024-11-19 18:37:47 +00:00
|
|
|
|
2024-11-20 01:25:36 +00:00
|
|
|
## Why run my own mail server?
|
|
|
|
|
|
|
|
I'll cut to the chase: the main reason why you'd want to run your own mail server is for related reasons of privacy and
|
|
|
|
digital sovereignty. For privacy benefits, as much as you have control over your server, you can protect your email
|
|
|
|
from the eyes of prying server admins (given that you yourself are the admin). Even for email providers that market
|
|
|
|
themselves around privacy such as Protonmail, rely on trust that Proton are not reading your unencrypted incoming
|
|
|
|
email. This is not an issue exclusive to any particular mail provider; if information arrives unencrypted at a server,
|
|
|
|
those with access to the server (i.e. administrators) can read that information, simple as. And as nice as it would be
|
|
|
|
if everyone used GPG end-to-end encryption for email, the vast majority of emails people receive are not end-to-end
|
|
|
|
encrypted, and entirely legible to the mail servers involved. If you're not exchanging <abbr
|
|
|
|
title="End-to-End Encrypted">E2EE</abbr> email, you can't mitigate the fact that your exchange is entirely legible to
|
|
|
|
the mail server of the person you're corresponding with, but you can at least eliminate your anxieties about the mail
|
|
|
|
server you yourself are using.[^server_trust]
|
|
|
|
|
|
|
|
Running your own mail server also allows you to implement things your way, with the features you want. For instance,
|
|
|
|
[you can run a sieve filter for encrypting all incoming mail with a user's public GPG
|
2024-11-20 01:33:30 +00:00
|
|
|
key](https://www.grepular.com/Automatically_Encrypting_all_Incoming_Email); for obvious reasons, public (as in, open to
|
|
|
|
public sign-up) mail servers that implement sieve do not allow users to create their own executables for sieve filters.
|
2024-11-20 01:25:36 +00:00
|
|
|
|
|
|
|
Hosting your own mail server is not something I would universally recommend to people. While I'm very much against
|
|
|
|
"nothing to hide, nothing to fear", a combination of that factor alongside a low state threat model (i.e. there is
|
|
|
|
little state interest in you, domestic or foreign), a lack of relevant knowledge, and a lack of interest in managing
|
|
|
|
your own server/learning how to, likely make self-hosting email not a reasonable privacy suggestion.
|
|
|
|
|
|
|
|
When you host your own mail server, you are responsible for securing the server. If you entrust Google with your email,
|
|
|
|
you can at least know that your email is secure, though not private; Google will hire people with the relevant
|
|
|
|
knowledge and skills to secure a mail server. If you are not confident in your ability to do this and not interested in
|
|
|
|
learning, you may want to find another solution.
|
|
|
|
|
2024-11-20 21:24:28 +00:00
|
|
|
There are also existing solutions that aim to "simplify" the process of managing a mail server; there have always been
|
|
|
|
plenty of services offering mail server hosting which is managed for you, the customer, and there are also projects
|
|
|
|
like [Mailcow](https://mailcow.email/), which is an attempt to make a user-friendly distributable mail server stack
|
|
|
|
based on Docker. It has a web GUI you can use to configure your mail server. This may be an option for people who value
|
|
|
|
digital sovereignty but don't want to get their hands dirty with config files. I only mention this as something you may
|
|
|
|
want to look into; I have never used Mailcow and cannot recommend it personally.
|
|
|
|
|
2024-11-19 18:37:47 +00:00
|
|
|
# Why this tutorial?
|
|
|
|
|
|
|
|
There are many tutorials on the internet about how to set up a mail server. I don't claim that mine is particularly
|
|
|
|
better than anyone else's; I'm mostly writing this for my own reference so that I can recreate my own setup on new
|
|
|
|
machines.
|
|
|
|
|
|
|
|
There are existing
|
|
|
|
[mail server tutorials for Alpine Linux](https://wiki.alpinelinux.org/wiki/Hosting_services_on_Alpine#Mail), including
|
|
|
|
ones for Postfix and Dovecot. This tutorial aims to be "monolithic" (i.e. covers the entire mail server setup with all
|
|
|
|
its components), making it easier to follow without trying to follow different tutorials that may not be 100%
|
|
|
|
compatible with each other, and to be adapted to my own specific use-cases, which may not be yours.
|
|
|
|
|
|
|
|
I am hugely indebted to [LinuxBabe's mail server tutorial for
|
|
|
|
Ubuntu](https://www.linuxbabe.com/mail-server/setup-basic-postfix-mail-sever-ubuntu), which is actually what I followed
|
|
|
|
to set up my own server. Essentially, this tutorial could be thought of as an Alpine Linux adaptation of LinuxBabe's
|
|
|
|
tutorial. If you want to set up an Ubuntu or Debian mail server, I recommend following LinuxBabe's tutorial, which is
|
|
|
|
written very clearly and is easy to follow.
|
|
|
|
|
|
|
|
The mail server will be composed of the following software:
|
|
|
|
|
|
|
|
<!-- Using an html table for colspan & rowspan -->
|
|
|
|
<table>
|
|
|
|
<tr>
|
|
|
|
<th>Component</th>
|
|
|
|
<th colspan="2">Software</th>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td>Mail transfer agent</td>
|
|
|
|
<td colspan="2">Postfix</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td>Mail delivery agent</td>
|
2024-11-20 03:03:19 +00:00
|
|
|
<td colspan="2">Dovecot</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td>DKIM authentication and signing</td>
|
|
|
|
<td colspan="2">OpenDKIM</td>
|
2024-11-19 18:37:47 +00:00
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td>Spam filter</td>
|
|
|
|
<td rowspan="2">Amavis</td>
|
|
|
|
<td>SpamAssassin</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td>Antivirus</td>
|
|
|
|
<td>ClamAV</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td>MDA server-side filtering</td>
|
|
|
|
<td colspan="2">Pigeonhole</td>
|
|
|
|
</tr>
|
|
|
|
</table>
|
|
|
|
|
|
|
|
Postfix will be our SMTP server, and Dovecot will run an IMAP server for us.
|
|
|
|
|
|
|
|
Postfix and Dovecot are required for the minimum of what you'd expect from a working mail server (i.e. a user can log
|
|
|
|
in through a standard SMTP/IMAP/POP3 email client, read their emails, and send emails). The rest is optional and
|
|
|
|
modular, i.e. you can opt to have e.g. Pigeonhole but not Amavis.
|
|
|
|
|
|
|
|
We will end up with a small-scale mail server running on Alpine Linux with one domain, and we will use Unix user
|
2024-11-20 02:12:44 +00:00
|
|
|
accounts as mail accounts. We will only set up IMAP, not POP3.
|
2024-11-19 18:37:47 +00:00
|
|
|
|
|
|
|
This tutorial was written for Alpine Linux 3.20.3, though will most likely work on other versions too.
|
|
|
|
|
|
|
|
This tutorial assumes no prior knowledge about mail servers.
|
|
|
|
|
|
|
|
# You will need
|
|
|
|
|
|
|
|
## A server
|
|
|
|
|
|
|
|
Any computer will do. This tutorial is for Alpine Linux specifically.
|
|
|
|
|
|
|
|
The relevant thing to consider for your server is that port 25 (the port for sending email) is not blocked. Most <abbr
|
|
|
|
title="Virtual Private Server">VPS</abbr> hosts block port 25 because spammers commonly use VPSes to send spam, so you
|
|
|
|
will need to find one that doesn't block port 25. Some VPS hosts block port 25 by default, but will unblock it upon
|
|
|
|
request, and re-block it if they find you are spamming.
|
|
|
|
|
|
|
|
## A domain name
|
|
|
|
|
|
|
|
Self-explanatory. You need a domain name and the ability to set its DNS records.
|
|
|
|
|
|
|
|
# Before you start
|
|
|
|
|
|
|
|
## Set up your DNS records
|
|
|
|
|
|
|
|
Firstly, pick a domain for your mail server. If you're sending emails from `domain.com`, `mail.domain.com` is a common
|
|
|
|
choice.
|
|
|
|
|
|
|
|
### MX record
|
|
|
|
|
|
|
|
An MX record denotes that your domain is used to send and receive email, and tells other MTAs the domain name of your
|
|
|
|
mail server. We will use `mail.domain.com` for your MX record. For instance, my MX record looks like:
|
|
|
|
|
2024-11-20 03:00:32 +00:00
|
|
|
```dns
|
2024-11-19 18:37:47 +00:00
|
|
|
revsuine.xyz. 14400 IN MX 0 mail.revsuine.xyz
|
|
|
|
```
|
|
|
|
|
|
|
|
### Mail server records (A, AAAA, and/or CNAME)
|
|
|
|
|
|
|
|
Now you need to set a record stating the IP address of your mail server (`mail.domain.com` above). Depending on your
|
|
|
|
setup, you may want to create a CNAME record pointing to `domain.com` if the IP address of `mail.domain.com` is the
|
|
|
|
same as the IP address of `domain.com`, or an A record if the IP address is not shared with another domain.
|
|
|
|
|
|
|
|
I use a CNAME record because the IP addresses of `mail.revsuine.xyz` and `revsuine.xyz` are the same, so my record is:
|
|
|
|
|
2024-11-20 03:00:32 +00:00
|
|
|
```dns
|
2024-11-19 18:37:47 +00:00
|
|
|
mail.revsuine.xyz. 14400 IN CNAME revsuine.xyz
|
|
|
|
```
|
|
|
|
|
|
|
|
If you use an A record, your record may look something like
|
|
|
|
|
2024-11-20 03:00:32 +00:00
|
|
|
```dns
|
2024-11-19 18:37:47 +00:00
|
|
|
mail.domain.com. 14400 IN A ip.address.here
|
|
|
|
```
|
|
|
|
|
|
|
|
If you use IPv6, you should also add an AAAA record, e.g.:
|
|
|
|
|
2024-11-20 03:00:32 +00:00
|
|
|
```dns
|
2024-11-19 18:37:47 +00:00
|
|
|
mail.domain.com. 14400 IN AAAA ip:address:here::
|
|
|
|
```
|
|
|
|
|
|
|
|
### A note on my DNS records
|
|
|
|
|
|
|
|
I use one server with one IP address for hosting several services under one apex domain. For instance, my static
|
|
|
|
website is hosted at `revsuine.xyz`; my Nextcloud is hosted at `cloud.revsuine.xyz`; and my mail server is hosted at
|
|
|
|
`mail.revsuine.xyz`. To handle this setup, I've created a subdomain `master.revsuine.xyz` (you can call the subdomain
|
2024-11-19 20:51:30 +00:00
|
|
|
anything you want) with an *A record* (because your [PTR record](#ptr-record) is expected to be an A record, not a
|
2024-11-19 18:37:47 +00:00
|
|
|
CNAME record) to my server's IP address.
|
|
|
|
|
|
|
|
I set my server's hostname and PTR record to `master.revsuine.xyz`. I will also refer to this `master.revsuine.xyz`
|
|
|
|
subdomain further down when configuring Postfix.
|
|
|
|
|
|
|
|
### PTR record
|
|
|
|
|
|
|
|
A PTR record is used for "reverse DNS", or rDNS, lookup: instead of mapping a domain to an IP address, it maps an IP
|
|
|
|
address to a domain. It is not managed through your DNS manager (e.g. whomever you bought your domain name from), but
|
|
|
|
through whoever gives you your IP address. If you rent a server, be it a VPS or a dedicated server, your hosting
|
|
|
|
provider whom you rent from will be able to manage PTR records. You may have an option to add a PTR record in the
|
|
|
|
dashboard of your hosting provider, or you may have to contact their support to get a PTR record added.
|
|
|
|
|
|
|
|
For the above stated reasons, my PTR record for my single server (which hosts all my services) is `master.revsuine.xyz`.
|
|
|
|
|
|
|
|
If your hostname is `mail.domain.com`, your PTR record should be `mail.domain.com`.
|
|
|
|
|
|
|
|
## Unblock your ports
|
|
|
|
|
|
|
|
After unblocking ports from your internet provider (e.g. if your VPS host blocks outgoing port 25), make sure the
|
|
|
|
following TCP ports are open on your firewall:
|
|
|
|
|
|
|
|
| Port | Usage |
|
|
|
|
| ---- | --------------------------------- |
|
|
|
|
| 25 | SMTP |
|
|
|
|
| 143 | IMAP |
|
|
|
|
| 465 | Email message submission over TLS |
|
|
|
|
| 587 | Email message submission |
|
|
|
|
| 993 | IMAPS (IMAP over TLS) |
|
|
|
|
|
2024-11-20 02:12:44 +00:00
|
|
|
## Obtain a TLS certificate
|
|
|
|
|
|
|
|
To enable TLS encryption, you need a certificate. [Let's Encrypt](https://letsencrypt.org/) provides free TLS
|
|
|
|
certificates. To get a certificate from them, you can use certbot:
|
|
|
|
|
|
|
|
# apk add certbot
|
|
|
|
|
|
|
|
We will need a web server to use certbot. I'm going to use nginx for this guide, because nginx is what I use on my
|
|
|
|
server, but [the certbot website](https://certbot.eff.org/) has instructions for a variety of setups. If you don't
|
|
|
|
already have an nginx server, install nginx and set it up now.
|
|
|
|
|
|
|
|
Install `certbot-nginx` with:
|
|
|
|
|
|
|
|
# apk add certbot-nginx
|
|
|
|
|
|
|
|
Add the following to your nginx config (for instance, inside `http {}` in `/etc/nginx/nginx.conf`, or in a dedicated
|
|
|
|
virtual host file `/etc/nginx/http.d/mail.domain.com.conf`):
|
|
|
|
|
|
|
|
```nginx
|
|
|
|
server {
|
|
|
|
listen 80;
|
|
|
|
listen [::]:80;
|
|
|
|
server_name mail.domain.com;
|
|
|
|
|
|
|
|
root /usr/share/nginx/html/;
|
|
|
|
|
|
|
|
location ~ /.well-known/acme-challenge {
|
|
|
|
allow all;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
Replace `mail.domain.com` with the <abbr title="Fully-Qualified Domain Name">FQDN</abbr> of your mail server.
|
|
|
|
|
|
|
|
The `root` can be set to any extant directory on your system that you're happy to publish to the web. You can just make
|
|
|
|
an empty directory at `/usr/share/nginx/html`, or make this the directory of your website, etc.
|
|
|
|
|
|
|
|
Reload or restart nginx for the changes to take effect:
|
|
|
|
|
|
|
|
# rc-service nginx reload
|
|
|
|
|
|
|
|
Now run the following command to get your free TLS certificate:
|
|
|
|
|
|
|
|
# certbot certonly -a nginx --staple-ocsp --email your@email.here -d mail.domain.com
|
|
|
|
|
|
|
|
If you have several subdomains in your nginx config that you'd like covered by the same certificate, you can omit `-d
|
|
|
|
mail.domain.com` and get a certificate covering all the domains in your nginx config. On my server, I have one
|
2024-11-20 02:32:17 +00:00
|
|
|
certificate at `/etc/letsencrypt/live/revsuine.xyz/` covering my apex domain and all subdomains. If you go for a
|
|
|
|
certificate with only one domain name, e.g. for `mail.domain.com`, it will be at
|
|
|
|
`/etc/letsencrypt/live/mail.domain.com/`.
|
2024-11-20 02:12:44 +00:00
|
|
|
|
2024-11-19 18:37:47 +00:00
|
|
|
# Postfix
|
|
|
|
|
2024-11-19 20:39:10 +00:00
|
|
|
Postfix is a [mail transport agent](https://en.wikipedia.org/wiki/Message_transfer_agent) (aka SMTP server). [In its
|
|
|
|
own words](https://www.postfix.org/):
|
|
|
|
|
|
|
|
> Postfix attempts to be fast, easy to administer, and secure. The outside has a definite Sendmail-ish flavor, but the
|
|
|
|
> inside is completely different.
|
|
|
|
|
|
|
|
## Installing Postfix
|
|
|
|
|
|
|
|
On your server, install Postfix with:
|
|
|
|
|
|
|
|
# apk add postfix
|
|
|
|
|
|
|
|
You likely also want to have Postfix documentation:
|
|
|
|
|
|
|
|
# apk add postfix-doc
|
|
|
|
|
|
|
|
Verify that Postfix is installed by checking its version:
|
|
|
|
|
|
|
|
$ postconf mail_version
|
|
|
|
|
|
|
|
## Configuring Postfix
|
|
|
|
|
|
|
|
Edit `/etc/postfix/main.cf`.
|
|
|
|
|
|
|
|
You should set `myhostname` to the hostname of your server; [in my case, this is
|
2024-11-19 20:51:30 +00:00
|
|
|
`master.revsuine.xyz`](#a-note-on-my-dns-records).
|
2024-11-19 20:39:10 +00:00
|
|
|
|
|
|
|
Now set `mydomain` to the domain you intend to send email from. For instance, my email addresses are
|
|
|
|
`name@revsuine.xyz`, so `mydomain` is set to `revsuine.xyz`.
|
|
|
|
|
|
|
|
`myorigin` determines the domain name in the `From:` field of locally sent emails. So you could for instance set this
|
|
|
|
to `revsuine.xyz`.
|
|
|
|
|
2024-11-20 21:07:07 +00:00
|
|
|
Set `mydestination` to the following:
|
|
|
|
|
|
|
|
```conf
|
|
|
|
mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain
|
|
|
|
```
|
|
|
|
|
|
|
|
`mydestination` states the list of domains your machine will consider itself the destination for, e.g. if `mydomain` is
|
|
|
|
set to `revsuine.xyz` then any emails sent to `username@revsuine.xyz` will be sent to my server according to the above
|
|
|
|
configuration.
|
|
|
|
|
2024-11-19 20:39:10 +00:00
|
|
|
`maillog_file` denotes where Postfix's log file is. By default this is `/var/log/messages`; you may want to configure
|
|
|
|
Postfix to have a dedicated log file like `/var/log/postfix.log`.
|
|
|
|
|
|
|
|
You probably want to have `logrotate` rotate your Postfix log. If there isn't already such a file, you want to create
|
|
|
|
one at `/etc/logrotate.d/postfix`:
|
|
|
|
|
|
|
|
```
|
|
|
|
/var/log/postfix*.log
|
|
|
|
/var/log/mail*.log
|
|
|
|
{
|
|
|
|
daily
|
|
|
|
missingok
|
|
|
|
notifempty
|
|
|
|
rotate 7
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2024-11-20 02:32:17 +00:00
|
|
|
Add the following TLS settings, replacing `your.domain.com` with your mail server's FQDN, [or otherwise where the TLS
|
|
|
|
certificate we generated would be](#obtain-a-tls-certificate):
|
|
|
|
|
|
|
|
```conf
|
|
|
|
# Enable TLS encryption when Postfix receives incoming emails
|
|
|
|
smtpd_tls_cert_file = /etc/letsencrypt/live/your.domain.com/fullchain.pem
|
|
|
|
smtpd_tls_key_file = /etc/letsencrypt/live/your.domain.com/privkey.pem
|
|
|
|
smtpd_tls_security_level = may
|
|
|
|
smtpd_tls_loglevel = 1
|
|
|
|
smtpd_tls_session_cache_database = lmdb:${data_directory}/smtpd_scache
|
|
|
|
|
|
|
|
# Enable TLS encryption when Postfix sends outgoing emails
|
|
|
|
smtp_tls_security_level = may
|
|
|
|
smtp_tls_loglevel = 1
|
|
|
|
smtp_tls_session_cache_database = lmdb:${data_directory}/smtp_scache
|
|
|
|
|
|
|
|
# Enforce TLSv1.3 or TLSv1.2
|
|
|
|
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
|
|
|
|
smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
|
|
|
|
smtp_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
|
|
|
|
smtp_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
|
|
|
|
|
|
|
|
# only offer authentication after STARTTLS
|
|
|
|
smtpd_tls_auth_only = yes
|
|
|
|
|
|
|
|
# disable SSL compression
|
|
|
|
tls_ssl_options = NO_COMPRESSION
|
|
|
|
|
|
|
|
# Configure the allowed cipher list
|
|
|
|
smtpd_tls_mandatory_ciphers = high
|
|
|
|
smtp_tls_mandatory_ciphers = high
|
|
|
|
smtpd_tls_ciphers = high
|
|
|
|
smtpd_tls_mandatory_ciphers = high
|
|
|
|
tls_high_cipherlist = ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256
|
|
|
|
tls_preempt_cipherlist = yes
|
|
|
|
```
|
|
|
|
|
|
|
|
The allowed cipher list is from [Mailcow](https://docs.mailcow.email/manual-guides/Postfix/u_e-postfix-harden_ciphers/).
|
|
|
|
|
|
|
|
If you're using this as a personal mail server, you may not want to have a mailbox size limit, so you can set:
|
|
|
|
|
|
|
|
```conf
|
|
|
|
mailbox_size_limit = 0
|
|
|
|
```
|
|
|
|
|
|
|
|
By default, `mailbox_size_limit` is `51200000`. This number is in bytes. You can similarly set a `message_size_limit`.
|
|
|
|
|
|
|
|
Finally, here are some various hardening settings you can add to your `/etc/postfix/main.conf`:
|
|
|
|
|
|
|
|
```conf
|
|
|
|
# connections rate limit: no of connections allowed per unit
|
|
|
|
# `postconf anvil_rate_time_unit` will give the time unit; by default it's
|
|
|
|
# 60 seconds, so 600/60=10 connections allowed per second
|
|
|
|
smtpd_client_connection_rate_limit = 600
|
|
|
|
# messages rate limit, again over same time limit
|
|
|
|
smtpd_client_message_rate_limit = 60
|
|
|
|
# VRFY command used to check if an email address exists
|
|
|
|
# not needed and can be used to find spam recipients
|
|
|
|
disable_vrfy_command = yes
|
|
|
|
# servers that don't use HELO or EHLO are either not properly configured
|
|
|
|
# or sending spam usually
|
|
|
|
smtpd_helo_required = yes
|
|
|
|
smtpd_delay_reject = yes
|
|
|
|
smtpd_helo_restrictions =
|
|
|
|
permit_mynetworks,
|
|
|
|
reject_invalid_helo_hostname,
|
|
|
|
reject_unknown_helo_hostname,
|
|
|
|
permit
|
|
|
|
```
|
|
|
|
|
2024-11-19 20:39:10 +00:00
|
|
|
## Send your first email
|
|
|
|
|
|
|
|
Have the `postfix` service auto-start upon boot, and start it during this session:
|
|
|
|
|
|
|
|
# rc-update add postfix default
|
|
|
|
# rc-service postfix start
|
|
|
|
|
|
|
|
You can now send an email with the following command:
|
|
|
|
|
|
|
|
$ echo "test email" | sendmail user@externaldomain.com
|
|
|
|
|
2024-11-20 01:33:30 +00:00
|
|
|
Send this email to your email account with an external server, e.g. a Gmail account. Note that Protonmail has quite
|
2024-11-19 20:39:10 +00:00
|
|
|
stringent spam filters and this likely would be rejected by Protonmail, i.e. not even reach your spam folder.
|
|
|
|
|
|
|
|
## Configure email aliases
|
|
|
|
|
|
|
|
You can configure aliases for your mail server. Edit the `/etc/postfix/aliases`[^postfix_aliases_location] file.
|
|
|
|
|
|
|
|
You shouldn't receive mail as root, so configure `root` to have an alias to your user, e.g.
|
|
|
|
|
|
|
|
```
|
|
|
|
root: revsuine
|
|
|
|
```
|
|
|
|
|
|
|
|
You also *must* have a `MAILER-DAEMON` and `postmaster` alias present:
|
|
|
|
|
|
|
|
```
|
|
|
|
MAILER-DAEMON: postmaster
|
|
|
|
postmaster: root
|
|
|
|
```
|
|
|
|
|
|
|
|
Note how you can have referential aliases; mail to `postmaster` is aliased to `root`, which is aliased to `revsuine`,
|
|
|
|
so ultimately `revsuine` will get `postmaster`'s mail.
|
|
|
|
|
|
|
|
You can continue to populate the aliases file with whatever aliases you want.
|
|
|
|
|
2024-11-20 02:32:17 +00:00
|
|
|
## Enable Postfix submission and smtps service
|
|
|
|
|
|
|
|
To send emails from email clients, you'll need to enable Postfix's submission service so that Postfix can receive
|
|
|
|
emails to send via SMTP. Edit `/etc/postfix/master.cf` and ensure that the following lines are present:
|
|
|
|
|
|
|
|
```conf
|
|
|
|
submission inet n - n - - smtpd
|
|
|
|
-o syslog_name=postfix/submission
|
|
|
|
-o smtpd_tls_security_level=encrypt
|
|
|
|
-o smtpd_sasl_auth_enable=yes
|
|
|
|
-o smtpd_relay_restrictions=permit_sasl_authenticated,reject
|
|
|
|
-o smtpd_recipient_restrictions=permit_mynetworks,permit_sasl_authenticated,reject
|
|
|
|
-o smtp_sasl_type=dovecot
|
|
|
|
-o smtpd_sasl_path=private/auth
|
|
|
|
|
|
|
|
smtps inet n - n - - smtpd
|
|
|
|
-o syslog_name=postfix/smtps
|
|
|
|
-o smtpd_tls_wrappermode=yes
|
|
|
|
-o smtpd_sasl_auth_enable=yes
|
|
|
|
-o smtpd_relay_restrictions=permit_sasl_authenticated,reject
|
|
|
|
-o smtpd_recipient_restrictions=permit_mynetworks,permit_sasl_authenticated,reject
|
|
|
|
-o smtpd_sasl_type=dovecot
|
|
|
|
-o smtpd_sasl_path=private/auth
|
|
|
|
```
|
|
|
|
|
|
|
|
They may be commented out, or partially present without some options.
|
|
|
|
|
|
|
|
Restart Postfix.
|
|
|
|
|
|
|
|
# rc-service postfix restart
|
|
|
|
|
2024-11-20 01:25:36 +00:00
|
|
|
# Dovecot
|
|
|
|
|
2024-11-20 02:59:40 +00:00
|
|
|
[Dovecot](https://www.dovecot.org/) is a popular IMAP and POP3 server which we'll be using for our MDA. Let's install
|
|
|
|
it:
|
|
|
|
|
|
|
|
# apk add dovecot
|
|
|
|
|
|
|
|
Check the Dovecot version with:
|
|
|
|
|
|
|
|
$ dovecot --version
|
|
|
|
|
|
|
|
Now let's enable IMAP by editing `/etc/dovecot/dovecot.conf`. Find a `protocols = ` line, or add one, and set it to:
|
|
|
|
|
|
|
|
```conf
|
|
|
|
protocols = imap
|
|
|
|
```
|
|
|
|
|
|
|
|
## Configure how to store emails
|
|
|
|
|
|
|
|
You probably want to use the Maildir format for storing emails, where each user's mail is stored at `~/Maildir` (this
|
|
|
|
can be set to another location if desired).
|
|
|
|
|
|
|
|
In `/etc/dovecot/conf.d/10-mail.conf`, set:
|
|
|
|
|
|
|
|
```conf
|
|
|
|
mail_location = maildir:~/Maildir
|
|
|
|
mail_privileged_group = mail
|
|
|
|
```
|
|
|
|
|
|
|
|
`mail_privileged_group` tells us which group of Unix users can send mail; in this case, it's anyone in the `mail`
|
|
|
|
group. You can create the group with:
|
|
|
|
|
|
|
|
# addgroup mail
|
|
|
|
# adduser postfix mail
|
|
|
|
# adduser dovecot mail
|
|
|
|
|
|
|
|
We want to ensure that `postfix` and `dovecot` users have the right to access mail.
|
|
|
|
|
|
|
|
To change the Maildir directory, e.g. to set it to `~/mail`, you would set the following:
|
|
|
|
|
|
|
|
`/etc/dovecot/conf.d/10-mail.conf`:
|
|
|
|
|
|
|
|
```conf
|
|
|
|
mail_location = maildir:~/mail
|
|
|
|
```
|
|
|
|
|
|
|
|
`/etc/postfix/main.cf`:
|
|
|
|
|
|
|
|
```conf
|
|
|
|
home_mailbox = mail/
|
|
|
|
```
|
|
|
|
|
|
|
|
## Get emails with LMTP
|
|
|
|
|
|
|
|
<abbr title="Local Mail Transfer Protocol">LMTP</abbr> is a protocol which can be used for Postfix to pass incoming
|
|
|
|
emails to Dovecot. To install it for Dovecot:
|
|
|
|
|
|
|
|
# apk add dovecot-lmtpd
|
|
|
|
|
|
|
|
Add `lmtp` to the supported protocols in `/etc/dovecot/dovecot.conf`:
|
|
|
|
|
|
|
|
```conf
|
|
|
|
protocols = imap lmtp
|
|
|
|
```
|
|
|
|
|
|
|
|
Now change the LMTP service (or add if it isn't already there) in `/etc/dovecot/conf.d/10-master.conf` to:
|
|
|
|
|
|
|
|
```conf
|
|
|
|
service lmtp {
|
|
|
|
unix_listener /var/spool/postfix/private/dovecot-lmtp {
|
|
|
|
mode = 0600
|
|
|
|
user = postfix
|
|
|
|
group = postfix
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
Postfix needs to be configured to use this socket. Edit `/etc/postfix/main.cf` with the following lines:
|
|
|
|
|
|
|
|
```conf
|
|
|
|
mailbox_transport = lmtp:unix:private/dovecot-lmtp
|
|
|
|
smtputf8_enable = no
|
|
|
|
```
|
2024-11-20 01:25:36 +00:00
|
|
|
|
2024-11-20 21:07:07 +00:00
|
|
|
## Configuring authentication
|
|
|
|
|
|
|
|
Edit `/etc/dovecot/conf.d/10-auth.conf` and uncomment the following line:
|
|
|
|
|
|
|
|
```conf
|
|
|
|
disable_plaintext_auth = yes
|
|
|
|
```
|
|
|
|
|
|
|
|
This disables plaintext authentication *unless* SSL/TLS is used.
|
|
|
|
|
|
|
|
In the same file, configure `auth_username_format`. As the variable name suggests, this denotes the format the server
|
|
|
|
expects usernames in for authentication. Setting it to `%n` removes the domain, so to sign in to `user@domain.com`
|
|
|
|
you'd enter your username as `user`. For this setup, you should set `auth_username_format` to `%n`, because we are
|
|
|
|
using Unix user accounts for email accounts; Dovecot wouldn't be able to find `user@domain.com` because the mailbox
|
|
|
|
user is just `user`.
|
|
|
|
|
|
|
|
In the same file again, `auth_mechanisms` is a space-separated list of authentication mechanisms your server uses. Set
|
|
|
|
this to
|
|
|
|
|
|
|
|
```conf
|
|
|
|
auth_mechanisms = plain login
|
|
|
|
```
|
|
|
|
|
|
|
|
`login` is mostly to support older email clients, but is optional.
|
|
|
|
|
|
|
|
Edit `/etc/dovecot/conf.d/10-master.conf`, and change `service auth` to the following:
|
|
|
|
|
|
|
|
```conf
|
|
|
|
service auth {
|
|
|
|
unix_listener /var/spool/postfix/private/auth {
|
|
|
|
mode = 0660
|
|
|
|
user = postfix
|
|
|
|
group = postfix
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
Now we need to set the actual mechanism through which the server knows what password to expect, and what users exist.
|
|
|
|
We will use a file at `/etc/dovecot/passwd` to manage this. Edit `/etc/dovecot/conf.d/auth-passwdfile.conf.ext` to be
|
|
|
|
the following:
|
|
|
|
|
|
|
|
```conf
|
|
|
|
passdb {
|
|
|
|
driver = passwd-file
|
|
|
|
args = scheme=argon2id username_format=%n /etc/dovecot/passwd
|
|
|
|
}
|
|
|
|
|
|
|
|
userdb {
|
|
|
|
driver = passwd
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
See [this documentation](https://doc.dovecot.org/main/core/config/auth/schemes.html) to decide on a password scheme to
|
|
|
|
use. I picked `argon2id` as the most secure option, however also the most expensive option, so it may be a poor option
|
|
|
|
if you have many users. Dovecot recommends that, if using ARGON2ID, you set `vsz_limit = 2G` for the `auth` service. To
|
|
|
|
do that with our setup, edit `/etc/dovecot/conf.d/10-master.conf` and add the line
|
|
|
|
|
|
|
|
```conf
|
|
|
|
vsz_limit = 2G
|
|
|
|
```
|
|
|
|
|
|
|
|
to the `service auth {}` section.
|
|
|
|
|
|
|
|
Now we want to include this file. Edit `/etc/dovecot/10-auth.conf` and ensure it includes this line, and that other
|
|
|
|
`!include` lines for other `auth-*.conf.ext` files are commented out:
|
|
|
|
|
|
|
|
```conf
|
|
|
|
!include auth-passwdfile.conf.ext
|
|
|
|
```
|
|
|
|
|
|
|
|
## Creating a user
|
|
|
|
|
|
|
|
Now let's create a user. We will be using a Unix user account, so create one with `adduser` if you don't already have
|
|
|
|
one. Their Unix username will be their email username, and what appears before the `@` in their email address. They
|
|
|
|
should also be in the `mail` group. So for instance:
|
|
|
|
|
|
|
|
# adduser revsuine
|
|
|
|
# adduser revsuine mail
|
|
|
|
|
|
|
|
We will not, however, be using their Unix password for authentication. Instead, we'll set them a password dedicated for
|
|
|
|
their email account. Create or edit the `/etc/dovecot/passwd` text file. Have a look at the following example:
|
|
|
|
|
|
|
|
```passwd
|
|
|
|
revsuine:{ARGON2ID}$argon2id$v=19$m=65536,t=3,p=1$H1oyL7UdwUWiBuZGnyXorQ$3aW/cfyNdrjoHw3OK7HlOzwgKqdg61prln8QMtWJijg
|
|
|
|
muffalo:{ARGON2ID}$argon2id$v=19$m=65536,t=3,p=1$KLnLOiqlhbhOPLhmTUqllA$Raki8Rw/+eOgJzDSEXxtw0mqI+aYLyFf+gpi+MQTdfo
|
|
|
|
thrumbo:{ARGON2ID}$argon2id$v=19$m=65536,t=3,p=1$8R4rVQ2hlKmiZ0Zmyzwg0g$tkesrePjJfLAEKu1wyJY1tu6V+fR5+C6/etyKq6WJlQ
|
|
|
|
```
|
|
|
|
|
|
|
|
This lists three users, `revsuine`, `muffalo`, and `thrumbo` (those are their usernames). These will all be system
|
|
|
|
users in the `mail` group. After the colon is the ARGON2ID hash of their password.
|
|
|
|
|
|
|
|
If you're storing passwords with ARGON2ID, to get what goes after the colon in your passwd file, run this command:
|
|
|
|
|
|
|
|
# doveadm pw -s argon2id
|
|
|
|
|
|
|
|
You will be prompted to enter a password, and then it will output exactly what to put after the colon, such as
|
|
|
|
`{ARGON2ID}$argon2id$v=19$m=65536,t=3,p=1$H1oyL7UdwUWiBuZGnyXorQ$3aW/cfyNdrjoHw3OK7HlOzwgKqdg61prln8QMtWJijg`. Each
|
|
|
|
user is their own line of the file.
|
|
|
|
|
|
|
|
Set up your `/etc/dovecot/passwd` file accordingly, making sure each user listed is also a system user, because we are
|
|
|
|
storing their mail in their home directories.
|
|
|
|
|
|
|
|
## Use your TLS certificate
|
|
|
|
|
|
|
|
Edit `/etc/dovecot/conf.d/10-ssl.conf` and set the following options (some should already be present, so you should
|
|
|
|
just change their values):
|
|
|
|
|
|
|
|
```conf
|
|
|
|
ssl = required
|
|
|
|
ssl_cert = </etc/letsencrypt/live/mail.domain.com/fullchain.pem
|
|
|
|
ssl_key = </etc/letsencrypt/live/mail.domain.com/privkey.pem
|
|
|
|
ssl_prefer_server_ciphers = yes
|
|
|
|
ssl_min_protocol = TLSv1.2
|
|
|
|
ssl_cipher_list = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305
|
|
|
|
```
|
|
|
|
|
|
|
|
Replace `mail.domain.com` with the domain you obtained your TLS certificate for. You can check
|
|
|
|
|
|
|
|
$ ls /etc/letsencrypt/live
|
|
|
|
|
|
|
|
if you're not sure.
|
|
|
|
|
|
|
|
The cipher list is from [Mailcow](https://docs.mailcow.email/manual-guides/Dovecot/u_e-dovecot-harden_ciphers/).
|
|
|
|
|
|
|
|
OpenSSL 3.x has a FIPS provider which is incompatible with Dovecot, so it should be disabled. Edit
|
|
|
|
`/etc/ssl/openssl.conf` and make sure the following line is commented out:
|
|
|
|
|
|
|
|
```conf
|
|
|
|
# providers = provider_sect
|
|
|
|
```
|
|
|
|
|
|
|
|
## Configure "special" mailboxes
|
|
|
|
|
|
|
|
The file `/etc/dovecot/conf.d/15-mailboxes.conf` denotes "special" mailboxes, such as your spam folder. You can
|
|
|
|
configure these, including setting these to auto-create, in `/etc/dovecot/conf.d/15-mailboxes.conf`. I have mine set
|
|
|
|
to:
|
|
|
|
|
|
|
|
```conf
|
|
|
|
# NOTE: Assumes "namespace inbox" has been defined in 10-mail.conf.
|
|
|
|
namespace inbox {
|
|
|
|
# These mailboxes are widely used and could perhaps be created automatically:
|
|
|
|
mailbox Drafts {
|
|
|
|
special_use = \Drafts
|
|
|
|
auto = create
|
|
|
|
}
|
|
|
|
mailbox Junk {
|
|
|
|
special_use = \Junk
|
|
|
|
}
|
|
|
|
mailbox Spam {
|
|
|
|
special_use = \Junk
|
|
|
|
auto = create
|
|
|
|
}
|
|
|
|
mailbox Trash {
|
|
|
|
special_use = \Trash
|
|
|
|
auto = create
|
|
|
|
}
|
|
|
|
|
|
|
|
# For \Sent mailboxes there are two widely used names. We'll mark both of
|
|
|
|
# them as \Sent. User typically deletes one of them if duplicates are created.
|
|
|
|
mailbox Sent {
|
|
|
|
special_use = \Sent
|
|
|
|
}
|
|
|
|
mailbox "Sent Messages" {
|
|
|
|
special_use = \Sent
|
|
|
|
auto = create
|
|
|
|
}
|
|
|
|
|
|
|
|
mailbox Drafts {
|
|
|
|
special_use = \Drafts
|
|
|
|
auto = create
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
You can set the `auto = create` option for any mailbox you want to be auto-created for users.
|
|
|
|
|
|
|
|
Now restart Dovecot. Keep an eye on terminal output, as if there's a configuration error, you'll get an error message
|
|
|
|
when restarting.
|
|
|
|
|
|
|
|
# rc-service dovecot restart
|
|
|
|
|
|
|
|
# Use a local email client
|
|
|
|
|
|
|
|
You are now ready to try logging in on a local email client such as Thunderbird, Evolution, Geary, KMail, etc.
|
|
|
|
|
|
|
|
To log in:
|
|
|
|
|
|
|
|
Enter your display name, email address (this is `[Unix user]@[mydomain variable in Postfix config]`), and the password
|
|
|
|
you set for yourself in `/etc/dovecot/passwd`. Set the following settings:
|
|
|
|
|
|
|
|
<!-- html table so that the headers can be on the left & colspan -->
|
|
|
|
|
|
|
|
<table>
|
|
|
|
<tr>
|
|
|
|
<td></td>
|
|
|
|
<th>Incoming</th>
|
|
|
|
<th>Outgoing</th>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<th>Server type</th>
|
|
|
|
<td>IMAP</td>
|
|
|
|
<td>SMTP</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<th>Server</th>
|
2024-11-20 21:17:16 +00:00
|
|
|
<td colspan="2"><code>mail.domain.com</code>, or whatever your MX record is set to</td>
|
2024-11-20 21:07:07 +00:00
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<th>Port</th>
|
|
|
|
<td>993</td>
|
|
|
|
<td>465</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<th>Username</th>
|
2024-11-20 21:17:16 +00:00
|
|
|
<td colspan="2">Your system username; this should be the contents of your email address before the
|
|
|
|
<code>@</code></td>
|
2024-11-20 21:07:07 +00:00
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<th>Encryption</th>
|
|
|
|
<td colspan="2">SSL/TLS</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<th>Authentication</th>
|
|
|
|
<td>Password</td>
|
2024-11-20 21:17:16 +00:00
|
|
|
<td>PLAIN (shows up as <code>Normal password</code> in Thunderbird)</td>
|
2024-11-20 21:07:07 +00:00
|
|
|
</tr>
|
|
|
|
</table>
|
|
|
|
|
|
|
|
With our setup, we are also able to use STARTTLS on port 143 (incoming) and 587 (outgoing) too.
|
|
|
|
|
|
|
|
You should be able to send and receive emails as normal now.
|
|
|
|
|
2024-11-21 03:32:47 +00:00
|
|
|
# Set up SPF, DKIM, and DMARC
|
|
|
|
|
|
|
|
<abbr title="Sender Policy Framework">SPF</abbr>, <abbr title="DomainKeys Identified Mail">DKIM</abbr>, and <abbr
|
|
|
|
title="Domain-based Message Authentication, Reporting and Conformance">DMARC</abbr> records are TXT DNS records that
|
|
|
|
protect against people spoofing your domain. Having correctly configured SPF, DKIM, and DMARC records helps your mail
|
|
|
|
avoid getting caught by spam filters.
|
|
|
|
|
|
|
|
SPF records indicate which hosts or IP addresses are allowed to send email from your domain.
|
|
|
|
|
|
|
|
DKIM digitally signs emails with a private key to verify that they came from your server. If someone else without your
|
|
|
|
private key sends email from your domain, they wouldn't be able to produce a valid DKIM signature. DKIM public keys are
|
|
|
|
published in TXT DNS records, so that any other mail server can verify a signature of an email from your domain.
|
|
|
|
|
|
|
|
DMARC records state that your domain uses SPF and DKIM, and that emails sent from your domain should pass SPF and DKIM
|
|
|
|
checks.
|
|
|
|
|
|
|
|
## Sender Policy Framework
|
|
|
|
|
|
|
|
Add a TXT record for your root domain with the contents `v=spf1 mx ~all`, like:
|
|
|
|
|
|
|
|
```dns
|
|
|
|
revsuine.xyz. 900 IN TXT "v=spf1 mx ~all"
|
|
|
|
```
|
|
|
|
|
|
|
|
In your DNS manager, you would enter:
|
|
|
|
|
|
|
|
<!-- html table so that header can be column not row -->
|
|
|
|
|
|
|
|
<table>
|
|
|
|
<tr>
|
|
|
|
<th>Name</th>
|
|
|
|
<td><code>@</code></td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<th>Type</th>
|
|
|
|
<td><code>TXT</code></td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<th>TTL</th>
|
|
|
|
<td>Default (mine is 900)</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<th>TXT data</th>
|
|
|
|
<td><code>v=spf1 mx ~all</code></td>
|
|
|
|
</tr>
|
|
|
|
</table>
|
|
|
|
|
|
|
|
This is assuming you're sending emails from `domain.com` instead of, e.g. `sub.domain.com`. If your email addresses are
|
|
|
|
like `user@sub.domain.com`, you would use `sub` as the name in the DNS record instead of `@`, which denotes the apex
|
|
|
|
domain. The same applies for all the DNS records in this section.
|
|
|
|
|
|
|
|
Breaking down the TXT data:
|
|
|
|
|
|
|
|
<!-- html table bc the last cell is quite long in contents and markdown requires one cell to all be on one line -->
|
|
|
|
|
|
|
|
<table>
|
|
|
|
<tr>
|
|
|
|
<th>Part</th>
|
|
|
|
<th>Explanation</th>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td><code>v=spf1</code></td>
|
|
|
|
<td>This is an SPF record, and the SPF record version is SPF1.</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td><code>mx</code></td>
|
|
|
|
<td>All hosts listed in MX records are allowed to send emails from this domain.</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td><code>~all</code></td>
|
|
|
|
<td>
|
|
|
|
Emails from your domain should only come from hosts specified by your SPF record. Can also be
|
|
|
|
<code>+all</code>, <code>-all</code>, <code>?all</code>, but those are rarely used. <code>-all</code> means
|
|
|
|
that emails not from SPF-approved hosts should be rejected; however, this option can cause valid emails to
|
|
|
|
be rejected if the recipient has multiple SMTP servers, and an email is relayed from one of their SMTP
|
|
|
|
servers to another, for instance if one SMTP server goes down and they have a backup server.
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
</table>
|
|
|
|
|
|
|
|
## DomainKeys Identified Mail
|
|
|
|
|
|
|
|
### Configure OpenDKIM
|
|
|
|
|
|
|
|
OpenDKIM is an open-source implementation of DKIM signing and authentication. You can install it with:
|
|
|
|
|
|
|
|
# apk add opendkim opendkim-utils
|
|
|
|
|
|
|
|
You may also want `opendkim-doc` for documentation.
|
|
|
|
|
|
|
|
Add the `postfix` user to the `opendkim` group:
|
|
|
|
|
|
|
|
# adduser postfix opendkim
|
|
|
|
|
|
|
|
Edit your OpenDKIM config file at `/etc/opendkim/opendkim.conf`. Ensure the following is present (`Canonicalization` is
|
|
|
|
likely already there, so just change and uncomment things, and add lines where necessary):
|
|
|
|
|
|
|
|
```conf
|
|
|
|
Canonicalization relaxed/simple
|
|
|
|
Mode sv
|
|
|
|
SubDomains no
|
|
|
|
AutoRestart yes
|
|
|
|
AutoRestartRate 10/1M
|
|
|
|
Background yes
|
|
|
|
DNSTimeout 5
|
|
|
|
SignatureAlgorithm rsa-sha256
|
|
|
|
```
|
|
|
|
|
|
|
|
Add the following to the config file:
|
|
|
|
|
|
|
|
```conf
|
|
|
|
# OpenDKIM user
|
|
|
|
# Remember to add user postfix to group opendkim
|
|
|
|
UserID opendkim
|
|
|
|
|
|
|
|
# Map domains in From addresses to keys used to sign messages
|
|
|
|
KeyTable refile:/etc/opendkim/key.table
|
|
|
|
SigningTable refile:/etc/opendkim/signing.table
|
|
|
|
|
|
|
|
# Hosts to ignore when verifying signatures
|
|
|
|
ExternalIgnoreList /etc/opendkim/trusted.hosts
|
|
|
|
|
|
|
|
# A set of internal hosts whose mail should be signed
|
|
|
|
InternalHosts /etc/opendkim/trusted.hosts
|
|
|
|
```
|
|
|
|
|
|
|
|
Create a directory for OpenDKIM's keys at `/etc/opendkim/keys/`, and ensure the directory is owned by `opendkim` and
|
|
|
|
that no one else has read or write access to the keys directory:
|
|
|
|
|
|
|
|
# mkdir /etc/opendkim/keys
|
|
|
|
# chown -R opendkim:opendkim /etc/opendkim
|
|
|
|
# chmod go-rw /etc/opendkim/keys
|
|
|
|
|
|
|
|
Create `/etc/opendkim/signing.table` and set its contents to the following:
|
|
|
|
|
|
|
|
```
|
|
|
|
*@domain.com default._domainkey.domain.com
|
|
|
|
*@*.domain.com default._domainkey.domain.com
|
|
|
|
```
|
|
|
|
|
|
|
|
This tells OpenDKIM to use your domain's private key to sign any emails originating from `domain.com` and its
|
|
|
|
subdomains. Replace `domain.com` with your domain.
|
|
|
|
|
|
|
|
Now create `/etc/opendkim/key.table` and set its contents to:
|
|
|
|
|
|
|
|
```
|
|
|
|
default._domainkey.domain.com domain.com:default:/etc/opendkim/keys/domain.com/default.private
|
|
|
|
```
|
|
|
|
|
|
|
|
Replacing `domain.com` with your domain. This tells OpenDKIM where your private key is stored.
|
|
|
|
|
|
|
|
Create `/etc/opendkim/trusted.hosts` and set its contents to
|
|
|
|
|
|
|
|
```
|
|
|
|
127.0.0.1
|
|
|
|
localhost
|
|
|
|
|
|
|
|
.domain.com
|
|
|
|
```
|
|
|
|
|
|
|
|
Similarly, replace `domain.com` with your domain.
|
|
|
|
|
|
|
|
### Generate your keys
|
|
|
|
|
|
|
|
Create a directory for your domain's keys at `/etc/opendkim/keys/domain.com`. Use `opendkim-genkey` to generate your
|
|
|
|
keys:
|
|
|
|
|
|
|
|
# opendkim-genkey -b 2048 -d domain.com -D /etc/opendkim/keys/domain.com -s default -v
|
|
|
|
|
|
|
|
Replace `domain.com` with your domain.
|
|
|
|
|
|
|
|
Set the owner and permissions of the private key so that only `opendkim` has read and write access to it:
|
|
|
|
|
|
|
|
# chown opendkim:opendkim /etc/opendkim/keys/domain.com/default.private
|
|
|
|
# chmod 600 /etc/opendkim/keys/domain.com/default.private
|
|
|
|
|
|
|
|
### Publish your public key in your DNS records
|
|
|
|
|
|
|
|
Look at your public key:
|
|
|
|
|
|
|
|
# cat /etc/opendkim/keys/domain.com/default.txt
|
|
|
|
|
|
|
|
You'll see something like this:
|
|
|
|
|
|
|
|
```
|
|
|
|
default._domainkey IN TXT ( "v=DKIM1; k=rsa; "
|
|
|
|
"p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu7QJxihVsEGhsZBLMxGKCVecIhjINp/zMGH0ExHN5QelxRIKdAHpJ33cZUBEsL0H27/4E8BK9RZ4AOaDMHfIGJ9FybyyD+gHhvKFFHzyts0QpkwLV+3bApsMqSR4ZsSzt3pZvRhQrXaoUds+9CyQBuEGx16PcA2O04/vWlvWhwStJrZWWHDYl2PX3QHfFFSsJaTsiFMwnMECvg"
|
|
|
|
"a6TdBTcsbcHwfedkoeMv5RQFlKisqCEiJkUYbJaczDA88fcZm21eGW8HiCSwq3324ExfWSwPGVsXAn1Blq/oKklpjXQIwwrphglK//G6AF7M3AAfqBdCvUbkAjs28fJwGqiVxaCwIDAQAB" ) ; ----- DKIM key default for revsuine.xyz
|
|
|
|
```
|
|
|
|
|
|
|
|
This is what your DNS record should look like. Copy **everything between the brackets** and add it to your DNS record:
|
|
|
|
|
|
|
|
<!-- using html table for above reasons of line breaks... -->
|
|
|
|
|
|
|
|
<table>
|
|
|
|
<tr>
|
|
|
|
<th>Name</th>
|
|
|
|
<td><code>default._domainkey</code></td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<th>Type</th>
|
|
|
|
<td><code>TXT</code></td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<th>TTL</th>
|
|
|
|
<td>Default value (mine is 900)</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<th>TXT data</th>
|
|
|
|
<td>
|
|
|
|
What you copied from between the brackets, <em>with all double quotes and extra whitespace (beyond a single
|
|
|
|
space character) removed</em>
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
</table>
|
|
|
|
|
|
|
|
So with the above public key, my DNS record is
|
|
|
|
|
|
|
|
```dns
|
|
|
|
default._domainkey.revsuine.xyz. 900 IN TXT (
|
|
|
|
"v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQ"
|
|
|
|
"EFAAOCAQ8AMIIBCgKCAQEAu7QJxihVsEGhsZBLMx"
|
|
|
|
"GKCVecIhjINp/zMGH0ExHN5QelxRIKdAHpJ33cZU"
|
|
|
|
"BEsL0H27/4E8BK9RZ4AOaDMHfIGJ9FybyyD+gHhv"
|
|
|
|
"KFFHzyts0QpkwLV+3bApsMqSR4ZsSzt3pZvRhQrX"
|
|
|
|
"aoUds+9CyQBuEGx16PcA2O04/vWlvWhwStJrZWWH"
|
|
|
|
"DYl2PX3QHfFFSsJaTsiFMwnMECvg a6TdBTcsbcH"
|
|
|
|
"wfedkoeMv5RQFlKisqCEiJkUYbJaczDA88fcZm21"
|
|
|
|
"eGW8HiCSwq3324ExfWSwPGVsXAn1Blq/oKklpjXQ"
|
|
|
|
"IwwrphglK//G6AF7M3AAfqBdCvUbkAjs28fJwGqi"
|
|
|
|
"VxaCwIDAQAB"
|
|
|
|
)
|
|
|
|
```
|
|
|
|
|
|
|
|
and what I entered into the data field of my DNS manager when adding the record was
|
|
|
|
|
|
|
|
```
|
|
|
|
v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu7QJxihVsEGhsZBLMxGKCVecIhjINp/zMGH0ExHN5QelxRIKdAHpJ33cZUBEsL0H27/4E8BK9RZ4AOaDMHfIGJ9FybyyD+gHhvKFFHzyts0QpkwLV+3bApsMqSR4ZsSzt3pZvRhQrXaoUds+9CyQBuEGx16PcA2O04/vWlvWhwStJrZWWHDYl2PX3QHfFFSsJaTsiFMwnMECvg a6TdBTcsbcHwfedkoeMv5RQFlKisqCEiJkUYbJaczDA88fcZm21eGW8HiCSwq3324ExfWSwPGVsXAn1Blq/oKklpjXQIwwrphglK//G6AF7M3AAfqBdCvUbkAjs28fJwGqiVxaCwIDAQAB
|
|
|
|
```
|
|
|
|
|
|
|
|
You can now test your DKIM key with:
|
|
|
|
|
|
|
|
# opendkim-testkey -d domain.com -s default -vvv
|
|
|
|
|
|
|
|
Don't worry about
|
|
|
|
|
|
|
|
```
|
|
|
|
opendkim-testkey: key not secure
|
|
|
|
```
|
|
|
|
|
|
|
|
This just means that DNSSEC isn't enabled for your domain name.
|
|
|
|
|
|
|
|
### Use OpenDKIM with Postfix
|
|
|
|
|
|
|
|
You can use a Unix socket for this, but I couldn't get the Unix socket to work, so I'll show you how to connect Postfix
|
|
|
|
to OpenDKIM using a TCP/IP socket on port 8891 instead.
|
|
|
|
|
|
|
|
Edit your OpenDKIM config `/etc/opendkim/opendkim.conf`, and ensure that the following line is present:
|
|
|
|
|
|
|
|
```conf
|
|
|
|
Socket inet:8891@localhost
|
|
|
|
```
|
|
|
|
|
|
|
|
Also make sure there are no other uncommented `Socket` lines.
|
|
|
|
|
|
|
|
Now configure Postfix at `/etc/postfix/main.cf`, and add the following lines:
|
|
|
|
|
|
|
|
```conf
|
|
|
|
milter_default_action = accept
|
|
|
|
milter_protocol = 6
|
|
|
|
smtpd_milters = inet:127.0.0.1:8891
|
|
|
|
non_smtpd_milters = $smtpd_milters
|
|
|
|
```
|
|
|
|
|
|
|
|
This uses the Milter extension, which is something that can be used to process mail; in this case, to add headers to
|
|
|
|
emails relating to DKIM.
|
|
|
|
|
|
|
|
<!-- TODO DMARC section here -->
|
|
|
|
|
|
|
|
### Test SPF, DKIM, and DMARC
|
|
|
|
|
|
|
|
You can use [mail-tester.com](https://www.mail-tester.com/) and send an email from your domain to check that SPF, DKIM,
|
|
|
|
and DMARC are all working for your server.
|
|
|
|
|
2024-11-19 20:39:10 +00:00
|
|
|
<!-- FOOTNOTES: -->
|
|
|
|
|
2024-11-20 01:25:36 +00:00
|
|
|
[^server_trust]: This is only true to the extent that your server is not compromised. You could say there's an order of
|
|
|
|
server trust-ability that goes:
|
|
|
|
|
|
|
|
```
|
|
|
|
VPS < rented dedicated server < server you yourself physically own, store, and manage
|
|
|
|
```
|
|
|
|
|
|
|
|
There is little that can be done to secure a VM running on a compromised host. Even with full-disk encryption, the
|
|
|
|
host can dump the encryption key from RAM, because the encryption key must be stored in memory whilst a
|
|
|
|
full-disk-encrypted system is booted.
|
|
|
|
|
|
|
|
For a dedicated server you rent, there are at least no concerns about a compromised host, but an attacker with
|
|
|
|
physical access (in this case, the untrusted people you rent the dedicated server from) can attempt evil maid
|
2024-11-20 01:33:30 +00:00
|
|
|
attacks. You are hopefully able to implement mechanisms to detect this, though.
|
2024-11-20 01:25:36 +00:00
|
|
|
|
|
|
|
There are reasons you may want to go with a rented server instead of one you own, though. For instance, if you live
|
|
|
|
in a jurisdiction known for terrible privacy laws such as a [5/14 eyes
|
|
|
|
country](https://restoreprivacy.com/5-eyes-9-eyes-14-eyes/), or if you are a political dissident with domestic
|
|
|
|
state interest in you, you likely want to go offshore for server hosting. Changing the jurisdiction can protect you
|
|
|
|
if the jurisdiction you choose won't work with your national intelligence agencies.
|
|
|
|
|
2024-11-19 20:39:10 +00:00
|
|
|
[^postfix_aliases_location]: Your aliases file will most likely be in this location by default, but you can run
|
|
|
|
|
2024-11-20 01:25:36 +00:00
|
|
|
```
|
|
|
|
$ postconf alias_maps
|
|
|
|
```
|
2024-11-19 20:39:10 +00:00
|
|
|
|
|
|
|
to find out where this file should be.
|
|
|
|
|