313 lines
10 KiB
ReStructuredText
313 lines
10 KiB
ReStructuredText
.. _setup-guide:
|
||
|
||
Setup Guide
|
||
===========
|
||
|
||
Mail servers can be a tricky thing to set up. This guide is supposed to
|
||
run you through the most important steps to achieve a 10/10 score on
|
||
`<https://mail-tester.com>`_.
|
||
|
||
Requirements
|
||
~~~~~~~~~~~~
|
||
|
||
To set up a self-hosted mail server, you need the following:
|
||
|
||
* Small (e.g. 1C/2G) server running NixOS
|
||
* Stable IPv4 and - strongly recommended - IPv6 addresses
|
||
|
||
* Ability to configure a Reverse DNS (PTR record) for your IP addresses
|
||
* Access to SMTP traffic on port 25/tcp - some hosters make you ask for this
|
||
|
||
* A registered domain name with DNS record management access
|
||
|
||
Once these requirements are in place, you can begin setting up your selfhosted
|
||
mailserver.
|
||
|
||
.. note::
|
||
|
||
Below we'll assume that your server got assigned the public IP addresses
|
||
``192.0.2.1`` (IPv4) and ``2001:db8::1`` (IPv6) and that you control the
|
||
``example.com`` domain.
|
||
|
||
Configure forward DNS records
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
Here we set up ``mail.example.com`` as the forward hostname for your mail server
|
||
to point to the IP addresses allocated to the server. This allows reaching
|
||
the server under this name and to reference it later in MX records for mail
|
||
delivery.
|
||
|
||
Now edit the ``example.com`` zone and create the following DNS records:
|
||
|
||
.. csv-table::
|
||
:header: "Name", "TTL", "Type", "Value"
|
||
:widths: 30, 10, 10, 50
|
||
|
||
mail.example.com., 3600, A, 192.0.2.1
|
||
mail.example.com., 3600, AAAA, 2001:db8::1
|
||
|
||
.. note::
|
||
If your server does not have an IPv6 address, you must skip the ``AAAA``
|
||
record.
|
||
|
||
Verify DNS record propagation
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
Before we continue with the next step, we require that the forward DNS record
|
||
has propagated. For that it's best to check an authoritative nameserver for
|
||
``example.com`` so that we don't look at cached DNS records.
|
||
|
||
.. code-block:: console
|
||
|
||
# Find the authoritative nameservers for example.com
|
||
$ nix-shell -p dig --command "dig NS example.com +short"
|
||
ns1.example.org.
|
||
ns2.example.org.
|
||
|
||
# Query the A record from an authoritative nameserver
|
||
$ nix-shell -p dig --command "dig @ns1.example.org A mail.example.com +short"
|
||
192.0.2.1
|
||
|
||
# Query the AAAA record from an authoritative nameserver
|
||
$ nix-shell -p dig --command "dig @ns1.example.org AAAA mail.example.com +short"
|
||
2001:db8::1
|
||
|
||
|
||
DNS propagation usually takes a few minutes, so you might need to retry these
|
||
queries. Once the IP addresses appear you can continue with the next step.
|
||
|
||
Setup the server
|
||
~~~~~~~~~~~~~~~~
|
||
|
||
The following configuration describes a fairly complete mail server, capable
|
||
of sending and receiving mail for statically configured accounts. It includes
|
||
encrypted SMTP and IMAP services for secure delivery and retrieval, and relies
|
||
on ACME HTTP-01 to automatically obtain and maintain a TLS certificate.
|
||
|
||
While `more options`_ are available, the configuration below covers the most
|
||
common settings to get your mail server up and running.
|
||
|
||
.. _more options: options.html
|
||
|
||
.. literalinclude:: ./setup-example.nix
|
||
:language: nix
|
||
|
||
After a ``nixos-rebuild switch`` your server should be running all the necessary
|
||
mail services.
|
||
|
||
Configure DNS records
|
||
~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
Reverse DNS
|
||
^^^^^^^^^^^
|
||
|
||
Earlier, we configured forward DNS from your hostname to your IP address. Now we
|
||
will configure reverse DNS so that your IP address points back to your hostname.
|
||
|
||
If your forward and reverse DNS do not match, many mail servers will reject or
|
||
flag your emails as spam, severely impairing delivery.
|
||
|
||
Your server provider should allow you to configure reverse DNS (PTR record)
|
||
records for the IP addresses you control, typically through their control panel
|
||
or account management interface:
|
||
|
||
- Configure ``192.0.2.1`` to point to ``mail.example.com.``
|
||
- Configure ``2001:db8::1`` to point to ``mail.example.com.``, if you have IPv6
|
||
addressing
|
||
|
||
Alternatively, if you interact with a proper DNS setup, the actual DNS records
|
||
look like this:
|
||
|
||
.. csv-table::
|
||
:header: "Name", "TTL", "Type", "Value"
|
||
:widths: 30, 10, 10, 50
|
||
|
||
1.2.0.192.in-addr.arpa., 86400, PTR, mail.example.com.
|
||
1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa., 86400, PTR, mail.example.com.
|
||
|
||
.. note::
|
||
Reverse DNS uses reverse notation for naming its records:
|
||
|
||
* IPv4 reverses the order of the octets and appends ``in-addr.arpa.``, so
|
||
``192.0.2.1`` becomes ``1.2.0.192.in-addr.arpa.``
|
||
* IPv6 fully expands the address and reverses each hex digit before
|
||
concatenating it with dots and appending ``ip6.arpa.``
|
||
|
||
.. code-block:: console
|
||
|
||
nix-shell -p haskellPackages.ip6addr --command "ip6addr --ptr 2001:db8::1"
|
||
1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.IP6.ARPA.
|
||
|
||
.. warning::
|
||
|
||
We don't recommend setting up a mail server if you are unable to configure
|
||
reverse DNS on your public IP addresses because mails would inevitable be
|
||
marked as spam. Note that many residential ISP providers don't allow you to
|
||
set a reverse DNS entry and prohibit sending mail through policy blocklists
|
||
like Spamhaus PBL.
|
||
|
||
DNS propagation often isn't instant, so verify before continuing:
|
||
|
||
.. code-block:: console
|
||
|
||
$ nix-shell -p dig --command "dig -x 192.0.2.1 +short"
|
||
mail.example.com.
|
||
|
||
$ nix-shell -p dig --command "dig -x 2001:db8::1 +short"
|
||
mail.example.com.
|
||
|
||
|
||
MX record
|
||
^^^^^^^^^
|
||
|
||
The MX record instructs other mailservers where to deliver mail for a domain
|
||
name.
|
||
|
||
Create the MX record for ``example.com`` to point to the hostname of the server.
|
||
|
||
.. csv-table::
|
||
:header: "Name", "TTL", "Priority", "Type", "Value"
|
||
:widths: 30, 10, 10, 10, 50
|
||
|
||
example.com., 3600, MX, 10, mail.example.com.
|
||
|
||
The priority field determines the order when multiple servers are configured.
|
||
It is not important in this scenario but setting a value is mandatory and 10
|
||
leaves some wiggle room below and above, should you ever need that.
|
||
|
||
.. code-block:: console
|
||
|
||
$ nix-shell -p dig --command "dig @ns1.example.org MX example.com +short"
|
||
10 mail.example.com.
|
||
|
||
SPF record
|
||
^^^^^^^^^^
|
||
|
||
With `SPF`_ we can specify which mail servers are authorized to send mail on
|
||
behalf of a domain name.
|
||
|
||
.. _SPF: https://en.wikipedia.org/wiki/Sender_Policy_Framework
|
||
|
||
The SPF record is TXT record and we can tie it in with the MX record we created
|
||
in the previous step. Finishing with ``-all`` indicates that without any match
|
||
the mail should be rejected.
|
||
|
||
.. csv-table::
|
||
:header: "Name", "TTL", "Type", "Value"
|
||
:widths: 30, 10, 10, 50
|
||
|
||
example.com., 86400, TXT, v=spf1 mx -all
|
||
|
||
.. code-block:: console
|
||
|
||
$ nix-shell -p dig --command "dig TXT example.com +short"
|
||
v=spf1 mx -all
|
||
|
||
|
||
DKIM record
|
||
^^^^^^^^^^^
|
||
|
||
On system activation a `DKIM`_ keypair for ``example.com`` was generated. The
|
||
mail server uses this key to sign outgoing emails, allowing receiving servers to
|
||
verify the authenticity of the sender domain and ensuring that the signed parts
|
||
of the message have not been tampered with.
|
||
|
||
.. _DKIM: https://en.wikipedia.org/wiki/DomainKeys_Identified_Mail
|
||
|
||
Now, check ``/var/dkim/example.com.mail.txt``, which contains the proposed DNS
|
||
record for the ``mail`` DKIM selector.
|
||
|
||
.. code-block:: none
|
||
|
||
mail._domainkey IN TXT ( "v=DKIM1; k=rsa; "
|
||
"p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv7hSess/UgEjaaq/NDn5KtW2iZzYljhf45DH3tN/kqcJ04JJk/Z1rS7CMJQ/pYZSSnQOju0H25uOtODvhqXPDxDdtCyDSrx54z/38lGNtA76/iWy/ikjb9hEkb2k3HuKex3P4KhhOC1pytDEFnh/T2aBxPNOigc/cpqm1U9RbnAwvArtx9dgOAgiV8rOIgPgyrPw1B3cJG3hgFYU2"
|
||
"GwXMoiFQPgwm7bkjelmThqXozA7jFJfnYt49jjrIYCv8X/nQx9cNpVAv2852mhU/3uuy6sa4MPjT6RiK9BJCMyDnqSpTPCjIubL4VhGCuzp7RPBkayWnlaH0X8PWGq6BQ0eBwIDAQAB"
|
||
) ;
|
||
|
||
Based on the content of this file, we can create the DKIM TXT record for the
|
||
``mail`` selector in the ``example.com`` zone. For the ``p=`` value, glue the
|
||
two long strings back together without any quotes and spaces and put them into
|
||
your record below.
|
||
|
||
.. csv-table::
|
||
:header: "Name", "TTL", "Type", "Value"
|
||
:widths: 30, 10, 10, 50
|
||
|
||
mail._domainkey.example.com., 86400, TXT, v=DKIM1; k=rsa; p=MIIBIjANBgk...Q0eBwIDAQAB
|
||
|
||
.. code-block:: console
|
||
|
||
$ nix-shell -p dig --command "dig @ns1.example.org TXT mail._domainkey.example.com +short"
|
||
"v=DKIM1; k=rsa; p=MIIBIjANBgk...Q0eBwIDAQAB"
|
||
|
||
|
||
DMARC record
|
||
^^^^^^^^^^^^
|
||
|
||
Finally, DMARC lets you define a policy for how strictly SPF and DKIM should be
|
||
checked and how to handle validation failures. For a new server, it’s important
|
||
to have a DMARC record in place, even if it doesn’t enforce any actions yet,
|
||
because it improves deliverability by showing receiving servers that your domain
|
||
is properly managed and reducing the risk of email spoofing.
|
||
|
||
.. csv-table::
|
||
:header: "Name", "TTL", "Type", "Value"
|
||
:widths: 30, 10, 10, 50
|
||
|
||
_dmarc.example.com., 86400, TXT, v=DMARC1; p=none;
|
||
|
||
Verify propagation one final time.
|
||
|
||
.. code-block:: console
|
||
|
||
$ nix-shell -p dig --command "dig @ns1.example.org TXT _dmarc.example.com +short"
|
||
"v=DMARC1; p=none"
|
||
|
||
|
||
Test your Setup
|
||
~~~~~~~~~~~~~~~
|
||
|
||
Write an email to your aunt — she’s been waiting far too long for your reply,
|
||
and this is your chance to finally make her day. Or, if you prefer a less
|
||
emotional test, send a message to `mail-tester.com`_ to see how your outgoing
|
||
mail scores.
|
||
|
||
You can also let `MXToolbox`_ take a peek at your setup. If you followed the
|
||
steps carefully, everything should be working perfectly!
|
||
|
||
.. _mail-tester.com: https://mail-tester.com/
|
||
.. _MXToolbox: https://mxtoolbox.com/
|
||
|
||
|
||
Join the community
|
||
~~~~~~~~~~~~~~~~~~
|
||
|
||
The community has a lively chat room on Matrix at `#nixos-mailserver:nixos.org`_
|
||
where you can ask questions, get help, share ideas, or discuss contributions.
|
||
|
||
.. _#nixos-mailserver:nixos.org: https://matrix.to/#/#nixos-mailserver:nixos.org
|
||
|
||
Next steps
|
||
~~~~~~~~~~
|
||
|
||
Your server scored perfect results already, so these steps are entirely
|
||
optional.
|
||
|
||
Are you feeling adventurous? Dive into our `advanced configurations`_ to explore
|
||
additional features and capabilities that let you fine-tune and extend your
|
||
mail setup.
|
||
|
||
If you want to take things even further, more elaborate testing services can
|
||
give you a clearer picture of your mail service and suggest ways to improve
|
||
it.
|
||
|
||
- `internet.nl`_ (supported by the Dutch Government)
|
||
- `MECSA`_ (supported by the European Commission)
|
||
|
||
Finally, you can also browse the full list of `options`_ provided by NixOS mailserver.
|
||
|
||
.. _advanced configurations: advanced-configurations.html
|
||
.. _options: options.html
|
||
.. _internet.nl: https://internet.nl/test-mail/
|
||
.. _MECSA: https://mecsa.jrc.ec.europa.eu/
|