mgoblinTool = ./websites/tools/mgoblin;
peertubeTool = ./websites/tools/peertube;
toolsTool = ./websites/tools/tools;
+ mailTool = ./websites/tools/mail;
mail = ./mail;
mailMilters = ./mail/milters.nix;
${conf.entries}
${if lib.attrsets.hasAttr "withEmail" conf && lib.lists.length conf.withEmail > 0 then ''
- mail IN A ${myconfig.env.servers.immaeEu.ips.main.ip4}
mx-1 IN A ${myconfig.env.servers.eldiron.ips.main.ip4}
- ${builtins.concatStringsSep "\n" (map (i: "mail IN AAAA ${i}") myconfig.env.servers.immaeEu.ips.main.ip6)}
+ mx-2 IN A ${myconfig.env.servers.immaeEu.ips.main.ip4}
${builtins.concatStringsSep "\n" (map (i: "mx-1 IN AAAA ${i}") myconfig.env.servers.eldiron.ips.main.ip6)}
+ ${builtins.concatStringsSep "\n" (map (i: "mx-2 IN AAAA ${i}") myconfig.env.servers.immaeEu.ips.main.ip6)}
${lib.concatStringsSep "\n\n" (map (e:
let
n = if e.domain == "" then "@" else "${e.domain} ";
in
''
; ------------------ mail: ${n} ---------------------------
- ${n} IN MX 10 mail.${conf.name}.
- ${n} IN MX 50 mx-1.${conf.name}.
+ ${n} IN MX 10 mx-1.${conf.name}.
+ ${n} IN MX 20 mx-2.${conf.name}.
; https://tools.ietf.org/html/rfc6186
_submission._tcp${suffix} SRV 0 1 587 smtp.immae.eu.
_pop3s._tcp${suffix} SRV 10 1 995 pop3.immae.eu.
_sieve._tcp${suffix} SRV 0 1 4190 imap.immae.eu.
+ ; MTA-STS
+ ; https://blog.delouw.ch/2018/12/16/using-mta-sts-to-enhance-email-transport-security-and-privacy/
+ ; https://support.google.com/a/answer/9261504
+ _mta-sts${suffix} IN TXT "v=STSv1;id=20190630054629Z"
+ _smtp._tls${suffix} IN TXT "v=TLSRPTv1;rua=mailto:postmaster+mta-sts@immae.eu"
+ mta-sts${suffix} IN A ${myconfig.env.servers.eldiron.ips.main.ip4}
+ ${builtins.concatStringsSep "\n" (map (i: "mta-sts${suffix} IN AAAA ${i}") myconfig.env.servers.eldiron.ips.main.ip6)}
+
; Mail sender authentications
${n} IN TXT "v=spf1 mx ~all"
_dmarc${suffix} IN TXT "v=DMARC1; p=none; adkim=r; aspf=r; fo=1; rua=mailto:postmaster+rua@immae.eu; ruf=mailto:postmaster+ruf@immae.eu;"
milter_macro_daemon_name = "ORIGINATING";
smtpd_milters = "unix:${config.myServices.mail.milters.sockets.opendkim}";
};
+ # FIXME: Mail adressed to localhost.immae.eu will still have mx-1 as
+ # prioritized MX, which provokes "mail for localhost.immae.eu loops
+ # back to myself" errors. This transport entry forces to push
+ # e-mails to its right destination.
+ transport = ''
+ localhost.immae.eu smtp:[immae.eu]:25
+ '';
destination = ["localhost"];
# This needs to reverse DNS
hostname = "eldiron.immae.eu";
tools.mediagoblin.enable = true;
tools.peertube.enable = true;
tools.tools.enable = true;
+ tools.email.enable = true;
};
};
}
--- /dev/null
+{ lib, pkgs, config, myconfig, ... }:
+let
+ roundcubemail = pkgs.callPackage ./roundcubemail.nix {
+ inherit (pkgs.webapps) roundcubemail roundcubemail-plugins roundcubemail-skins;
+ env = myconfig.env.tools.roundcubemail;
+ };
+ rainloop = pkgs.callPackage ./rainloop.nix {};
+ cfg = config.myServices.websites.tools.email;
+in
+{
+ options.myServices.websites.tools.email = {
+ enable = lib.mkEnableOption "enable email website";
+ };
+
+ imports = [
+ ./mta-sts.nix
+ ];
+
+ config = lib.mkIf cfg.enable {
+ secrets.keys = roundcubemail.keys;
+
+ services.websites.env.tools.modules =
+ [ "proxy_fcgi" ]
+ ++ rainloop.apache.modules
+ ++ roundcubemail.apache.modules;
+
+ services.websites.env.tools.vhostConfs.mail = {
+ certName = "mail";
+ addToCerts = true;
+ hosts = ["mail.immae.eu"];
+ root = "/run/current-system/webapps/_mail";
+ extraConfig = [
+ rainloop.apache.vhostConf
+ roundcubemail.apache.vhostConf
+ ''
+ <Directory /run/current-system/webapps/_mail>
+ Require all granted
+ Options -Indexes
+ </Directory>
+ ''
+ ];
+ };
+ systemd.services = {
+ phpfpm-rainloop = {
+ after = lib.mkAfter rainloop.phpFpm.serviceDeps;
+ wants = rainloop.phpFpm.serviceDeps;
+ };
+ phpfpm-roundcubemail = {
+ after = lib.mkAfter roundcubemail.phpFpm.serviceDeps;
+ wants = roundcubemail.phpFpm.serviceDeps;
+ };
+ };
+
+ services.phpfpm.pools.roundcubemail = {
+ listen = roundcubemail.phpFpm.socket;
+ extraConfig = roundcubemail.phpFpm.pool;
+ phpOptions = config.services.phpfpm.phpOptions + roundcubemail.phpFpm.phpConfig;
+ };
+ services.phpfpm.poolConfigs = {
+ rainloop = rainloop.phpFpm.pool;
+ };
+ system.activationScripts = {
+ roundcubemail = roundcubemail.activationScript;
+ rainloop = rainloop.activationScript;
+ };
+
+ myServices.websites.webappDirs = {
+ _mail = ./www;
+ "${roundcubemail.apache.webappName}" = roundcubemail.webRoot;
+ "${rainloop.apache.webappName}" = rainloop.webRoot;
+ };
+
+ };
+
+}
--- /dev/null
+{ lib, pkgs, config, myconfig, ... }:
+let
+ domains = (lib.remove null (lib.flatten (map
+ (zone: map
+ (e: if e.receive
+ then {
+ domain = "${e.domain}${lib.optionalString (e.domain != "") "."}${zone.name}";
+ mail = zone.name;
+ }
+ else null
+ )
+ (zone.withEmail or [])
+ )
+ myconfig.env.dns.masterZones
+ )));
+ # FIXME: increase the id number in modules/private/dns.nix when this
+ # file change (date -u +'%Y%m%d%H%M%S'Z)
+ file = domain: pkgs.writeText "mta-sts-${domain.domain}.txt" ''
+ version: STSv1
+ mode: testing
+ mx: mx-1.${domain.mail}
+ mx: mx-2.${domain.mail}
+ max_age: 604800
+ '';
+ root = pkgs.runCommand "mta-sts_root" {} ''
+ mkdir -p $out
+ ${builtins.concatStringsSep "\n" (map (d:
+ "cp ${file d} $out/${d.domain}.txt"
+ ) domains)}
+ '';
+in
+{
+ config.myServices.websites.webappDirs = {
+ _mta-sts = root;
+ };
+
+ config.services.websites.env.tools.vhostConfs.mta_sts = {
+ certName = "mail";
+ addToCerts = true;
+ hosts = ["mta-sts.mail.immae.eu"] ++ map (v: "mta-sts.${v.domain}") domains;
+ root = "/run/current-system/webapps/_mta-sts";
+ extraConfig = [
+ ''
+ RewriteEngine on
+ RewriteCond %{HTTP_HOST} ^mta-sts.(.*)$
+ RewriteRule ^/.well-known/mta-sts.txt$ %{DOCUMENT_ROOT}/%1.txt [L]
+ <Directory /run/current-system/webapps/_mta-sts>
+ Require all granted
+ Options -Indexes
+ </Directory>
+ ''
+ ];
+ };
+
+}
--- /dev/null
+<!doctype html>
+<html lang="fr">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <title>E-mail configuration</title>
+ <style type="text/css">
+ body {
+ padding-top: 1em;
+ padding-left: 5px;
+ padding-right: 5px;
+ text-align: left;
+ margin: auto;
+ font: 20px Helvetica, sans-serif;
+ color: #333;
+ height: 100%;
+ min-height: 100%;
+ }
+ article {
+ text-align: justify;
+ display: block;
+ max-width: 850px;
+ margin: 0 auto;
+ padding-top: 30px;
+ }
+ span.code {
+ font-family: monospace;
+ }
+ </style>
+ </head>
+ <body>
+ <p>
+ Email configuration. For automatic configuration in your smart e-mail
+ client, use <span class="code">login@mail.immae.eu</span>. If it
+ doesn’t work, the details are there:
+ <ul>
+ <li>IMAP: <span class="code">imap.immae.eu</span>
+ <ul>
+ <li>No unencrypted access</li>
+ <li>STARTTLS: 143 (recommended)</li>
+ <li>SSL: 993</li>
+ </ul>
+ </li>
+ <li>POP3: <span class="code">pop3.immae.eu</span>
+ <ul>
+ <li>No unencrypted access</li>
+ <li>STARTTLS: 110 (recommended)</li>
+ <li>SSL: 995</li>
+ </ul>
+ </li>
+ <li>SMTP: <span class="code">smtp.immae.eu</span>
+ <ul>
+ <li>No unencrypted access</li>
+ <li>STARTTLS: 587</li>
+ </ul>
+ </li>
+ <li>Sieve: <span class="code">imap.immae.eu</span>
+ <ul>
+ <li>No unencrypted access</li>
+ <li>STARTTLS: 4190</li>
+ </ul>
+ </li>
+ </ul>
+ </p>
+ <p>Webmails:
+ <ul>
+ <li><a href="/roundcube">Roundcube</a></li>
+ <li><a href="/rainloop">Rainloop</a> (experimental)</li>
+ </ul>
+ </p>
+ </body>
+</html>
+
inherit (pkgs.webapps) ttrss ttrss-plugins;
env = myconfig.env.tools.ttrss;
};
- roundcubemail = pkgs.callPackage ./roundcubemail.nix {
- inherit (pkgs.webapps) roundcubemail roundcubemail-plugins roundcubemail-skins;
- env = myconfig.env.tools.roundcubemail;
- };
- rainloop = pkgs.callPackage ./rainloop.nix {};
kanboard = pkgs.callPackage ./kanboard.nix {
env = myconfig.env.tools.kanboard;
};
secrets.keys =
kanboard.keys
++ ldap.keys
- ++ roundcubemail.keys
++ shaarli.keys
++ ttrss.keys
++ wallabag.keys
++ yourls.keys;
- services.websites.env.integration.modules =
- rainloop.apache.modules;
-
services.websites.env.tools.modules =
[ "proxy_fcgi" ]
++ adminer.apache.modules
++ ympd.apache.modules
++ ttrss.apache.modules
- ++ roundcubemail.apache.modules
++ wallabag.apache.modules
++ yourls.apache.modules
++ rompr.apache.modules
</FilesMatch>
</Directory>
''
- rainloop.apache.vhostConf
];
};
root = "/var/lib/ftp/tools.immae.eu";
extraConfig = [
''
+ RedirectMatch 301 ^/roundcube(.*)$ https://mail.immae.eu/roundcube$1
+
<Directory "/var/lib/ftp/tools.immae.eu">
DirectoryIndex index.php index.htm index.html
AllowOverride all
adminer.apache.vhostConf
ympd.apache.vhostConf
ttrss.apache.vhostConf
- roundcubemail.apache.vhostConf
wallabag.apache.vhostConf
yourls.apache.vhostConf
rompr.apache.vhostConf
RedirectMatch 301 ^/taskweb(.*)$ https://task.immae.eu/taskweb$1
+ RedirectMatch 301 ^/roundcube(.*)$ https://mail.immae.eu/roundcube$1
+
RedirectMatch 301 ^/(.*)$ https://tools.immae.eu/$1
''
];
after = lib.mkAfter ldap.phpFpm.serviceDeps;
wants = ldap.phpFpm.serviceDeps;
};
- phpfpm-rainloop = {
- after = lib.mkAfter rainloop.phpFpm.serviceDeps;
- wants = rainloop.phpFpm.serviceDeps;
- };
- phpfpm-roundcubemail = {
- after = lib.mkAfter roundcubemail.phpFpm.serviceDeps;
- wants = roundcubemail.phpFpm.serviceDeps;
- };
phpfpm-shaarli = {
after = lib.mkAfter shaarli.phpFpm.serviceDeps;
wants = shaarli.phpFpm.serviceDeps;
paths = [ "/var/secrets/mpd" ];
};
- services.phpfpm.pools.roundcubemail = {
- listen = roundcubemail.phpFpm.socket;
- extraConfig = roundcubemail.phpFpm.pool;
- phpOptions = config.services.phpfpm.phpOptions + roundcubemail.phpFpm.phpConfig;
- };
-
services.phpfpm.pools.devtools = {
listen = "/var/run/phpfpm/devtools.sock";
extraConfig = ''
shaarli = shaarli.phpFpm.pool;
dokuwiki = dokuwiki.phpFpm.pool;
ldap = ldap.phpFpm.pool;
- rainloop = rainloop.phpFpm.pool;
kanboard = kanboard.phpFpm.pool;
tools = ''
listen = /var/run/phpfpm/tools.sock
system.activationScripts = {
adminer = adminer.activationScript;
ttrss = ttrss.activationScript;
- roundcubemail = roundcubemail.activationScript;
wallabag = wallabag.activationScript;
yourls = yourls.activationScript;
rompr = rompr.activationScript;
shaarli = shaarli.activationScript;
dokuwiki = dokuwiki.activationScript;
- rainloop = rainloop.activationScript;
kanboard = kanboard.activationScript;
ldap = ldap.activationScript;
};
"${dokuwiki.apache.webappName}" = dokuwiki.webRoot;
"${ldap.apache.webappName}" = "${ldap.webRoot}/htdocs";
"${rompr.apache.webappName}" = rompr.webRoot;
- "${roundcubemail.apache.webappName}" = roundcubemail.webRoot;
"${shaarli.apache.webappName}" = shaarli.webRoot;
"${ttrss.apache.webappName}" = ttrss.webRoot;
"${wallabag.apache.webappName}" = wallabag.webRoot;
"${yourls.apache.webappName}" = yourls.webRoot;
- "${rainloop.apache.webappName}" = rainloop.webRoot;
"${kanboard.apache.webappName}" = kanboard.webRoot;
};