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'
|
|
|
|
+++
|
|
|
|
|
|
|
|
# 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-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>
|
|
|
|
<td colspan="2">DKIM authentication and signing</td>
|
|
|
|
</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-19 20:39:10 +00:00
|
|
|
```bindzone
|
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-19 20:39:10 +00:00
|
|
|
```bindzone
|
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-19 20:39:10 +00:00
|
|
|
```bindzone
|
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-19 20:39:10 +00:00
|
|
|
```bindzone
|
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
|
|
|
|
certificate at `/etc/letsencrypt/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/mail.domain.com/`.
|
|
|
|
|
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`.
|
|
|
|
|
|
|
|
`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
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
## 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 01:25:36 +00:00
|
|
|
# Dovecot
|
|
|
|
|
|
|
|
[Dovecot](https://www.dovecot.org/) is a popular IMAP and POP3 server which we'll be using for our MDA.
|
|
|
|
|
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.
|
|
|
|
|