.. SPDX-License-Identifier: GPL-3.0-or-later .. SPDX-FileCopyrightText: Antoine Eiche .. SPDX-FileCopyrightText: Martin Weinelt .. SPDX-FileCopyrightText: The NixOS Mailserver contributors .. _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 ``_. 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/