From 4fcab839d7fe55cb6544ac57e615dd3c09cfeeb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Na=C3=AFm=20Favier?= Date: Wed, 30 Nov 2022 22:30:45 +0100 Subject: [PATCH] docs: use MarkDown for option docs --- .readthedocs.yaml | 4 +- default.nix | 51 +- docs/add-roundcube.rst | 2 +- docs/conf.py | 12 +- docs/howto-develop.rst | 8 +- docs/options.md | 1202 ++++++++++++++++++++++++++++ docs/options.rst | 1319 ------------------------------- docs/requirements.txt | 6 +- flake.lock | 17 + flake.nix | 90 +-- scripts/generate-options.py | 81 ++ scripts/generate-rst-options.py | 87 -- shell.nix | 11 +- 13 files changed, 1403 insertions(+), 1487 deletions(-) create mode 100644 docs/options.md delete mode 100644 docs/options.rst create mode 100644 scripts/generate-options.py delete mode 100644 scripts/generate-rst-options.py diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 3918d82..eb6988e 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -5,9 +5,9 @@ version: 2 build: - os: ubuntu-20.04 + os: ubuntu-22.04 tools: - python: "3.9" + python: "3" sphinx: configuration: docs/conf.py diff --git a/default.nix b/default.nix index 275ac83..ef27f43 100644 --- a/default.nix +++ b/default.nix @@ -79,7 +79,7 @@ in ``` Warning: this is stored in plaintext in the Nix store! - Use `hashedPasswordFile` instead. + Use {option}`mailserver.loginAccounts..hashedPasswordFile` instead. ''; }; @@ -156,7 +156,7 @@ in description = '' Specifies if the account should be a send-only account. Emails sent to send-only accounts will be rejected from - unauthorized senders with the sendOnlyRejectMessage + unauthorized senders with the `sendOnlyRejectMessage` stating the reason. ''; }; @@ -200,7 +200,7 @@ in description = '' Folder to store search indices. If null, indices are stored along with email, which could not necessarily be desirable, - especially when the fullTextSearch option is enable since + especially when {option}`mailserver.fullTextSearch.enable` is `true` since indices it creates are voluminous and do not need to be backed up. @@ -242,8 +242,8 @@ in default = "no"; description = '' Fail searches when no index is available. If set to - body, then only body searches (as opposed to - header) are affected. If set to no, searches may + `body`, then only body searches (as opposed to + header) are affected. If set to `no`, searches may fall back to a very slow brute force search. ''; }; @@ -281,7 +281,7 @@ in randomizedDelaySec = mkOption { type = types.int; default = 1000; - description = "Run the maintenance job not exactly at the time specified with onCalendar, but plus or minus this many seconds."; + description = "Run the maintenance job not exactly at the time specified with `onCalendar`, but plus or minus this many seconds."; }; }; }; @@ -333,7 +333,7 @@ in the value {`"user@example.com" = "user@elsewhere.com";}` means that mails to `user@example.com` are forwarded to `user@elsewhere.com`. The difference with the - `extraVirtualAliases` option is that `user@elsewhere.com` + {option}`mailserver.extraVirtualAliases` option is that `user@elsewhere.com` can't send mail as `user@example.com`. Also, this option allows to forward mails to external addresses. ''; @@ -367,7 +367,7 @@ in description = '' The unix UID of the virtual mail user. Be mindful that if this is changed, you will need to manually adjust the permissions of - mailDirectory. + `mailDirectory`. ''; }; @@ -582,7 +582,7 @@ in type = types.str; default = "mail"; description = '' - + The DKIM selector. ''; }; @@ -590,7 +590,7 @@ in type = types.path; default = "/var/dkim"; description = '' - + The DKIM directory. ''; }; @@ -601,7 +601,7 @@ in How many bits in generated DKIM keys. RFC6376 advises minimum 1024-bit keys. If you have already deployed a key with a different number of bits than specified - here, then you should use a different selector (dkimSelector). In order to get + here, then you should use a different selector ({option}`mailserver.dkimSelector`). In order to get this package to generate a key with the new number of bits, you will either have to change the selector or delete the old key file. ''; @@ -673,7 +673,7 @@ in type = types.str; example = "ACME Corp."; description = '' - The name of your organization used in the org_name attribute in + The name of your organization used in the `org_name` attribute in DMARC reports. ''; }; @@ -681,7 +681,7 @@ in fromName = mkOption { type = types.str; default = cfg.dmarcReporting.organizationName; - defaultText = literalExpression "organizationName"; + defaultText = literalMD "{option}`mailserver.dmarcReporting.organizationName`"; description = '' The sender name for DMARC reports. Defaults to the organization name. ''; @@ -738,7 +738,7 @@ in if (ip == "0.0.0.0" || ip == "::") then "127.0.0.1" else if isIpv6 ip then "[${ip}]" else ip; - defaultText = lib.literalDocBook "computed from "; + defaultText = lib.literalMD "computed from `config.services.redis.servers.rspamd.bind`"; description = '' Address that rspamd should use to contact redis. ''; @@ -776,7 +776,7 @@ in sendingFqdn = mkOption { type = types.str; default = cfg.fqdn; - defaultText = "config.mailserver.fqdn"; + defaultText = lib.literalMD "{option}`mailserver.fqdn`"; example = "myserver.example.com"; description = '' The fully qualified domain name of the mail server used to @@ -792,7 +792,7 @@ in This setting allows the server to identify as myserver.example.com when forwarding mail, independently of - `fqdn` (which, for SSL reasons, should generally be the name + {option}`mailserver.fqdn` (which, for SSL reasons, should generally be the name to which the user connects). Set this to the name to which the sending IP's reverse DNS @@ -864,7 +864,7 @@ in start program = "${pkgs.systemd}/bin/systemctl start rspamd" stop program = "${pkgs.systemd}/bin/systemctl stop rspamd" ''; - defaultText = lib.literalDocBook "see source"; + defaultText = lib.literalMD "see [source](https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/-/blob/master/default.nix)"; description = '' The configuration used for monitoring via monit. Use a mail address that you actively check and set it via 'set alert ...'. @@ -881,7 +881,8 @@ in description = '' The location where borg saves the backups. This can be a local path or a remote location such as user@host:/path/to/repo. - It is exported and thus available as an environment variable to cmdPreexec and cmdPostexec. + It is exported and thus available as an environment variable to + {option}`mailserver.borgbackup.cmdPreexec` and {option}`mailserver.borgbackup.cmdPostexec`. ''; }; @@ -941,7 +942,7 @@ in default = "none"; description = '' The backup can be encrypted by choosing any other value than 'none'. - When using encryption the password / passphrase must be provided in passphraseFile. + When using encryption the password/passphrase must be provided in `passphraseFile`. ''; }; @@ -964,6 +965,7 @@ in locations = mkOption { type = types.listOf types.path; default = [cfg.mailDirectory]; + defaultText = lib.literalExpression "[ config.mailserver.mailDirectory ]"; description = "The locations that are to be backed up by borg."; }; @@ -984,9 +986,10 @@ in default = null; description = '' The command to be executed before each backup operation. - This is called prior to borg init in the same script that runs borg init and create and cmdPostexec. - Example: - export BORG_RSH="ssh -i /path/to/private/key" + This is called prior to borg init in the same script that runs borg init and create and `cmdPostexec`. + ''; + example = '' + export BORG_RSH="ssh -i /path/to/private/key" ''; }; @@ -996,7 +999,7 @@ in description = '' The command to be executed after each backup operation. This is called after borg create completed successfully and in the same script that runs - cmdPreexec, borg init and create. + `cmdPreexec`, borg init and create. ''; }; @@ -1009,7 +1012,7 @@ in example = true; description = '' Whether to enable automatic reboot after kernel upgrades. - This is to be used in conjunction with system.autoUpgrade.enable = true" + This is to be used in conjunction with `system.autoUpgrade.enable = true;` ''; }; method = mkOption { diff --git a/docs/add-roundcube.rst b/docs/add-roundcube.rst index 6d4795c..4e6be83 100644 --- a/docs/add-roundcube.rst +++ b/docs/add-roundcube.rst @@ -1,5 +1,5 @@ Add Roundcube, a webmail -======================= +======================== The NixOS module for roundcube nearly works out of the box with SNM. By default, it sets up a nginx virtual host to serve the webmail, other web diff --git a/docs/conf.py b/docs/conf.py index 84eb68b..1845917 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -18,7 +18,7 @@ # -- Project information ----------------------------------------------------- project = 'NixOS Mailserver' -copyright = '2020, NixOS Mailserver Contributors' +copyright = '2022, NixOS Mailserver Contributors' author = 'NixOS Mailserver Contributors' @@ -28,8 +28,16 @@ author = 'NixOS Mailserver Contributors' # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ + 'myst_parser' ] +myst_enable_extensions = [ + 'colon_fence', + 'linkify', +] + +smartquotes = False + # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -50,4 +58,4 @@ 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'] +html_static_path = [] diff --git a/docs/howto-develop.rst b/docs/howto-develop.rst index ce74683..0ac9009 100644 --- a/docs/howto-develop.rst +++ b/docs/howto-develop.rst @@ -30,8 +30,8 @@ run tests manually. For instance: Contributing to the documentation --------------------------------- -The documentation is written in RST, build with Sphinx and published -by `Read the Docs `_. +The documentation is written in RST (except option documentation which is in MarkDown), +built with Sphinx and published by `Read the Docs `_. For the syntax, see `RST/Sphinx Cheatsheet `_. @@ -47,11 +47,11 @@ documentation: $ firefox ./_build/html/index.html Note if you modify some NixOS mailserver options, you would also need -to regenerate the ``options.rst`` file: +to regenerate the ``options.md`` file: :: - $ nix-shell --run generate-rst-options + $ nix-shell --run generate-options Nixops ------ diff --git a/docs/options.md b/docs/options.md new file mode 100644 index 0000000..0944fa7 --- /dev/null +++ b/docs/options.md @@ -0,0 +1,1202 @@ + +# Mailserver options + +## `mailserver` + + + +`````{option} mailserver.debug +Whether to enable verbose logging for mailserver related services. This +intended be used for development purposes only, you probably don't want +to enable this unless you're hacking on nixos-mailserver. + + +- type: ```boolean``` +- default: ```False``` + +````` + + +`````{option} mailserver.domains +The domains that this mail server serves. + +- type: ```list of string``` +- default: ```[]``` +- example: ```['example.com']``` +````` + + +`````{option} mailserver.enable +Whether to enable nixos-mailserver. + +- type: ```boolean``` +- default: ```False``` +- example: ```True``` +````` + + +`````{option} mailserver.enableImap +Whether to enable IMAP with STARTTLS on port 143. + + +- type: ```boolean``` +- default: ```True``` + +````` + + +`````{option} mailserver.enableImapSsl +Whether to enable IMAP with TLS in wrapper-mode on port 993. + + +- type: ```boolean``` +- default: ```True``` + +````` + + +`````{option} mailserver.enableManageSieve +Whether to enable ManageSieve, setting this option to true will open +port 4190 in the firewall. + +The ManageSieve protocol allows users to manage their Sieve scripts on +a remote server with a supported client, including Thunderbird. + + +- type: ```boolean``` +- default: ```False``` + +````` + + +`````{option} mailserver.enablePop3 +Whether to enable POP3 with STARTTLS on port on port 110. + + +- type: ```boolean``` +- default: ```False``` + +````` + + +`````{option} mailserver.enablePop3Ssl +Whether to enable POP3 with TLS in wrapper-mode on port 995. + + +- type: ```boolean``` +- default: ```False``` + +````` + + +`````{option} mailserver.enableSubmission +Whether to enable SMTP with STARTTLS on port 587. + + +- type: ```boolean``` +- default: ```True``` + +````` + + +`````{option} mailserver.enableSubmissionSsl +Whether to enable SMTP with TLS in wrapper-mode on port 465. + + +- type: ```boolean``` +- default: ```True``` + +````` + + +`````{option} mailserver.extraVirtualAliases +Virtual Aliases. A virtual alias `"info@example.com" = "user1@example.com"` means that +all mail to `info@example.com` is forwarded to `user1@example.com`. Note +that it is expected that `postmaster@example.com` and `abuse@example.com` is +forwarded to some valid email address. (Alternatively you can create login +accounts for `postmaster` and (or) `abuse`). Furthermore, it also allows +the user `user1@example.com` to send emails as `info@example.com`. +It's also possible to create an alias for multiple accounts. In this +example all mails for `multi@example.com` will be forwarded to both +`user1@example.com` and `user2@example.com`. + + +- type: ```attribute set of ((Login Account) or non-empty (list of (Login Account)))``` +- default: ```{}``` +- example: ```{'abuse@example.com': 'user1@example.com', 'info@example.com': 'user1@example.com', 'multi@example.com': ['user1@example.com', 'user2@example.com'], 'postmaster@example.com': 'user1@example.com'}``` +````` + + +`````{option} mailserver.forwards +To forward mails to an external address. For instance, +the value {`"user@example.com" = "user@elsewhere.com";}` +means that mails to `user@example.com` are forwarded to +`user@elsewhere.com`. The difference with the +{option}`mailserver.extraVirtualAliases` option is that `user@elsewhere.com` +can't send mail as `user@example.com`. Also, this option +allows to forward mails to external addresses. + + +- type: ```attribute set of ((list of string) or string)``` +- default: ```{}``` +- example: ```{'user@example.com': 'user@elsewhere.com'}``` +````` + + +`````{option} mailserver.fqdn +The fully qualified domain name of the mail server. + +- type: ```string``` + +- example: ```mx.example.com``` +````` + + +`````{option} mailserver.hierarchySeparator +The hierarchy separator for mailboxes used by dovecot for the namespace 'inbox'. +Dovecot defaults to "." but recommends "/". +This affects how mailboxes appear to mail clients and sieve scripts. +For instance when using "." then in a sieve script "example.com" would refer to the mailbox "com" in the parent mailbox "example". +This does not determine the way your mails are stored on disk. +See https://wiki.dovecot.org/Namespaces for details. + + +- type: ```string``` +- default: ```.``` + +````` + + +`````{option} mailserver.indexDir +Folder to store search indices. If null, indices are stored +along with email, which could not necessarily be desirable, +especially when {option}`mailserver.fullTextSearch.enable` is `true` since +indices it creates are voluminous and do not need to be backed +up. + +Be careful when changing this option value since all indices +would be recreated at the new location (and clients would need +to resynchronize). + +Note the some variables can be used in the file path. See +https://doc.dovecot.org/configuration_manual/mail_location/#variables +for details. + + +- type: ```null or string``` +- default: ```None``` +- example: ```/var/lib/dovecot/indices``` +````` + + +`````{option} mailserver.keyFile +Scheme 1) +Location of the key file + + +- type: ```path``` + +- example: ```/root/mail-server.key``` +````` + + +`````{option} mailserver.lmtpSaveToDetailMailbox +If an email address is delimited by a "+", should it be filed into a +mailbox matching the string after the "+"? For example, +user1+test@example.com would be filed into the mailbox "test". + + +- type: ```one of "yes", "no"``` +- default: ```yes``` + +````` + + +`````{option} mailserver.localDnsResolver +Runs a local DNS resolver (kresd) as recommended when running rspamd. This prevents your log file from filling up with rspamd_monitored_dns_mon entries. + + +- type: ```boolean``` +- default: ```True``` + +````` + + +`````{option} mailserver.mailDirectory +Where to store the mail. + + +- type: ```path``` +- default: ```/var/vmail``` + +````` + + +`````{option} mailserver.mailboxes +The mailboxes for dovecot. +Depending on the mail client used it might be necessary to change some mailbox's name. + + +- type: ```unspecified value``` +- default: ```{'Drafts': {'auto': 'subscribe', 'specialUse': 'Drafts'}, 'Junk': {'auto': 'subscribe', 'specialUse': 'Junk'}, 'Sent': {'auto': 'subscribe', 'specialUse': 'Sent'}, 'Trash': {'auto': 'no', 'specialUse': 'Trash'}}``` + +````` + + +`````{option} mailserver.maxConnectionsPerUser +Maximum number of IMAP/POP3 connections allowed for a user from each IP address. +E.g. a value of 50 allows for 50 IMAP and 50 POP3 connections at the same +time for a single user. + + +- type: ```signed integer``` +- default: ```100``` + +````` + + +`````{option} mailserver.messageSizeLimit +Message size limit enforced by Postfix. + +- type: ```signed integer``` +- default: ```20971520``` +- example: ```52428800``` +````` + + +`````{option} mailserver.openFirewall +Automatically open ports in the firewall. + +- type: ```boolean``` +- default: ```True``` + +````` + + +`````{option} mailserver.policydSPFExtraConfig +Extra configuration options for policyd-spf. This can be use to among +other things skip spf checking for some IP addresses. + + +- type: ```strings concatenated with "\n"``` +- default: `""` +- example: +``` +skip_addresses = 127.0.0.0/8,::ffff:127.0.0.0/104,::1 +``` +````` + + +`````{option} mailserver.rebootAfterKernelUpgrade.enable +Whether to enable automatic reboot after kernel upgrades. +This is to be used in conjunction with `system.autoUpgrade.enable = true;` + + +- type: ```boolean``` +- default: ```False``` +- example: ```True``` +````` + + +`````{option} mailserver.rebootAfterKernelUpgrade.method +Whether to issue a full "reboot" or just a "systemctl kexec"-only reboot. +It is recommended to use the default value because the quicker kexec reboot has a number of problems. +Also if your server is running in a virtual machine the regular reboot will already be very quick. + + +- type: ```one of "reboot", "systemctl kexec"``` +- default: ```reboot``` + +````` + + +`````{option} mailserver.recipientDelimiter +Configure the recipient delimiter. + + +- type: ```string``` +- default: ```+``` + +````` + + +`````{option} mailserver.rejectRecipients +Reject emails addressed to these local addresses from unauthorized senders. +Use if a spammer has found email addresses in a catchall domain but you do +not want to disable the catchall. + + +- type: ```list of string``` +- default: ```[]``` +- example: ```['sales@example.com', 'info@example.com']``` +````` + + +`````{option} mailserver.rejectSender +Reject emails from these addresses from unauthorized senders. +Use if a spammer is using the same domain or the same sender over and over. + + +- type: ```list of string``` +- default: ```[]``` +- example: ```['@example.com', 'spammer@example.net']``` +````` + + +`````{option} mailserver.rewriteMessageId +Rewrites the Message-ID's hostname-part of outgoing emails to the FQDN. +Please be aware that this may cause problems with some mail clients +relying on the original Message-ID. + + +- type: ```boolean``` +- default: ```False``` + +````` + + +`````{option} mailserver.sendingFqdn +The fully qualified domain name of the mail server used to +identify with remote servers. + +If this server's IP serves purposes other than a mail server, +it may be desirable for the server to have a name other than +that to which the user will connect. For example, the user +might connect to mx.example.com, but the server's IP has +reverse DNS that resolves to myserver.example.com; in this +scenario, some mail servers may reject or penalize the +message. + +This setting allows the server to identify as +myserver.example.com when forwarding mail, independently of +{option}`mailserver.fqdn` (which, for SSL reasons, should generally be the name +to which the user connects). + +Set this to the name to which the sending IP's reverse DNS +resolves. + + +- type: ```string``` +- default: {option}`mailserver.fqdn` +- example: ```myserver.example.com``` +````` + + +`````{option} mailserver.sieveDirectory +Where to store the sieve scripts. + + +- type: ```path``` +- default: ```/var/sieve``` + +````` + + +`````{option} mailserver.useFsLayout +Sets whether dovecot should organize mail in subdirectories: + +- /var/vmail/example.com/user/.folder.subfolder/ (default layout) +- /var/vmail/example.com/user/folder/subfolder/ (FS layout) + +See https://wiki2.dovecot.org/MailboxFormat/Maildir for details. + + +- type: ```boolean``` +- default: ```False``` + +````` + + +`````{option} mailserver.virusScanning +Whether to activate virus scanning. Note that virus scanning is _very_ +expensive memory wise. + + +- type: ```boolean``` +- default: ```False``` + +````` + + +`````{option} mailserver.vmailGroupName +The user name and group name of the user that owns the directory where all +the mail is stored. + + +- type: ```string``` +- default: ```virtualMail``` + +````` + + +`````{option} mailserver.vmailUID +The unix UID of the virtual mail user. Be mindful that if this is +changed, you will need to manually adjust the permissions of +`mailDirectory`. + + +- type: ```signed integer``` +- default: ```5000``` + +````` + + +`````{option} mailserver.vmailUserName +The user name and group name of the user that owns the directory where all +the mail is stored. + + +- type: ```string``` +- default: ```virtualMail``` + +````` + +## `mailserver.loginAccounts` + + +`````{option} mailserver.loginAccounts +The login account of the domain. Every account is mapped to a unix user, +e.g. `user1@example.com`. To generate the passwords use `mkpasswd` as +follows + +``` +nix-shell -p mkpasswd --run 'mkpasswd -sm bcrypt' +``` + + +- type: ```attribute set of (submodule)``` +- default: ```{}``` +- example: ```{'user1': {'hashedPassword': '$6$evQJs5CFQyPAW09S$Cn99Y8.QjZ2IBnSu4qf1vBxDRWkaIZWOtmu1Ddsm3.H3CFpeVc0JU4llIq8HQXgeatvYhh5O33eWG3TSpjzu6/'}, 'user2': {'hashedPassword': '$6$oE0ZNv2n7Vk9gOf$9xcZWCCLGdMflIfuA0vR1Q1Xblw6RZqPrP94mEit2/81/7AKj2bqUai5yPyWE.QYPyv6wLMHZvjw3Rlg7yTCD/'}}``` +````` + + +`````{option} mailserver.loginAccounts..aliases +A list of aliases of this login account. +Note: Use list entries like "@example.com" to create a catchAll +that allows sending from all email addresses in these domain. + + +- type: ```list of string``` +- default: ```[]``` +- example: ```['abuse@example.com', 'postmaster@example.com']``` +````` + + +`````{option} mailserver.loginAccounts..catchAll +For which domains should this account act as a catch all? +Note: Does not allow sending from all addresses of these domains. + + +- type: ```list of value "example.com" (singular enum)``` +- default: ```[]``` +- example: ```['example.com', 'example2.com']``` +````` + + +`````{option} mailserver.loginAccounts..hashedPassword +The user's hashed password. Use `mkpasswd` as follows + +``` +nix-shell -p mkpasswd --run 'mkpasswd -sm bcrypt' +``` + +Warning: this is stored in plaintext in the Nix store! +Use {option}`mailserver.loginAccounts..hashedPasswordFile` instead. + + +- type: ```null or string``` +- default: ```None``` +- example: ```$6$evQJs5CFQyPAW09S$Cn99Y8.QjZ2IBnSu4qf1vBxDRWkaIZWOtmu1Ddsm3.H3CFpeVc0JU4llIq8HQXgeatvYhh5O33eWG3TSpjzu6/``` +````` + + +`````{option} mailserver.loginAccounts..hashedPasswordFile +A file containing the user's hashed password. Use `mkpasswd` as follows + +``` +nix-shell -p mkpasswd --run 'mkpasswd -sm bcrypt' +``` + + +- type: ```null or path``` +- default: ```None``` +- example: ```/run/keys/user1-passwordhash``` +````` + + +`````{option} mailserver.loginAccounts..name +Username + +- type: ```string``` + +- example: ```user1@example.com``` +````` + + +`````{option} mailserver.loginAccounts..quota +Per user quota rules. Accepted sizes are `xx k/M/G/T` with the +obvious meaning. Leave blank for the standard quota `100G`. + + +- type: ```null or string``` +- default: ```None``` +- example: ```2G``` +````` + + +`````{option} mailserver.loginAccounts..sendOnly +Specifies if the account should be a send-only account. +Emails sent to send-only accounts will be rejected from +unauthorized senders with the `sendOnlyRejectMessage` +stating the reason. + + +- type: ```boolean``` +- default: ```False``` + +````` + + +`````{option} mailserver.loginAccounts..sendOnlyRejectMessage +The message that will be returned to the sender when an email is +sent to a send-only account. Only used if the account is marked +as send-only. + + +- type: ```string``` +- default: ```This account cannot receive emails.``` + +````` + + +`````{option} mailserver.loginAccounts..sieveScript +Per-user sieve script. + + +- type: ```null or strings concatenated with "\n"``` +- default: ```None``` +- example: +``` +require ["fileinto", "mailbox"]; + +if address :is "from" "gitlab@mg.gitlab.com" { + fileinto :create "GitLab"; + stop; +} + +# This must be the last rule, it will check if list-id is set, and +# file the message into the Lists folder for further investigation +elsif header :matches "list-id" "" { + fileinto :create "Lists"; + stop; +} +``` +````` + +## `mailserver.certificate` + + +`````{option} mailserver.certificateDirectory +Scheme 2) +This is the folder where the certificate will be created. The name is +hardcoded to "cert-DOMAIN.pem" and "key-DOMAIN.pem" and the +certificate is valid for 10 years. + + +- type: ```path``` +- default: ```/var/certs``` + +````` + + +`````{option} mailserver.certificateDomains +Secondary domains and subdomains for which it is necessary to generate a certificate. + +- type: ```list of string``` +- default: ```[]``` +- example: ```['imap.example.com', 'pop3.example.com']``` +````` + + +`````{option} mailserver.certificateFile +Scheme 1) +Location of the certificate + + +- type: ```path``` + +- example: ```/root/mail-server.crt``` +````` + + +`````{option} mailserver.certificateScheme +Certificate Files. There are three options for these. + +1) You specify locations and manually copy certificates there. +2) You let the server create new (self signed) certificates on the fly. +3) You let the server create a certificate via `Let's Encrypt`. Note that + this implies that a stripped down webserver has to be started. This also + implies that the FQDN must be set as an `A` record to point to the IP of + the server. In particular port 80 on the server will be opened. For details + on how to set up the domain records, see the guide in the readme. + + +- type: ```one of 1, 2, 3``` +- default: ```2``` + +````` + +## `mailserver.dkim` + + +`````{option} mailserver.dkimBodyCanonicalization +DKIM canonicalization algorithm for message bodies. + +See https://datatracker.ietf.org/doc/html/rfc6376/#section-3.4 for details. + + +- type: ```one of "relaxed", "simple"``` +- default: ```relaxed``` + +````` + + +`````{option} mailserver.dkimHeaderCanonicalization +DKIM canonicalization algorithm for message headers. + +See https://datatracker.ietf.org/doc/html/rfc6376/#section-3.4 for details. + + +- type: ```one of "relaxed", "simple"``` +- default: ```relaxed``` + +````` + + +`````{option} mailserver.dkimKeyBits +How many bits in generated DKIM keys. RFC6376 advises minimum 1024-bit keys. + +If you have already deployed a key with a different number of bits than specified +here, then you should use a different selector ({option}`mailserver.dkimSelector`). In order to get +this package to generate a key with the new number of bits, you will either have to +change the selector or delete the old key file. + + +- type: ```signed integer``` +- default: ```1024``` + +````` + + +`````{option} mailserver.dkimKeyDirectory +The DKIM directory. + + +- type: ```path``` +- default: ```/var/dkim``` + +````` + + +`````{option} mailserver.dkimSelector +The DKIM selector. + + +- type: ```string``` +- default: ```mail``` + +````` + + +`````{option} mailserver.dkimSigning +Whether to activate dkim signing. + + +- type: ```boolean``` +- default: ```True``` + +````` + +## `mailserver.dmarcReporting` + + +`````{option} mailserver.dmarcReporting.domain +The domain from which outgoing DMARC reports are served. + + +- type: ```value "example.com" (singular enum)``` + +- example: ```example.com``` +````` + + +`````{option} mailserver.dmarcReporting.email +The email address used for outgoing DMARC reports. Read-only. + + +- type: ```string``` +- default: ```"${localpart}@${domain}"``` + +````` + + +`````{option} mailserver.dmarcReporting.enable +Whether to send out aggregated, daily DMARC reports in response to incoming +mail, when the sender domain defines a DMARC policy including the RUA tag. + +This is helpful for the mail ecosystem, because it allows third parties to +get notified about SPF/DKIM violations originating from their sender domains. + +See https://rspamd.com/doc/modules/dmarc.html#reporting + + +- type: ```boolean``` +- default: ```False``` + +````` + + +`````{option} mailserver.dmarcReporting.fromName +The sender name for DMARC reports. Defaults to the organization name. + + +- type: ```string``` +- default: {option}`mailserver.dmarcReporting.organizationName` + +````` + + +`````{option} mailserver.dmarcReporting.localpart +The local part of the email address used for outgoing DMARC reports. + + +- type: ```string``` +- default: ```dmarc-noreply``` +- example: ```dmarc-report``` +````` + + +`````{option} mailserver.dmarcReporting.organizationName +The name of your organization used in the `org_name` attribute in +DMARC reports. + + +- type: ```string``` + +- example: ```ACME Corp.``` +````` + +## `mailserver.fullTextSearch` + + +`````{option} mailserver.fullTextSearch.autoIndex +Enable automatic indexing of messages as they are received or modified. + +- type: ```boolean``` +- default: ```True``` + +````` + + +`````{option} mailserver.fullTextSearch.autoIndexExclude +Mailboxes to exclude from automatic indexing. + + +- type: ```list of string``` +- default: ```[]``` +- example: ```['\\Trash', 'SomeFolder', 'Other/*']``` +````` + + +`````{option} mailserver.fullTextSearch.enable +Whether to enable Full text search indexing with xapian. This has significant performance and disk space cost.. + +- type: ```boolean``` +- default: ```False``` +- example: ```True``` +````` + + +`````{option} mailserver.fullTextSearch.enforced +Fail searches when no index is available. If set to +`body`, then only body searches (as opposed to +header) are affected. If set to `no`, searches may +fall back to a very slow brute force search. + + +- type: ```one of "yes", "no", "body"``` +- default: ```no``` + +````` + + +`````{option} mailserver.fullTextSearch.indexAttachments +Also index text-only attachements. Binary attachements are never indexed. + +- type: ```boolean``` +- default: ```False``` + +````` + + +`````{option} mailserver.fullTextSearch.maintenance.enable +Regularly optmize indices, as recommended by upstream. + +- type: ```boolean``` +- default: ```True``` + +````` + + +`````{option} mailserver.fullTextSearch.maintenance.onCalendar +When to run the maintenance job. See systemd.time(7) for more information about the format. + +- type: ```string``` +- default: ```daily``` + +````` + + +`````{option} mailserver.fullTextSearch.maintenance.randomizedDelaySec +Run the maintenance job not exactly at the time specified with `onCalendar`, but plus or minus this many seconds. + +- type: ```signed integer``` +- default: ```1000``` + +````` + + +`````{option} mailserver.fullTextSearch.maxSize +Size of the largest n-gram to index. + +- type: ```signed integer``` +- default: ```20``` + +````` + + +`````{option} mailserver.fullTextSearch.memoryLimit +Memory limit for the indexer process, in MiB. If null, leaves the default (which is rather low), and if 0, no limit. + +- type: ```null or signed integer``` +- default: ```None``` +- example: ```2000``` +````` + + +`````{option} mailserver.fullTextSearch.minSize +Size of the smallest n-gram to index. + +- type: ```signed integer``` +- default: ```2``` + +````` + +## `mailserver.redis` + + +`````{option} mailserver.redis.address +Address that rspamd should use to contact redis. + + +- type: ```string``` +- default: computed from `config.services.redis.servers.rspamd.bind` + +````` + + +`````{option} mailserver.redis.password +Password that rspamd should use to contact redis, or null if not required. + + +- type: ```null or string``` +- default: ```config.services.redis.servers.rspamd.requirePass``` + +````` + + +`````{option} mailserver.redis.port +Port that rspamd should use to contact redis. + + +- type: ```16 bit unsigned integer; between 0 and 65535 (both inclusive)``` +- default: ```config.services.redis.servers.rspamd.port``` + +````` + +## `mailserver.monitoring` + + +`````{option} mailserver.monitoring.alertAddress +The email address to send alerts to. + + +- type: ```string``` + + +````` + + +`````{option} mailserver.monitoring.config +The configuration used for monitoring via monit. +Use a mail address that you actively check and set it via 'set alert ...'. + + +- type: ```string``` +- default: see [source](https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/-/blob/master/default.nix) + +````` + + +`````{option} mailserver.monitoring.enable +Whether to enable monitoring via monit. + +- type: ```boolean``` +- default: ```False``` +- example: ```True``` +````` + +## `mailserver.backup` + + +`````{option} mailserver.backup.cmdPostexec +The command to be executed after each backup operation. This is wrapped in a shell script to be called by rsnapshot. + +- type: ```null or string``` +- default: ```None``` + +````` + + +`````{option} mailserver.backup.cmdPreexec +The command to be executed before each backup operation. This is wrapped in a shell script to be called by rsnapshot. + + +- type: ```null or string``` +- default: ```None``` + +````` + + +`````{option} mailserver.backup.cronIntervals +Periodicity at which intervals should be run by cron. +Note that the intervals also have to exist in configuration +as retain options. + + +- type: ```attribute set of string``` +- default: ```{'daily': '30 3 * * *', 'hourly': ' 0 * * * *', 'weekly': ' 0 5 * * 0'}``` + +````` + + +`````{option} mailserver.backup.enable +Whether to enable backup via rsnapshot. + +- type: ```boolean``` +- default: ```False``` +- example: ```True``` +````` + + +`````{option} mailserver.backup.retain.daily +How many daily snapshots are retained. + +- type: ```signed integer``` +- default: ```7``` + +````` + + +`````{option} mailserver.backup.retain.hourly +How many hourly snapshots are retained. + +- type: ```signed integer``` +- default: ```24``` + +````` + + +`````{option} mailserver.backup.retain.weekly +How many weekly snapshots are retained. + +- type: ```signed integer``` +- default: ```54``` + +````` + + +`````{option} mailserver.backup.snapshotRoot +The directory where rsnapshot stores the backup. + + +- type: ```path``` +- default: ```/var/rsnapshot``` + +````` + +## `mailserver.borgbackup` + + +`````{option} mailserver.borgbackup.cmdPostexec +The command to be executed after each backup operation. +This is called after borg create completed successfully and in the same script that runs +`cmdPreexec`, borg init and create. + + +- type: ```null or string``` +- default: ```None``` + +````` + + +`````{option} mailserver.borgbackup.cmdPreexec +The command to be executed before each backup operation. +This is called prior to borg init in the same script that runs borg init and create and `cmdPostexec`. + + +- type: ```null or string``` +- default: ```None``` +- example: +``` +export BORG_RSH="ssh -i /path/to/private/key" +``` +````` + + +`````{option} mailserver.borgbackup.compression.auto +Leaves it to borg to determine whether an individual file should be compressed. + +- type: ```boolean``` +- default: ```False``` + +````` + + +`````{option} mailserver.borgbackup.compression.level +Denotes the level of compression used by borg. +Most methods accept levels from 0 to 9 but zstd which accepts values from 1 to 22. +If null the decision is left up to borg. + + +- type: ```null or signed integer``` +- default: ```None``` + +````` + + +`````{option} mailserver.borgbackup.compression.method +Leaving this unset allows borg to choose. The default for borg 1.1.4 is lz4. + +- type: ```null or one of "none", "lz4", "zstd", "zlib", "lzma"``` +- default: ```None``` + +````` + + +`````{option} mailserver.borgbackup.enable +Whether to enable backup via borgbackup. + +- type: ```boolean``` +- default: ```False``` +- example: ```True``` +````` + + +`````{option} mailserver.borgbackup.encryption.method +The backup can be encrypted by choosing any other value than 'none'. +When using encryption the password/passphrase must be provided in `passphraseFile`. + + +- type: ```one of "none", "authenticated", "authenticated-blake2", "repokey", "keyfile", "repokey-blake2", "keyfile-blake2"``` +- default: ```none``` + +````` + + +`````{option} mailserver.borgbackup.encryption.passphraseFile +Path to a file containing the encryption password or passphrase. + +- type: ```null or path``` +- default: ```None``` + +````` + + +`````{option} mailserver.borgbackup.extraArgumentsForCreate +Additional arguments to add to the borg create command line e.g. '--stats'. + +- type: ```list of string``` +- default: ```[]``` + +````` + + +`````{option} mailserver.borgbackup.extraArgumentsForInit +Additional arguments to add to the borg init command line. + +- type: ```list of string``` +- default: ```['--critical']``` + +````` + + +`````{option} mailserver.borgbackup.group +The group borg and its launch script is run as. + +- type: ```string``` +- default: ```virtualMail``` + +````` + + +`````{option} mailserver.borgbackup.locations +The locations that are to be backed up by borg. + +- type: ```list of path``` +- default: ```[ config.mailserver.mailDirectory ]``` + +````` + + +`````{option} mailserver.borgbackup.name +The name of the individual backups as used by borg. +Certain placeholders will be replaced by borg. + + +- type: ```string``` +- default: ```{hostname}-{user}-{now}``` + +````` + + +`````{option} mailserver.borgbackup.repoLocation +The location where borg saves the backups. +This can be a local path or a remote location such as user@host:/path/to/repo. +It is exported and thus available as an environment variable to +{option}`mailserver.borgbackup.cmdPreexec` and {option}`mailserver.borgbackup.cmdPostexec`. + + +- type: ```string``` +- default: ```/var/borgbackup``` + +````` + + +`````{option} mailserver.borgbackup.startAt +When or how often the backup should run. Must be in the format described in systemd.time 7. + +- type: ```string``` +- default: ```hourly``` + +````` + + +`````{option} mailserver.borgbackup.user +The user borg and its launch script is run as. + +- type: ```string``` +- default: ```virtualMail``` + +````` + diff --git a/docs/options.rst b/docs/options.rst deleted file mode 100644 index b8aef82..0000000 --- a/docs/options.rst +++ /dev/null @@ -1,1319 +0,0 @@ - -Mailserver Options -================== - -mailserver -~~~~~~~~~~ - - - -mailserver.debug ----------------- - -Whether to enable verbose logging for mailserver related services. This -intended be used for development purposes only, you probably don't want -to enable this unless you're hacking on nixos-mailserver. - - -- type: ``boolean`` -- default: ``False`` - - - -mailserver.domains ------------------- - -The domains that this mail server serves. - -- type: ``list of string`` -- default: ``[]`` -- example: ``['example.com']`` - - -mailserver.enable ------------------ - -Whether to enable nixos-mailserver. - -- type: ``boolean`` -- default: ``False`` -- example: ``True`` - - -mailserver.enableImap ---------------------- - -Whether to enable IMAP with STARTTLS on port 143. - - -- type: ``boolean`` -- default: ``True`` - - - -mailserver.enableImapSsl ------------------------- - -Whether to enable IMAP with TLS in wrapper-mode on port 993. - - -- type: ``boolean`` -- default: ``True`` - - - -mailserver.enableManageSieve ----------------------------- - -Whether to enable ManageSieve, setting this option to true will open -port 4190 in the firewall. - -The ManageSieve protocol allows users to manage their Sieve scripts on -a remote server with a supported client, including Thunderbird. - - -- type: ``boolean`` -- default: ``False`` - - - -mailserver.enablePop3 ---------------------- - -Whether to enable POP3 with STARTTLS on port on port 110. - - -- type: ``boolean`` -- default: ``False`` - - - -mailserver.enablePop3Ssl ------------------------- - -Whether to enable POP3 with TLS in wrapper-mode on port 995. - - -- type: ``boolean`` -- default: ``False`` - - - -mailserver.enableSubmission ---------------------------- - -Whether to enable SMTP with STARTTLS on port 587. - - -- type: ``boolean`` -- default: ``True`` - - - -mailserver.enableSubmissionSsl ------------------------------- - -Whether to enable SMTP with TLS in wrapper-mode on port 465. - - -- type: ``boolean`` -- default: ``True`` - - - -mailserver.extraVirtualAliases ------------------------------- - -Virtual Aliases. A virtual alias `"info@example.com" = "user1@example.com"` means that -all mail to `info@example.com` is forwarded to `user1@example.com`. Note -that it is expected that `postmaster@example.com` and `abuse@example.com` is -forwarded to some valid email address. (Alternatively you can create login -accounts for `postmaster` and (or) `abuse`). Furthermore, it also allows -the user `user1@example.com` to send emails as `info@example.com`. -It's also possible to create an alias for multiple accounts. In this -example all mails for `multi@example.com` will be forwarded to both -`user1@example.com` and `user2@example.com`. - - -- type: ``attribute set of ((Login Account) or non-empty (list of (Login Account)))`` -- default: ``{}`` -- example: ``{'abuse@example.com': 'user1@example.com', 'info@example.com': 'user1@example.com', 'multi@example.com': ['user1@example.com', 'user2@example.com'], 'postmaster@example.com': 'user1@example.com'}`` - - -mailserver.forwards -------------------- - -To forward mails to an external address. For instance, -the value {`"user@example.com" = "user@elsewhere.com";}` -means that mails to `user@example.com` are forwarded to -`user@elsewhere.com`. The difference with the -`extraVirtualAliases` option is that `user@elsewhere.com` -can't send mail as `user@example.com`. Also, this option -allows to forward mails to external addresses. - - -- type: ``attribute set of ((list of string) or string)`` -- default: ``{}`` -- example: ``{'user@example.com': 'user@elsewhere.com'}`` - - -mailserver.fqdn ---------------- - -The fully qualified domain name of the mail server. - -- type: ``string`` - -- example: ``mx.example.com`` - - -mailserver.hierarchySeparator ------------------------------ - -The hierarchy separator for mailboxes used by dovecot for the namespace 'inbox'. -Dovecot defaults to "." but recommends "/". -This affects how mailboxes appear to mail clients and sieve scripts. -For instance when using "." then in a sieve script "example.com" would refer to the mailbox "com" in the parent mailbox "example". -This does not determine the way your mails are stored on disk. -See https://wiki.dovecot.org/Namespaces for details. - - -- type: ``string`` -- default: ``.`` - - - -mailserver.indexDir -------------------- - -Folder to store search indices. If null, indices are stored -along with email, which could not necessarily be desirable, -especially when the fullTextSearch option is enable since -indices it creates are voluminous and do not need to be backed -up. - -Be careful when changing this option value since all indices -would be recreated at the new location (and clients would need -to resynchronize). - -Note the some variables can be used in the file path. See -https://doc.dovecot.org/configuration_manual/mail_location/#variables -for details. - - -- type: ``null or string`` -- default: ``None`` -- example: ``/var/lib/dovecot/indices`` - - -mailserver.keyFile ------------------- - -Scheme 1) -Location of the key file - - -- type: ``path`` - -- example: ``/root/mail-server.key`` - - -mailserver.lmtpSaveToDetailMailbox ----------------------------------- - -If an email address is delimited by a "+", should it be filed into a -mailbox matching the string after the "+"? For example, -user1+test@example.com would be filed into the mailbox "test". - - -- type: ``one of "yes", "no"`` -- default: ``yes`` - - - -mailserver.localDnsResolver ---------------------------- - -Runs a local DNS resolver (kresd) as recommended when running rspamd. This prevents your log file from filling up with rspamd_monitored_dns_mon entries. - - -- type: ``boolean`` -- default: ``True`` - - - -mailserver.mailDirectory ------------------------- - -Where to store the mail. - - -- type: ``path`` -- default: ``/var/vmail`` - - - -mailserver.mailboxes --------------------- - -The mailboxes for dovecot. -Depending on the mail client used it might be necessary to change some mailbox's name. - - -- type: ``unspecified value`` -- default: ``{'Drafts': {'auto': 'subscribe', 'specialUse': 'Drafts'}, 'Junk': {'auto': 'subscribe', 'specialUse': 'Junk'}, 'Sent': {'auto': 'subscribe', 'specialUse': 'Sent'}, 'Trash': {'auto': 'no', 'specialUse': 'Trash'}}`` - - - -mailserver.maxConnectionsPerUser --------------------------------- - -Maximum number of IMAP/POP3 connections allowed for a user from each IP address. -E.g. a value of 50 allows for 50 IMAP and 50 POP3 connections at the same -time for a single user. - - -- type: ``signed integer`` -- default: ``100`` - - - -mailserver.messageSizeLimit ---------------------------- - -Message size limit enforced by Postfix. - -- type: ``signed integer`` -- default: ``20971520`` -- example: ``52428800`` - - -mailserver.openFirewall ------------------------ - -Automatically open ports in the firewall. - -- type: ``boolean`` -- default: ``True`` - - - -mailserver.policydSPFExtraConfig --------------------------------- - -Extra configuration options for policyd-spf. This can be use to among -other things skip spf checking for some IP addresses. - - -- type: ``strings concatenated with "\n"`` -- default: ``""`` -- example: -.. code:: - - skip_addresses = 127.0.0.0/8,::ffff:127.0.0.0/104,::1 - - - - -mailserver.rebootAfterKernelUpgrade.enable ------------------------------------------- - -Whether to enable automatic reboot after kernel upgrades. -This is to be used in conjunction with system.autoUpgrade.enable = true" - - -- type: ``boolean`` -- default: ``False`` -- example: ``True`` - - -mailserver.rebootAfterKernelUpgrade.method ------------------------------------------- - -Whether to issue a full "reboot" or just a "systemctl kexec"-only reboot. -It is recommended to use the default value because the quicker kexec reboot has a number of problems. -Also if your server is running in a virtual machine the regular reboot will already be very quick. - - -- type: ``one of "reboot", "systemctl kexec"`` -- default: ``reboot`` - - - -mailserver.recipientDelimiter ------------------------------ - -Configure the recipient delimiter. - - -- type: ``string`` -- default: ``+`` - - - -mailserver.rejectRecipients ---------------------------- - -Reject emails addressed to these local addresses from unauthorized senders. -Use if a spammer has found email addresses in a catchall domain but you do -not want to disable the catchall. - - -- type: ``list of string`` -- default: ``[]`` -- example: ``['sales@example.com', 'info@example.com']`` - - -mailserver.rejectSender ------------------------ - -Reject emails from these addresses from unauthorized senders. -Use if a spammer is using the same domain or the same sender over and over. - - -- type: ``list of string`` -- default: ``[]`` -- example: ``['@example.com', 'spammer@example.net']`` - - -mailserver.rewriteMessageId ---------------------------- - -Rewrites the Message-ID's hostname-part of outgoing emails to the FQDN. -Please be aware that this may cause problems with some mail clients -relying on the original Message-ID. - - -- type: ``boolean`` -- default: ``False`` - - - -mailserver.sendingFqdn ----------------------- - -The fully qualified domain name of the mail server used to -identify with remote servers. - -If this server's IP serves purposes other than a mail server, -it may be desirable for the server to have a name other than -that to which the user will connect. For example, the user -might connect to mx.example.com, but the server's IP has -reverse DNS that resolves to myserver.example.com; in this -scenario, some mail servers may reject or penalize the -message. - -This setting allows the server to identify as -myserver.example.com when forwarding mail, independently of -`fqdn` (which, for SSL reasons, should generally be the name -to which the user connects). - -Set this to the name to which the sending IP's reverse DNS -resolves. - - -- type: ``string`` -- default: ``config.mailserver.fqdn`` -- example: ``myserver.example.com`` - - -mailserver.sieveDirectory -------------------------- - -Where to store the sieve scripts. - - -- type: ``path`` -- default: ``/var/sieve`` - - - -mailserver.useFsLayout ----------------------- - -Sets whether dovecot should organize mail in subdirectories: - -- /var/vmail/example.com/user/.folder.subfolder/ (default layout) -- /var/vmail/example.com/user/folder/subfolder/ (FS layout) - -See https://wiki2.dovecot.org/MailboxFormat/Maildir for details. - - -- type: ``boolean`` -- default: ``False`` - - - -mailserver.virusScanning ------------------------- - -Whether to activate virus scanning. Note that virus scanning is _very_ -expensive memory wise. - - -- type: ``boolean`` -- default: ``False`` - - - -mailserver.vmailGroupName -------------------------- - -The user name and group name of the user that owns the directory where all -the mail is stored. - - -- type: ``string`` -- default: ``virtualMail`` - - - -mailserver.vmailUID -------------------- - -The unix UID of the virtual mail user. Be mindful that if this is -changed, you will need to manually adjust the permissions of -mailDirectory. - - -- type: ``signed integer`` -- default: ``5000`` - - - -mailserver.vmailUserName ------------------------- - -The user name and group name of the user that owns the directory where all -the mail is stored. - - -- type: ``string`` -- default: ``virtualMail`` - - -mailserver.loginAccount -~~~~~~~~~~~~~~~~~~~~~~~ - - -mailserver.loginAccounts ------------------------- - -The login account of the domain. Every account is mapped to a unix user, -e.g. `user1@example.com`. To generate the passwords use `mkpasswd` as -follows - -``` -nix-shell -p mkpasswd --run 'mkpasswd -sm bcrypt' -``` - - -- type: ``attribute set of (submodule)`` -- default: ``{}`` -- example: ``{'user1': {'hashedPassword': '$6$evQJs5CFQyPAW09S$Cn99Y8.QjZ2IBnSu4qf1vBxDRWkaIZWOtmu1Ddsm3.H3CFpeVc0JU4llIq8HQXgeatvYhh5O33eWG3TSpjzu6/'}, 'user2': {'hashedPassword': '$6$oE0ZNv2n7Vk9gOf$9xcZWCCLGdMflIfuA0vR1Q1Xblw6RZqPrP94mEit2/81/7AKj2bqUai5yPyWE.QYPyv6wLMHZvjw3Rlg7yTCD/'}}`` - - -mailserver.loginAccounts..aliases ---------------------------------------- - -A list of aliases of this login account. -Note: Use list entries like "@example.com" to create a catchAll -that allows sending from all email addresses in these domain. - - -- type: ``list of string`` -- default: ``[]`` -- example: ``['abuse@example.com', 'postmaster@example.com']`` - - -mailserver.loginAccounts..catchAll ----------------------------------------- - -For which domains should this account act as a catch all? -Note: Does not allow sending from all addresses of these domains. - - -- type: ``list of value "example.com" (singular enum)`` -- default: ``[]`` -- example: ``['example.com', 'example2.com']`` - - -mailserver.loginAccounts..hashedPassword ----------------------------------------------- - -The user's hashed password. Use `mkpasswd` as follows - -``` -nix-shell -p mkpasswd --run 'mkpasswd -sm bcrypt' -``` - -Warning: this is stored in plaintext in the Nix store! -Use `hashedPasswordFile` instead. - - -- type: ``null or string`` -- default: ``None`` -- example: ``$6$evQJs5CFQyPAW09S$Cn99Y8.QjZ2IBnSu4qf1vBxDRWkaIZWOtmu1Ddsm3.H3CFpeVc0JU4llIq8HQXgeatvYhh5O33eWG3TSpjzu6/`` - - -mailserver.loginAccounts..hashedPasswordFile --------------------------------------------------- - -A file containing the user's hashed password. Use `mkpasswd` as follows - -``` -nix-shell -p mkpasswd --run 'mkpasswd -sm bcrypt' -``` - - -- type: ``null or path`` -- default: ``None`` -- example: ``/run/keys/user1-passwordhash`` - - -mailserver.loginAccounts..name ------------------------------------- - -Username - -- type: ``string`` - -- example: ``user1@example.com`` - - -mailserver.loginAccounts..quota -------------------------------------- - -Per user quota rules. Accepted sizes are `xx k/M/G/T` with the -obvious meaning. Leave blank for the standard quota `100G`. - - -- type: ``null or string`` -- default: ``None`` -- example: ``2G`` - - -mailserver.loginAccounts..sendOnly ----------------------------------------- - -Specifies if the account should be a send-only account. -Emails sent to send-only accounts will be rejected from -unauthorized senders with the sendOnlyRejectMessage -stating the reason. - - -- type: ``boolean`` -- default: ``False`` - - - -mailserver.loginAccounts..sendOnlyRejectMessage ------------------------------------------------------ - -The message that will be returned to the sender when an email is -sent to a send-only account. Only used if the account is marked -as send-only. - - -- type: ``string`` -- default: ``This account cannot receive emails.`` - - - -mailserver.loginAccounts..sieveScript -------------------------------------------- - -Per-user sieve script. - - -- type: ``null or strings concatenated with "\n"`` -- default: ``None`` -- example: -.. code:: - - require ["fileinto", "mailbox"]; - - if address :is "from" "gitlab@mg.gitlab.com" { - fileinto :create "GitLab"; - stop; - } - - # This must be the last rule, it will check if list-id is set, and - # file the message into the Lists folder for further investigation - elsif header :matches "list-id" "" { - fileinto :create "Lists"; - stop; - } - - - -mailserver.certificate -~~~~~~~~~~~~~~~~~~~~~~ - - -mailserver.certificateDirectory -------------------------------- - -Scheme 2) -This is the folder where the certificate will be created. The name is -hardcoded to "cert-DOMAIN.pem" and "key-DOMAIN.pem" and the -certificate is valid for 10 years. - - -- type: ``path`` -- default: ``/var/certs`` - - - -mailserver.certificateDomains ------------------------------ - -Secondary domains and subdomains for which it is necessary to generate a certificate. - -- type: ``list of string`` -- default: ``[]`` -- example: ``['imap.example.com', 'pop3.example.com']`` - - -mailserver.certificateFile --------------------------- - -Scheme 1) -Location of the certificate - - -- type: ``path`` - -- example: ``/root/mail-server.crt`` - - -mailserver.certificateScheme ----------------------------- - -Certificate Files. There are three options for these. - -1) You specify locations and manually copy certificates there. -2) You let the server create new (self signed) certificates on the fly. -3) You let the server create a certificate via `Let's Encrypt`. Note that - this implies that a stripped down webserver has to be started. This also - implies that the FQDN must be set as an `A` record to point to the IP of - the server. In particular port 80 on the server will be opened. For details - on how to set up the domain records, see the guide in the readme. - - -- type: ``one of 1, 2, 3`` -- default: ``2`` - - -mailserver.dkim -~~~~~~~~~~~~~~~ - - -mailserver.dkimBodyCanonicalization ------------------------------------ - -DKIM canonicalization algorithm for message bodies. - -See https://datatracker.ietf.org/doc/html/rfc6376/#section-3.4 for details. - - -- type: ``one of "relaxed", "simple"`` -- default: ``relaxed`` - - - -mailserver.dkimHeaderCanonicalization -------------------------------------- - -DKIM canonicalization algorithm for message headers. - -See https://datatracker.ietf.org/doc/html/rfc6376/#section-3.4 for details. - - -- type: ``one of "relaxed", "simple"`` -- default: ``relaxed`` - - - -mailserver.dkimKeyBits ----------------------- - -How many bits in generated DKIM keys. RFC6376 advises minimum 1024-bit keys. - -If you have already deployed a key with a different number of bits than specified -here, then you should use a different selector (dkimSelector). In order to get -this package to generate a key with the new number of bits, you will either have to -change the selector or delete the old key file. - - -- type: ``signed integer`` -- default: ``1024`` - - - -mailserver.dkimKeyDirectory ---------------------------- - - - - -- type: ``path`` -- default: ``/var/dkim`` - - - -mailserver.dkimSelector ------------------------ - - - - -- type: ``string`` -- default: ``mail`` - - - -mailserver.dkimSigning ----------------------- - -Whether to activate dkim signing. - - -- type: ``boolean`` -- default: ``True`` - - -mailserver.dmarcReporting -~~~~~~~~~~~~~~~~~~~~~~~~~ - - -mailserver.dmarcReporting.domain --------------------------------- - -The domain from which outgoing DMARC reports are served. - - -- type: ``value "example.com" (singular enum)`` - -- example: ``example.com`` - - -mailserver.dmarcReporting.email -------------------------------- - -The email address used for outgoing DMARC reports. Read-only. - - -- type: ``string`` -- default: ``"${localpart}@${domain}"`` - - - -mailserver.dmarcReporting.enable --------------------------------- - -Whether to send out aggregated, daily DMARC reports in response to incoming -mail, when the sender domain defines a DMARC policy including the RUA tag. - -This is helpful for the mail ecosystem, because it allows third parties to -get notified about SPF/DKIM violations originating from their sender domains. - -See https://rspamd.com/doc/modules/dmarc.html#reporting - - -- type: ``boolean`` -- default: ``False`` - - - -mailserver.dmarcReporting.fromName ----------------------------------- - -The sender name for DMARC reports. Defaults to the organization name. - - -- type: ``string`` -- default: ``organizationName`` - - - -mailserver.dmarcReporting.localpart ------------------------------------ - -The local part of the email address used for outgoing DMARC reports. - - -- type: ``string`` -- default: ``dmarc-noreply`` -- example: ``dmarc-report`` - - -mailserver.dmarcReporting.organizationName ------------------------------------------- - -The name of your organization used in the org_name attribute in -DMARC reports. - - -- type: ``string`` - -- example: ``ACME Corp.`` - -mailserver.fullTextSearch -~~~~~~~~~~~~~~~~~~~~~~~~~ - - -mailserver.fullTextSearch.autoIndex ------------------------------------ - -Enable automatic indexing of messages as they are received or modified. - -- type: ``boolean`` -- default: ``True`` - - - -mailserver.fullTextSearch.autoIndexExclude ------------------------------------------- - -Mailboxes to exclude from automatic indexing. - - -- type: ``list of string`` -- default: ``[]`` -- example: ``['\\Trash', 'SomeFolder', 'Other/*']`` - - -mailserver.fullTextSearch.enable --------------------------------- - -Whether to enable Full text search indexing with xapian. This has significant performance and disk space cost.. - -- type: ``boolean`` -- default: ``False`` -- example: ``True`` - - -mailserver.fullTextSearch.enforced ----------------------------------- - -Fail searches when no index is available. If set to -body, then only body searches (as opposed to -header) are affected. If set to no, searches may -fall back to a very slow brute force search. - - -- type: ``one of "yes", "no", "body"`` -- default: ``no`` - - - -mailserver.fullTextSearch.indexAttachments ------------------------------------------- - -Also index text-only attachements. Binary attachements are never indexed. - -- type: ``boolean`` -- default: ``False`` - - - -mailserver.fullTextSearch.maintenance.enable --------------------------------------------- - -Regularly optmize indices, as recommended by upstream. - -- type: ``boolean`` -- default: ``True`` - - - -mailserver.fullTextSearch.maintenance.onCalendar ------------------------------------------------- - -When to run the maintenance job. See systemd.time(7) for more information about the format. - -- type: ``string`` -- default: ``daily`` - - - -mailserver.fullTextSearch.maintenance.randomizedDelaySec --------------------------------------------------------- - -Run the maintenance job not exactly at the time specified with onCalendar, but plus or minus this many seconds. - -- type: ``signed integer`` -- default: ``1000`` - - - -mailserver.fullTextSearch.maxSize ---------------------------------- - -Size of the largest n-gram to index. - -- type: ``signed integer`` -- default: ``20`` - - - -mailserver.fullTextSearch.memoryLimit -------------------------------------- - -Memory limit for the indexer process, in MiB. If null, leaves the default (which is rather low), and if 0, no limit. - -- type: ``null or signed integer`` -- default: ``None`` -- example: ``2000`` - - -mailserver.fullTextSearch.minSize ---------------------------------- - -Size of the smallest n-gram to index. - -- type: ``signed integer`` -- default: ``2`` - - -mailserver.redis -~~~~~~~~~~~~~~~~ - - -mailserver.redis.address ------------------------- - -Address that rspamd should use to contact redis. - - -- type: ``string`` -- default: computed from - - - -mailserver.redis.password -------------------------- - -Password that rspamd should use to contact redis, or null if not required. - - -- type: ``null or string`` -- default: ``config.services.redis.servers.rspamd.requirePass`` - - - -mailserver.redis.port ---------------------- - -Port that rspamd should use to contact redis. - - -- type: ``16 bit unsigned integer; between 0 and 65535 (both inclusive)`` -- default: ``config.services.redis.servers.rspamd.port`` - - -mailserver.monitoring -~~~~~~~~~~~~~~~~~~~~~ - - -mailserver.monitoring.alertAddress ----------------------------------- - -The email address to send alerts to. - - -- type: ``string`` - - - - -mailserver.monitoring.config ----------------------------- - -The configuration used for monitoring via monit. -Use a mail address that you actively check and set it via 'set alert ...'. - - -- type: ``string`` -- default: see source - - - -mailserver.monitoring.enable ----------------------------- - -Whether to enable monitoring via monit. - -- type: ``boolean`` -- default: ``False`` -- example: ``True`` - -mailserver.backup -~~~~~~~~~~~~~~~~~ - - -mailserver.backup.cmdPostexec ------------------------------ - -The command to be executed after each backup operation. This is wrapped in a shell script to be called by rsnapshot. - -- type: ``null or string`` -- default: ``None`` - - - -mailserver.backup.cmdPreexec ----------------------------- - -The command to be executed before each backup operation. This is wrapped in a shell script to be called by rsnapshot. - - -- type: ``null or string`` -- default: ``None`` - - - -mailserver.backup.cronIntervals -------------------------------- - -Periodicity at which intervals should be run by cron. -Note that the intervals also have to exist in configuration -as retain options. - - -- type: ``attribute set of string`` -- default: ``{'daily': '30 3 * * *', 'hourly': ' 0 * * * *', 'weekly': ' 0 5 * * 0'}`` - - - -mailserver.backup.enable ------------------------- - -Whether to enable backup via rsnapshot. - -- type: ``boolean`` -- default: ``False`` -- example: ``True`` - - -mailserver.backup.retain.daily ------------------------------- - -How many daily snapshots are retained. - -- type: ``signed integer`` -- default: ``7`` - - - -mailserver.backup.retain.hourly -------------------------------- - -How many hourly snapshots are retained. - -- type: ``signed integer`` -- default: ``24`` - - - -mailserver.backup.retain.weekly -------------------------------- - -How many weekly snapshots are retained. - -- type: ``signed integer`` -- default: ``54`` - - - -mailserver.backup.snapshotRoot ------------------------------- - -The directory where rsnapshot stores the backup. - - -- type: ``path`` -- default: ``/var/rsnapshot`` - - -mailserver.borg -~~~~~~~~~~~~~~~ - - -mailserver.borgbackup.cmdPostexec ---------------------------------- - -The command to be executed after each backup operation. -This is called after borg create completed successfully and in the same script that runs -cmdPreexec, borg init and create. - - -- type: ``null or string`` -- default: ``None`` - - - -mailserver.borgbackup.cmdPreexec --------------------------------- - -The command to be executed before each backup operation. -This is called prior to borg init in the same script that runs borg init and create and cmdPostexec. -Example: - export BORG_RSH="ssh -i /path/to/private/key" - - -- type: ``null or string`` -- default: ``None`` - - - -mailserver.borgbackup.compression.auto --------------------------------------- - -Leaves it to borg to determine whether an individual file should be compressed. - -- type: ``boolean`` -- default: ``False`` - - - -mailserver.borgbackup.compression.level ---------------------------------------- - -Denotes the level of compression used by borg. -Most methods accept levels from 0 to 9 but zstd which accepts values from 1 to 22. -If null the decision is left up to borg. - - -- type: ``null or signed integer`` -- default: ``None`` - - - -mailserver.borgbackup.compression.method ----------------------------------------- - -Leaving this unset allows borg to choose. The default for borg 1.1.4 is lz4. - -- type: ``null or one of "none", "lz4", "zstd", "zlib", "lzma"`` -- default: ``None`` - - - -mailserver.borgbackup.enable ----------------------------- - -Whether to enable backup via borgbackup. - -- type: ``boolean`` -- default: ``False`` -- example: ``True`` - - -mailserver.borgbackup.encryption.method ---------------------------------------- - -The backup can be encrypted by choosing any other value than 'none'. -When using encryption the password / passphrase must be provided in passphraseFile. - - -- type: ``one of "none", "authenticated", "authenticated-blake2", "repokey", "keyfile", "repokey-blake2", "keyfile-blake2"`` -- default: ``none`` - - - -mailserver.borgbackup.encryption.passphraseFile ------------------------------------------------ - -Path to a file containing the encryption password or passphrase. - -- type: ``null or path`` -- default: ``None`` - - - -mailserver.borgbackup.extraArgumentsForCreate ---------------------------------------------- - -Additional arguments to add to the borg create command line e.g. '--stats'. - -- type: ``list of string`` -- default: ``[]`` - - - -mailserver.borgbackup.extraArgumentsForInit -------------------------------------------- - -Additional arguments to add to the borg init command line. - -- type: ``list of string`` -- default: ``['--critical']`` - - - -mailserver.borgbackup.group ---------------------------- - -The group borg and its launch script is run as. - -- type: ``string`` -- default: ``virtualMail`` - - - -mailserver.borgbackup.locations -------------------------------- - -The locations that are to be backed up by borg. - -- type: ``list of path`` -- default: ``['/var/vmail']`` - - - -mailserver.borgbackup.name --------------------------- - -The name of the individual backups as used by borg. -Certain placeholders will be replaced by borg. - - -- type: ``string`` -- default: ``{hostname}-{user}-{now}`` - - - -mailserver.borgbackup.repoLocation ----------------------------------- - -The location where borg saves the backups. -This can be a local path or a remote location such as user@host:/path/to/repo. -It is exported and thus available as an environment variable to cmdPreexec and cmdPostexec. - - -- type: ``string`` -- default: ``/var/borgbackup`` - - - -mailserver.borgbackup.startAt ------------------------------ - -When or how often the backup should run. Must be in the format described in systemd.time 7. - -- type: ``string`` -- default: ``hourly`` - - - -mailserver.borgbackup.user --------------------------- - -The user borg and its launch script is run as. - -- type: ``string`` -- default: ``virtualMail`` - - diff --git a/docs/requirements.txt b/docs/requirements.txt index 1b9a4f8..2211dd5 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,2 +1,4 @@ -sphinx==4.0.2 -sphinx_rtd_theme==0.5.2 +sphinx ~= 5.3 +sphinx_rtd_theme ~= 1.1 +myst-parser ~= 0.18 +linkify-it-py ~= 2.0 diff --git a/flake.lock b/flake.lock index 0f7f71a..4b4474d 100644 --- a/flake.lock +++ b/flake.lock @@ -16,6 +16,22 @@ "type": "gitlab" } }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1668681692, + "narHash": "sha256-Ht91NGdewz8IQLtWZ9LCeNXMSXHUss+9COoqu6JLmXU=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "009399224d5e398d03b22badca40a37ac85412a1", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, "nixpkgs": { "locked": { "lastModified": 1669542132, @@ -49,6 +65,7 @@ "root": { "inputs": { "blobs": "blobs", + "flake-compat": "flake-compat", "nixpkgs": "nixpkgs", "nixpkgs-22_11": "nixpkgs-22_11", "utils": "utils" diff --git a/flake.nix b/flake.nix index 4b5c8e6..9a46ea3 100644 --- a/flake.nix +++ b/flake.nix @@ -2,6 +2,10 @@ description = "A complete and Simple Nixos Mailserver"; inputs = { + flake-compat = { + url = "github:edolstra/flake-compat"; + flake = false; + }; utils.url = "github:numtide/flake-utils"; nixpkgs.url = "flake:nixpkgs/nixos-unstable"; nixpkgs-22_11.url = "flake:nixpkgs/nixos-22.11"; @@ -11,7 +15,8 @@ }; }; - outputs = { self, utils, blobs, nixpkgs, nixpkgs-22_11 }: let + outputs = { self, utils, blobs, nixpkgs, nixpkgs-22_11, ... }: let + lib = nixpkgs.lib; system = "x86_64-linux"; pkgs = nixpkgs.legacyPackages.${system}; releases = [ @@ -43,22 +48,18 @@ # external-21_05 = ; # ... # } - allTests = pkgs.lib.listToAttrs ( - pkgs.lib.flatten (map (t: map (r: genTest t r) releases) testNames)); + allTests = lib.listToAttrs ( + lib.flatten (map (t: map (r: genTest t r) releases) testNames)); mailserverModule = import ./.; - # Generate a rst file describing options of the NixOS mailserver module - generateRstOptions = let - eval = import (pkgs.path + "/nixos/lib/eval-config.nix") { - inherit system; + # Generate a MarkDown file describing the options of the NixOS mailserver module + optionsDoc = let + eval = lib.evalModules { modules = [ mailserverModule { - # Because the blockbook package is currently broken (we - # don't care about this package but it is part of the - # NixOS module evaluation) - nixpkgs.config.allowBroken = true; + _module.check = false; mailserver = { fqdn = "mx.example.com"; domains = [ @@ -71,27 +72,26 @@ }; } ]; - }; - options = pkgs.nixosOptionsDoc { - options = eval.options; - }; - in pkgs.runCommand "options.rst" { buildInputs = [pkgs.python3]; } '' - echo Generating options.rst from ${options.optionsJSON}/share/doc/nixos/options.json - python ${./scripts/generate-rst-options.py} ${options.optionsJSON}/share/doc/nixos/options.json > $out + options = builtins.toFile "options.json" (builtins.toJSON + (lib.filter (opt: opt.visible && !opt.internal && lib.head opt.loc == "mailserver") + (lib.optionAttrSetToDocList eval.options))); + in pkgs.runCommand "options.md" { buildInputs = [pkgs.python3Minimal]; } '' + echo "Generating options.md from ${options}" + python ${./scripts/generate-options.py} ${options} > $out ''; # This is a script helping users to generate this file in the docs directory - generateRstOptionsScript = pkgs.writeScriptBin "generate-rst-options" '' - cp -v ${generateRstOptions} ./docs/options.rst + generateOptions = pkgs.writeShellScriptBin "generate-options" '' + install -vm644 ${optionsDoc} ./docs/options.md ''; - # This is to ensure we don't forget to update the options.rst file - testRstOptions = pkgs.runCommand "test-rst-options" {} '' - if ! diff -q ${./docs/options.rst} ${generateRstOptions} + # This is to ensure we don't forget to update the options.md file + testOptions = pkgs.runCommand "test-options" {} '' + if ! diff -q ${./docs/options.md} ${optionsDoc} then - echo "The file ./docs/options.rst is not up-to-date and needs to be regenerated!" - echo " hint: run 'nix-shell --run generate-rst-options' to generate this file" + echo "The file ./docs/options.md is not up-to-date and needs to be regenerated!" + echo " hint: run 'nix-shell --run generate-options' to generate this file" exit 1 fi echo "test: ok" > $out @@ -99,43 +99,43 @@ documentation = pkgs.stdenv.mkDerivation { name = "documentation"; - src = pkgs.lib.sourceByRegex ./docs ["logo.png" "conf.py" "Makefile" ".*rst$"]; + src = lib.sourceByRegex ./docs ["logo\\.png" "conf\\.py" "Makefile" ".*\\.rst"]; buildInputs = [( - pkgs.python3.withPackages(p: [ - p.sphinx - p.sphinx_rtd_theme + pkgs.python3.withPackages (p: with p; [ + sphinx + sphinx_rtd_theme + myst-parser ]) )]; buildPhase = '' - cp ${generateRstOptions} options.rst - mkdir -p _static + cp ${optionsDoc} options.md # Workaround for https://github.com/sphinx-doc/sphinx/issues/3451 - export SOURCE_DATE_EPOCH=$(${pkgs.coreutils}/bin/date +%s) + unset SOURCE_DATE_EPOCH make html ''; installPhase = '' - cp -r _build/html $out + cp -Tr _build/html $out ''; }; - in rec { - nixosModules.mailserver = mailserverModule ; - nixosModule = self.nixosModules.mailserver; + in { + nixosModules = rec { + mailserver = mailserverModule; + default = mailserver; + }; + nixosModule = self.nixosModules.default; # compatibility hydraJobs.${system} = allTests // { - test-rst-options = testRstOptions; + test-options = testOptions; inherit documentation; }; checks.${system} = allTests; - devShell.${system} = pkgs.mkShell { - buildInputs = with pkgs; [ - generateRstOptionsScript - (python3.withPackages (p: with p; [ - sphinx - sphinx_rtd_theme - ])) - jq + devShells.${system}.default = pkgs.mkShell { + inputsFrom = [ documentation ]; + packages = with pkgs; [ + generateOptions clamav ]; }; + devShell.${system} = self.devShells.${system}.default; # compatibility }; } diff --git a/scripts/generate-options.py b/scripts/generate-options.py new file mode 100644 index 0000000..a4973b1 --- /dev/null +++ b/scripts/generate-options.py @@ -0,0 +1,81 @@ +import json +import sys + +header = """ +# Mailserver options + +## `mailserver` + +""" + +template = """ +`````{{option}} {key} +{description} + +{type} +{default} +{example} +````` +""" + +f = open(sys.argv[1]) +options = json.load(f) + +groups = ["mailserver.loginAccounts", + "mailserver.certificate", + "mailserver.dkim", + "mailserver.dmarcReporting", + "mailserver.fullTextSearch", + "mailserver.redis", + "mailserver.monitoring", + "mailserver.backup", + "mailserver.borgbackup"] + +def render_option_value(opt, attr): + if attr in opt: + if isinstance(opt[attr], dict) and '_type' in opt[attr]: + if opt[attr]['_type'] == 'literalExpression': + if '\n' in opt[attr]['text']: + res = '\n```nix\n' + opt[attr]['text'].rstrip('\n') + '\n```' + else: + res = '```{}```'.format(opt[attr]['text']) + elif opt[attr]['_type'] == 'literalMD': + res = opt[attr]['text'] + else: + s = str(opt[attr]) + if s == "": + res = '`""`' + elif '\n' in s: + res = '\n```\n' + s.rstrip('\n') + '\n```' + else: + res = '```{}```'.format(s) + res = '- ' + attr + ': ' + res + else: + res = "" + return res + +def print_option(opt): + if isinstance(opt['description'], dict) and '_type' in opt['description']: # mdDoc + description = opt['description']['text'] + else: + description = opt['description'] + print(template.format( + key=opt['name'], + description=description or "", + type="- type: ```{}```".format(opt['type']), + default=render_option_value(opt, 'default'), + example=render_option_value(opt, 'example'))) + + +print(header) +for opt in options: + if any([opt['name'].startswith(c) for c in groups]): + continue + print_option(opt) + +for c in groups: + print('## `{}`'.format(c)) + print() + for opt in options: + if opt['name'].startswith(c): + print_option(opt) diff --git a/scripts/generate-rst-options.py b/scripts/generate-rst-options.py deleted file mode 100644 index 8c5ce9c..0000000 --- a/scripts/generate-rst-options.py +++ /dev/null @@ -1,87 +0,0 @@ -import json -import sys -import re -import textwrap - -header = """ -Mailserver Options -================== - -mailserver -~~~~~~~~~~ - -""" - -template = """ -{key} -{line} - -{description} - -{type} -{default} -{example} -""" - -f = open(sys.argv[1]) -options = json.load(f) - -options = {k: v for k, v in options.items() - if k.startswith("mailserver.")} - -groups = ["mailserver.loginAccount", - "mailserver.certificate", - "mailserver.dkim", - "mailserver.dmarcReporting", - "mailserver.fullTextSearch", - "mailserver.redis", - "mailserver.monitoring", - "mailserver.backup", - "mailserver.borg"] - -def render_option_value(opt, attr): - if attr in opt: - if isinstance(opt[attr], dict) and '_type' in opt[attr]: - if opt[attr]['_type'] == 'literalExpression': - if '\n' in opt[attr]['text']: - res = '\n.. code:: nix\n\n' + textwrap.indent(opt[attr]['text'], ' ') + '\n' - else: - res = '``{}``'.format(opt[attr]['text']) - elif opt[attr]['_type'] == 'literalDocBook': - res = opt[attr]['text'] - else: - s = str(opt[attr]) - if s == "": - res = '``""``' - elif '\n' in s: - res = '\n.. code::\n\n' + textwrap.indent(s, ' ') + '\n' - else: - res = '``{}``'.format(s) - res = '- ' + attr + ': ' + res - else: - res = "" - return res - -def print_option(name, value): - print(template.format( - key=name, - line="-"*len(name), - description=value['description'] or "", - type="- type: ``{}``".format(value['type']), - default=render_option_value(value, 'default'), - example=render_option_value(value, 'example'))) - - -print(header) -for k, v in options.items(): - if any([k.startswith(c) for c in groups]): - continue - print_option(k, v) - -for c in groups: - print(c) - print("~"*len(c)) - print() - for k, v in options.items(): - if k.startswith(c): - print_option(k, v) diff --git a/shell.nix b/shell.nix index d32886e..6234bb4 100644 --- a/shell.nix +++ b/shell.nix @@ -1 +1,10 @@ -(import (builtins.fetchGit "https://github.com/edolstra/flake-compat") { src = ./.; }).shellNix +(import + ( + let lock = builtins.fromJSON (builtins.readFile ./flake.lock); in + fetchTarball { + url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz"; + sha256 = lock.nodes.flake-compat.locked.narHash; + } + ) + { src = ./.; } +).shellNix