From 781073b64d4608490155cf87cccb0357d889444c Mon Sep 17 00:00:00 2001 From: Antoine Eiche Date: Thu, 2 Jul 2020 21:02:47 +0200 Subject: [PATCH] docs: create a readthedocs manual The goal is to remove the WIKI since modifications can not be submitted via PRs. --- docs/backup-guide.rst | 20 +++ docs/conf.py | 53 ++++++++ docs/howto-add-radicale.rst | 50 ++++++++ docs/howto-develop.rst | 39 ++++++ docs/index.rst | 27 ++++ docs/quick-start.rst | 32 +++++ docs/setup-guide.rst | 242 ++++++++++++++++++++++++++++++++++++ shell.nix | 14 ++- 8 files changed, 471 insertions(+), 6 deletions(-) create mode 100644 docs/backup-guide.rst create mode 100644 docs/conf.py create mode 100644 docs/howto-add-radicale.rst create mode 100644 docs/howto-develop.rst create mode 100644 docs/index.rst create mode 100644 docs/quick-start.rst create mode 100644 docs/setup-guide.rst diff --git a/docs/backup-guide.rst b/docs/backup-guide.rst new file mode 100644 index 0000000..57acc2a --- /dev/null +++ b/docs/backup-guide.rst @@ -0,0 +1,20 @@ +A Complete Backup Guide +======================= + +This is really easy. First off you should have a backup of your +``configuration.nix`` file where you have the server config (but that is +already in a git repository right?) + +Next you need to backup ``/var/vmail`` or whatever you have specified +for the option ``mailDirectory``. This is where all the mails reside. +Good options are a cron job with ``rsync`` or ``scp``. But really +anything works, as it is simply a folder with plenty of files in it. If +your backup solution does not preserve the owner of the files don’t +forget to ``chown`` them to ``virtualMail:virtualMail`` if you copy them +back (or whatever you specified as ``vmailUserName``, and +``vmailGoupName``). + +Finally you can (optionally) make a backup of ``/var/dkim`` (or whatever +you specified as ``dkimKeyDirectory``). If you should lose those don’t +worry, new ones will be created on the fly. But you will need to repeat +step ``B)5`` and correct all the ``dkim`` keys. diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..84eb68b --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,53 @@ +# Configuration file for the Sphinx documentation builder. +# +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +# import os +# import sys +# sys.path.insert(0, os.path.abspath('.')) + + +# -- Project information ----------------------------------------------------- + +project = 'NixOS Mailserver' +copyright = '2020, NixOS Mailserver Contributors' +author = 'NixOS Mailserver Contributors' + + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + +master_doc = 'index' + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'sphinx_rtd_theme' + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] diff --git a/docs/howto-add-radicale.rst b/docs/howto-add-radicale.rst new file mode 100644 index 0000000..824e363 --- /dev/null +++ b/docs/howto-add-radicale.rst @@ -0,0 +1,50 @@ +How to Add Radicale to SNM +========================== + +Configuration by @dotlambda + +.. code:: nix + + { config, pkgs, lib, ... }: + + with lib; + + let + mailAccounts = config.mailserver.loginAccounts; + htpasswd = pkgs.writeText "radicale.users" (concatStrings + (flip mapAttrsToList mailAccounts (mail: user: + mail + ":" + user.hashedPassword + "\n" + )) + ); + + in { + services.radicale = { + enable = true; + config = '' + [auth] + type = htpasswd + htpasswd_filename = ${htpasswd} + htpasswd_encryption = crypt + ''; + }; + + services.nginx = { + enable = true; + virtualHosts = { + "cal.example.com" = { + forceSSL = true; + enableACME = true; + locations."/" = { + proxyPass = "http://localhost:5232/"; + extraConfig = '' + proxy_set_header X-Script-Name /; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_pass_header Authorization; + ''; + }; + }; + }; + }; + + networking.firewall.allowedTCPPorts = [ 80 443 ]; + } diff --git a/docs/howto-develop.rst b/docs/howto-develop.rst new file mode 100644 index 0000000..3a6361c --- /dev/null +++ b/docs/howto-develop.rst @@ -0,0 +1,39 @@ +How to Develop SNM +================== + +Run tests +--------- + +You can run the testsuite via + +:: + + nix-build tests -A extern.nixpkgs_20_03 + nix-build tests -A intern.nixpkgs_unstable + ... + +Nixops +------ + +You can test the setup via ``nixops``. After installation, do + +:: + + nixops create nixops/single-server.nix nixops/vbox.nix -d mail + nixops deploy -d mail + nixops info -d mail + +You can then test the server via e.g. \ ``telnet``. To log into it, use + +:: + + nixops ssh -d mail mailserver + +Imap +---- + +To test imap manually use + +:: + + openssl s_client -host mail.example.com -port 143 -starttls imap diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..7dc5d12 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,27 @@ +.. NixOS Mailserver documentation master file, created by + sphinx-quickstart on Thu Jul 2 20:50:36 2020. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to NixOS Mailserver's documentation! +============================================ + +.. image:: ../logo/logo.png + :width: 400 + :alt: SNM Logo + +.. toctree:: + :maxdepth: 2 + + quick-start + setup-guide + howto-develop + backup-guide + howto-add-radicale + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/docs/quick-start.rst b/docs/quick-start.rst new file mode 100644 index 0000000..367ff13 --- /dev/null +++ b/docs/quick-start.rst @@ -0,0 +1,32 @@ +Quick Start +=========== + +.. code:: nix + + { config, pkgs, ... }: + { + imports = [ + (builtins.fetchTarball { + url = "https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/-/archive/v2.2.1/nixos-mailserver-v2.2.1.tar.gz"; + sha256 = "03d49v8qnid9g9rha0wg2z6vic06mhp0b049s3whccn1axvs2zzx"; + }) + ]; + + + mailserver = { + enable = true; + fqdn = "mail.example.com"; + domains = [ "example.com" "example2.com" ]; + loginAccounts = { + "user1@example.com" = { + hashedPassword = "$6$/z4n8AQl6K$kiOkBTWlZfBd7PvF5GsJ8PmPgdZsFGN1jPGZufxxr60PoR0oUsrvzm2oQiflyz5ir9fFJ.d/zKm/NgLXNUsNX/"; + + aliases = [ + "info@example.com" + "postmaster@example.com" + "postmaster@example2.com" + ]; + }; + }; + }; + } diff --git a/docs/setup-guide.rst b/docs/setup-guide.rst new file mode 100644 index 0000000..35e3f5a --- /dev/null +++ b/docs/setup-guide.rst @@ -0,0 +1,242 @@ +A Complete 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 +``mail-tester.com``. + +What you need: + +- A server with a public IP (referred to as ``server-IP``) +- A Fully Qualified Domain Name (``FQDN``) where your server is + reachable, so that other servers can find yours. Common FQDN include + ``mx.example.com`` (where ``example.com`` is a domain you own) or + ``mail.example.com``. The domain is referred to as ``server-domain`` + (``example.com`` in the above example) and the ``FQDN`` is referred + to by ``server-FQDN`` (``mx.example.com`` above). +- A list of domains you want to your email server to serve. (Note that + this does not have to include ``server-domain``, but may of course). + These will be referred to as ``domains``. As an example, + ``domains = [ example1.com, example2.com ]``. + +A) Setup server +~~~~~~~~~~~~~~~ + +The following describes a server setup that is fairly complete. Even +though there are more possible options (see ``default.nix``), these +should be the most common ones. + +.. code:: nix + + { config, pkgs, ... }: + { + imports = [ + (builtins.fetchTarball { + # Pick a commit from the branch you are interested in + url = "https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/-/archive/A-COMMIT-ID/nixos-mailserver-A-COMMIT-ID.tar.gz"; + # And set its hash + sha256 = "0000000000000000000000000000000000000000000000000000"; + }) + ]; + + + mailserver = { + enable = true; + fqdn = ; + domains = [ ]; + + # A list of all login accounts. To create the password hashes, use + # mkpasswd -m sha-512 "super secret password" + loginAccounts = { + "user1@example.com" = { + hashedPassword = "$6$/z4n8AQl6K$kiOkBTWlZfBd7PvF5GsJ8PmPgdZsFGN1jPGZufxxr60PoR0oUsrvzm2oQiflyz5ir9fFJ.d/zKm/NgLXNUsNX/"; + + aliases = [ + "postmaster@example.com" + "postmaster@example2.com" + ]; + + # Make this user the catchAll address for domains example.com and + # example2.com + catchAll = [ + "example.com" + "example2.com" + ]; + }; + + "user2@example.com" = { ... }; + }; + + # Extra virtual aliases. These are email addresses that are forwarded to + # loginAccounts addresses. + extraVirtualAliases = { + # address = forward address; + "abuse@example.com" = "user1@example.com"; + }; + + # Use Let's Encrypt certificates. Note that this needs to set up a stripped + # down nginx and opens port 80. + certificateScheme = 3; + + # Enable IMAP and POP3 + enableImap = true; + enablePop3 = true; + enableImapSsl = true; + enablePop3Ssl = true; + + # Enable the ManageSieve protocol + enableManageSieve = true; + + # whether to scan inbound emails for viruses (note that this requires at least + # 1 Gb RAM for the server. Without virus scanning 256 MB RAM should be plenty) + virusScanning = false; + }; + } + +After a ``nixos-rebuild switch --upgrade`` your server should be good to +go. If you want to use ``nixops`` to deploy the server, look in the +subfolder ``nixops`` for some inspiration. + +B) Setup everything else +~~~~~~~~~~~~~~~~~~~~~~~~ + +Step 1: Set DNS entry for server +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Add a DNS record to the domain ``server-domain`` with the following +entries + +================ ===== ==== ======== ============= +Name (Subdomain) TTL Type Priority Value +================ ===== ==== ======== ============= +``server-FQDN`` 10800 A ``server-IP`` +================ ===== ==== ======== ============= + +This resolves DNS queries for ``server-FQDN`` to ``server-IP``. You can +test if your setting is correct by + +:: + + ping + 64 bytes from (): icmp_seq=1 ttl=46 time=21.3 ms + ... + +Note that it can take a while until a DNS entry is propagated. + +Step 2: Set rDNS (reverse DNS) entry for server +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Wherever you have rented your server, you should be able to set reverse +DNS entries for the IP’s you own. Add an entry resolving ``server-IP`` +to ``server-FQDN`` + +You can test if your setting is correct by + +:: + + host + .in-addr.arpa domain name pointer . + +Note that it can take a while until a DNS entry is propagated. + +Step 3: Set ``MX`` Records +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +For every ``domain`` in ``domains`` do: \* Add a ``MX`` record to the +domain ``domain`` + +:: + + | Name (Subdomain) | TTL | Type | Priority | Value | + | ---------------- | ----- | ---- | -------- | ----------------- | + | `domain` | | MX | 10 | `server-FQDN` | + +You can test this via + +:: + + dig -t MX + + ... + ;; ANSWER SECTION: + 10800 IN MX 10 + ... + +Note that it can take a while until a DNS entry is propagated. + +Step 4: Set ``SPF`` Records +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +For every ``domain`` in ``domains`` do: \* Add a ``SPF`` record to the +domain ``domain`` + +:: + + | Name (Subdomain) | TTL | Type | Priority | Value | + | ---------------- | ----- | ---- | -------- | ----------------- | + | `domain` | 10800 | TXT | | `v=spf1 ip4: -all` | + +You can check this with ``dig -t TXT `` similar to the last +section. Note that ``SPF`` records are set as ``TXT`` records since +RFC1035. + +Note that it can take a while until a DNS entry is propagated. If you +want to use multiple servers for your email handling, don’t forget to +add all server IP’s to this list. + +Step 5: Set ``DKIM`` signature +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In this section we assume that your ``dkimSelector`` is set to ``mail``. +If you have a different selector, replace all ``mail``\ ’s below +accordingly. + +For every ``domain`` in ``domains`` do: \* Go to your server and +navigate to the dkim key directory (by default ``/var/dkim``). There you +will find a public key for any domain in the ``domain.txt`` file. It +will look like +``mail._domainkey IN TXT "v=DKIM1; r=postmaster; g=*; k=rsa; p=" ; ----- DKIM mail for domain.tld`` +\* Add a ``DKIM`` record to the domain ``domain`` + +:: + + | Name (Subdomain) | TTL | Type | Priority | Value | + | ---------------- | ----- | ---- | -------- | ----------------- | + | mail._domainkey.`domain` | 10800 | TXT | | `v=DKIM1; p=` | + +You can check this with ``dig -t TXT mail._domainkey.`` similar +to the last section. + +Note that it can take a while until a DNS entry is propagated. + +Step 6: Set ``DMARC`` record +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +For every ``domain`` in ``domains`` do: + +- Add a ``DMARC`` record to the domain ``domain`` + + ==================== ===== ==== ======== ==================== + Name (Subdomain) TTL Type Priority Value + ==================== ===== ==== ======== ==================== + \_dmarc.\ ``domain`` 10800 TXT ``v=DMARC1; p=none`` + ==================== ===== ==== ======== ==================== + +You can check this with ``dig -t TXT _dmarc.`` similar to the +last section. + +Note that it can take a while until a DNS entry is propagated. + +C) Test your Setup +~~~~~~~~~~~~~~~~~~ + +Write an email to your aunt (who has been waiting for your reply far too +long), and sign up for some of the finest newsletters the Internet has. +Maybe you want to sign up for the `SNM Announcement +List `__? + +Besides that, you can send an email to +`mail-tester.com `__ and see how you +score, and let `mxtoolbox.com `__ take a look at +your setup, but if you followed the steps closely then everything should +be awesome! diff --git a/shell.nix b/shell.nix index 2c0d7f6..2c06231 100644 --- a/shell.nix +++ b/shell.nix @@ -1,9 +1,11 @@ -{ nixpkgs ? , system ? builtins.currentSystem }: - -with (import nixpkgs { inherit system; }); stdenv.mkDerivation rec { - name = "nixos-mailserver-env"; - env = buildEnv { name = name; paths = buildInputs; }; +let + nixpkgs = (import ./nix/sources.nix).nixpkgs-unstable; + pkgs = import nixpkgs {}; +in +pkgs.mkShell { buildInputs = with pkgs; [ - jq clamav + (python3.withPackages(p: [p.sphinx p.sphinx_rtd_theme])) + niv + jq clamav ]; }