summaryrefslogtreecommitdiff
path: root/content/tech
diff options
context:
space:
mode:
authorschneefux <schneefux+commit@schneefux.xyz>2016-06-12 19:05:56 +0200
committerschneefux <schneefux+commit@schneefux.xyz>2016-06-12 19:05:56 +0200
commitb790ae34fa264b2d591162213b19a77050928d54 (patch)
tree6c2f06defbae4537a718fb18ee473a1a8b9f6e09 /content/tech
parent12249dc66ace726f8d8e87417769492f6e1f88d0 (diff)
downloadblog-b790ae34fa264b2d591162213b19a77050928d54.tar.gz
blog-b790ae34fa264b2d591162213b19a77050928d54.zip
post: nixos mailserver
Diffstat (limited to 'content/tech')
-rw-r--r--content/tech/nixos-mailserver.md296
1 files changed, 296 insertions, 0 deletions
diff --git a/content/tech/nixos-mailserver.md b/content/tech/nixos-mailserver.md
new file mode 100644
index 0000000..d52f0c5
--- /dev/null
+++ b/content/tech/nixos-mailserver.md
@@ -0,0 +1,296 @@
+---
+categories:
+- software
+date: 2016-06-11
+title: NixOS mail server
+---
+
+This is my working, but in progress [NixOS]({{< ref "nixos-intro.md" >}}) mail server configuration. These are the relevant configuration parts, they are *not* tested and **not guaranteed to be secure, deploy at your own risk**. The configuration is based on [this](https://thomas-leister.de/allgemein/sicherer-mailserver-dovecot-postfix-virtuellen-benutzern-mysql-ubuntu-server-xenial/) blog post (German).
+
+For an easier overview, I created a seperate `mail.nix` that is included in the main `configuration.nix`. The firewall needs to be open for ports 993 (imps), 25 (smtp) and 587 (smtps).
+
+```nix
+imports =
+ [
+ ./mail.nix
+ ];
+
+networking.firewall.allowedTCPPorts = [ 993 25 587 ];
+```
+
+The server is built with postfix. Postfix transports the mail via smtp(s). Dovecot is the interface between user and provides pop3(s) and/or imap(s). Opendkim signs outgoing mail so that it is less likely to be marked as spam by other providers.
+
+DNS records must be and a PTR record can be set up. This is not covered here.
+
+It is advisable to use SSL certificates. NixOS has a module that gets Let's Encrypt certificates:
+
+```nix
+security.acme.certs = {
+ "yourdomain.tld" = {
+ webroot = "/var/www/challenges";
+ extraDomains = { "mail.yourdomain.tld" = null; };
+ email = "mail@provider.net";
+ postRun = "systemctl reload nginx.service postfix.service dovecot2.service";
+ };
+};
+```
+
+A web server is needed for the certification process.
+
+```nix
+services.nginx = {
+ enable = true;
+ httpConfig = ''
+ include ${pkgs.nginx}/conf/mime.types;
+
+ server {
+ listen 80;
+ listen [::]:80;
+ server_name mail.yourdomain.tld;
+ location /.well-known/acme-challenge {
+ root /var/www/challenges/;
+ }
+ }
+ '';
+};
+```
+
+After retrieving certificates once: `systemctl start acme-yourdomain.tld`, they will be regenerated regularly and placed in `/var/lib/acme/yourdomain.tld/` by default. Now comes the main configuration. The user `vmail` is the owner of the mailing system.
+
+```nix
+users.users.vmail = {
+ home = "/var/vmail";
+ createHome = true;
+ group = "vmail";
+};
+users.groups = { vmail = {}; };
+```
+
+Dovecot requires an external configuration file. I put it in `/etc/nixos/mail/dovecot.conf`.
+
+```nix
+services.dovecot2 = {
+ enable = true;
+ configFile = "/etc/nixos/mail/dovecot.conf";
+ sslCACert = "/var/lib/acme/yourdomain.tld/fullchain.pem";
+ sslServerCert = "/var/lib/acme/yourdomain.tld/fullchain.pem";
+ sslServerKey = "/var/lib/acme/yourdomain.tld/key.pem";
+};
+```
+
+This is the dovecot config. It exposes imap, lmtp and auth ports. imap is for the user. lmtp and auth are for exchanging data between dovecot and postfix. Postfix will authenticate via dovecot. `passdb` and `userdb` set to `pam` and `passwd` will allow every local unix user to authenticate with their username and password. Each user has a `~/Maildir` with their mail, each mailbox contains the folders "Spam", "Trash", "Drafts" and "Sent".
+
+```perl
+default_internal_user = dovecot2
+
+protocols = imap lmtp
+
+ssl = required
+ssl_cert = </var/lib/acme/yourdomain.tld/fullchain.pem
+ssl_key = </var/lib/acme/yourdomain.tld/key.pem
+ssl_dh_parameters_length = 2048
+ssl_protocols = !SSLv2 !SSLv3
+ssl_cipher_list = EDH+CAMELLIA:EDH+aRSA:EECDH+aRSA+AESGCM:EECDH+aRSA+SHA256:EECDH:+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!IDEA:!ECDSA:kEDH:CAMELLIA128-SHA:AES128-SHA
+ssl_prefer_server_ciphers = yes
+
+service imap-login {
+ inet_listener imap {
+ port = 143
+ }
+}
+
+service lmtp {
+ inet_listener {
+ port = 8458
+ }
+}
+
+
+service auth {
+ inet_listener {
+ port = 2847
+ }
+}
+
+protocol imap {
+ mail_plugins = $mail_plugins
+ mail_max_userip_connections = 20
+ imap_idle_notify_interval = 29 mins
+}
+
+protocol lmtp {
+ postmaster_address = postmaster@yourdomain.tld
+ mail_plugins = $mail_plugins
+}
+
+disable_plaintext_auth = yes
+auth_mechanisms = plain login
+
+auth_username_format = %Ln
+passdb {
+ driver = pam
+ args = dovecot2
+}
+userdb {
+ driver = passwd
+ args = blocking=no
+}
+
+mail_uid = vmail
+mail_gid = vmail
+mail_privileged_group = vmail
+
+mail_home = /var/vmail/mailboxes/%d/%n
+mail_location = maildir:~/Maildir
+
+namespace inbox {
+ inbox = yes
+
+ mailbox Spam {
+ auto = subscribe
+ special_use = \Junk
+ }
+
+ mailbox Trash {
+ auto = subscribe
+ special_use = \Trash
+ }
+
+ mailbox Drafts {
+ auto = subscribe
+ special_use = \Drafts
+ }
+
+ mailbox Sent {
+ auto = subscribe
+ special_use = \Sent
+ }
+}
+```
+
+Now comes postfix. Postfix is configured to authenticate via dovecot. Postscreen and dnsblog filter some spam mails.
+
+```nix
+ services.postfix = {
+ enable = true;
+ user = "vmail";
+ group = "vmail";
+ domain = "mail.yourdomain.tld";
+ hostname = "mail.yourdomain.tld";
+ sslCACert = "/var/lib/acme/yourdomain.tld/fullchain.pem";
+ sslCert = "/var/lib/acme/yourdomain.tld/fullchain.pem";
+ sslKey = "/var/lib/acme/yourdomain.tld/key.pem";
+ recipientDelimiter = "+";
+ destination = [ "yourdomain.tld" "mail.yourdomain.tld" ];
+ virtual = ''
+onealias@yourdomain.tld youruser
+anotheralias@yourdomain.tld youruser
+ '';
+ extraMasterConf = ''
+smtp inet n - n - 1 postscreen
+ -o smtpd_sasl_auth_enable=no
+smtpd pass - - n - - smtpd
+ -o smtpd_sasl_auth_enable=no
+dnsblog unix - - n - 0 dnsblog
+tlsproxy unix - - n - 0 tlsproxy
+submission inet n - n - - smtpd
+ -o syslog_name=postfix/submission
+ -o smtpd_tls_security_level=encrypt
+ -o smtpd_sasl_auth_enable=yes
+ -o smtpd_sasl_type=dovecot
+ -o smtpd_sasl_path=inet:127.0.0.1:2847
+ -o smtpd_sasl_security_options=noanonymous
+ -o smtpd_relay_restrictions=reject_non_fqdn_recipient,reject_unknown_recipient_domain,permit_mynetworks,permit_sasl_authenticated,reject
+ -o smtpd_sender_restrictions=permit_mynetworks,reject_non_fqdn_sender,permit_sasl_authenticated,reject
+ -o smtpd_client_restrictions=permit_mynetworks,permit_sasl_authenticated,reject
+ -o smtpd_helo_required=no
+ -o smtpd_helo_restrictions=
+ -o milter_macro_daemon_name=ORIGINATING
+ -o cleanup_service_name=submission-header-cleanup
+submission-header-cleanup unix n - n - 0 cleanup
+ -o header_checks=pcre:/etc/nixos/mail/anonymize_headers.pcre
+'';
+ extraConfig = ''
+maximal_queue_lifetime = 1h
+bounce_queue_lifetime = 1h
+maximal_backoff_time = 15m
+minimal_backoff_time = 5m
+queue_run_delay = 5m
+
+tls_ssl_options = NO_COMPRESSION
+tls_high_cipherlist = EDH+CAMELLIA:EDH+aRSA:EECDH+aRSA+AESGCM:EECDH+aRSA+SHA256:EECDH:+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!IDEA:!ECDSA:kEDH:CAMELLIA128-SHA:AES128-SHA
+smtp_tls_security_level = dane
+smtp_dns_support_level = dnssec
+smtp_tls_session_cache_database = btree:''${data_directory}/smtp_scache
+smtp_tls_protocols = !SSLv2, !SSLv3
+smtp_tls_ciphers = high
+smtpd_tls_security_level = may
+smtpd_tls_protocols = !SSLv2, !SSLv3
+smtpd_tls_ciphers = high
+smtpd_tls_eecdh_grade = strong
+smtpd_tls_dh1024_param_file=/var/lib/acme/yourdomain.tld/dhparams.pem
+smtpd_tls_session_cache_database = btree:''${data_directory}/smtpd_scache
+
+smtpd_relay_restrictions =
+ reject_non_fqdn_recipient
+ reject_unknown_recipient_domain
+ permit_mynetworks
+ reject_unauth_destination
+smtpd_client_restrictions = permit_mynetworks
+ reject_unknown_client_hostname
+smtpd_helo_required = yes
+smtpd_helo_restrictions = permit_mynetworks
+ reject_invalid_helo_hostname
+ reject_non_fqdn_helo_hostname
+ reject_unknown_helo_hostname
+smtpd_data_restrictions = reject_unauth_pipelining
+
+
+mailbox_transport = lmtp:inet:127.0.0.1:8458
+
+milter_default_action = accept
+milter_protocol = 2
+smtpd_milters = unix:/run/opendkim/opendkim.sock
+non_smtpd_milters = unix:/run/opendkim/opendkim.sock
+
+# Postscreen
+postscreen_access_list = permit_mynetworks
+postscreen_blacklist_action = drop
+postscreen_greet_action = drop
+
+# DNS blocklists
+postscreen_dnsbl_threshold = 2
+postscreen_dnsbl_sites = dnsbl.sorbs.net*1, bl.spamcop.net*1, ix.dnsbl.manitu.net*2, zen.spamhaus.org*2
+postscreen_dnsbl_action = drop
+
+# turn off biff notifications for performance
+biff = no
+
+append_dot_mydomain = no
+ '';
+};
+```
+
+`/etc/nixos/mail/anonymize_headers.pcre` replaces sensitive header data.
+
+```
+/^\s*(Received: from)[^\n]*(.*)/ REPLACE $1 [127.0.0.1] (localhost [127.0.0.1])$2
+/^\s*User-Agent/ IGNORE
+/^\s*X-Enigmail/ IGNORE
+/^\s*X-Mailer/ IGNORE
+/^\s*X-Originating-IP/ IGNORE
+```
+
+Finally, the opendkim configuration. Generate a key once with `opendkim-genkey -r -d yourdomain.tld`. Add the public key as DNS record.
+
+```nix
+services.opendkim = {
+ enable = true;
+ domains = "yourdomain.tld,mail.yourdomain.tld";
+ keyFile = "/etc/nixos/mail/key.private";
+ selector = "key";
+ socket = "local:/run/opendkim/opendkim.sock";
+ user = "vmail";
+ group = "vmail";
+};
+```