aboutsummaryrefslogtreecommitdiff
path: root/modules/private/websites/tools/mail
diff options
context:
space:
mode:
Diffstat (limited to 'modules/private/websites/tools/mail')
-rw-r--r--modules/private/websites/tools/mail/default.nix75
-rw-r--r--modules/private/websites/tools/mail/mta-sts.nix55
-rw-r--r--modules/private/websites/tools/mail/rainloop.nix59
-rw-r--r--modules/private/websites/tools/mail/roundcubemail.nix125
-rw-r--r--modules/private/websites/tools/mail/www/index.html73
5 files changed, 387 insertions, 0 deletions
diff --git a/modules/private/websites/tools/mail/default.nix b/modules/private/websites/tools/mail/default.nix
new file mode 100644
index 0000000..ea0a27f
--- /dev/null
+++ b/modules/private/websites/tools/mail/default.nix
@@ -0,0 +1,75 @@
1{ lib, pkgs, config, myconfig, ... }:
2let
3 roundcubemail = pkgs.callPackage ./roundcubemail.nix {
4 inherit (pkgs.webapps) roundcubemail roundcubemail-plugins roundcubemail-skins;
5 env = myconfig.env.tools.roundcubemail;
6 };
7 rainloop = pkgs.callPackage ./rainloop.nix {};
8 cfg = config.myServices.websites.tools.email;
9in
10{
11 options.myServices.websites.tools.email = {
12 enable = lib.mkEnableOption "enable email website";
13 };
14
15 imports = [
16 ./mta-sts.nix
17 ];
18
19 config = lib.mkIf cfg.enable {
20 secrets.keys = roundcubemail.keys;
21
22 services.websites.env.tools.modules =
23 [ "proxy_fcgi" ]
24 ++ rainloop.apache.modules
25 ++ roundcubemail.apache.modules;
26
27 services.websites.env.tools.vhostConfs.mail = {
28 certName = "mail";
29 addToCerts = true;
30 hosts = ["mail.immae.eu"];
31 root = "/run/current-system/webapps/_mail";
32 extraConfig = [
33 rainloop.apache.vhostConf
34 roundcubemail.apache.vhostConf
35 ''
36 <Directory /run/current-system/webapps/_mail>
37 Require all granted
38 Options -Indexes
39 </Directory>
40 ''
41 ];
42 };
43 systemd.services = {
44 phpfpm-rainloop = {
45 after = lib.mkAfter rainloop.phpFpm.serviceDeps;
46 wants = rainloop.phpFpm.serviceDeps;
47 };
48 phpfpm-roundcubemail = {
49 after = lib.mkAfter roundcubemail.phpFpm.serviceDeps;
50 wants = roundcubemail.phpFpm.serviceDeps;
51 };
52 };
53
54 services.phpfpm.pools.roundcubemail = {
55 listen = roundcubemail.phpFpm.socket;
56 extraConfig = roundcubemail.phpFpm.pool;
57 phpOptions = config.services.phpfpm.phpOptions + roundcubemail.phpFpm.phpConfig;
58 };
59 services.phpfpm.poolConfigs = {
60 rainloop = rainloop.phpFpm.pool;
61 };
62 system.activationScripts = {
63 roundcubemail = roundcubemail.activationScript;
64 rainloop = rainloop.activationScript;
65 };
66
67 myServices.websites.webappDirs = {
68 _mail = ./www;
69 "${roundcubemail.apache.webappName}" = roundcubemail.webRoot;
70 "${rainloop.apache.webappName}" = rainloop.webRoot;
71 };
72
73 };
74
75}
diff --git a/modules/private/websites/tools/mail/mta-sts.nix b/modules/private/websites/tools/mail/mta-sts.nix
new file mode 100644
index 0000000..bedefda
--- /dev/null
+++ b/modules/private/websites/tools/mail/mta-sts.nix
@@ -0,0 +1,55 @@
1{ lib, pkgs, config, myconfig, ... }:
2let
3 domains = (lib.remove null (lib.flatten (map
4 (zone: map
5 (e: if e.receive
6 then {
7 domain = "${e.domain}${lib.optionalString (e.domain != "") "."}${zone.name}";
8 mail = zone.name;
9 }
10 else null
11 )
12 (zone.withEmail or [])
13 )
14 myconfig.env.dns.masterZones
15 )));
16 # FIXME: increase the id number in modules/private/dns.nix when this
17 # file change (date -u +'%Y%m%d%H%M%S'Z)
18 file = domain: pkgs.writeText "mta-sts-${domain.domain}.txt" ''
19 version: STSv1
20 mode: testing
21 mx: mx-1.${domain.mail}
22 mx: mx-2.${domain.mail}
23 max_age: 604800
24 '';
25 root = pkgs.runCommand "mta-sts_root" {} ''
26 mkdir -p $out
27 ${builtins.concatStringsSep "\n" (map (d:
28 "cp ${file d} $out/${d.domain}.txt"
29 ) domains)}
30 '';
31in
32{
33 config.myServices.websites.webappDirs = {
34 _mta-sts = root;
35 };
36
37 config.services.websites.env.tools.vhostConfs.mta_sts = {
38 certName = "mail";
39 addToCerts = true;
40 hosts = ["mta-sts.mail.immae.eu"] ++ map (v: "mta-sts.${v.domain}") domains;
41 root = "/run/current-system/webapps/_mta-sts";
42 extraConfig = [
43 ''
44 RewriteEngine on
45 RewriteCond %{HTTP_HOST} ^mta-sts.(.*)$
46 RewriteRule ^/.well-known/mta-sts.txt$ %{DOCUMENT_ROOT}/%1.txt [L]
47 <Directory /run/current-system/webapps/_mta-sts>
48 Require all granted
49 Options -Indexes
50 </Directory>
51 ''
52 ];
53 };
54
55}
diff --git a/modules/private/websites/tools/mail/rainloop.nix b/modules/private/websites/tools/mail/rainloop.nix
new file mode 100644
index 0000000..dbf0f24
--- /dev/null
+++ b/modules/private/websites/tools/mail/rainloop.nix
@@ -0,0 +1,59 @@
1{ lib, pkgs, writeText, stdenv, fetchurl }:
2rec {
3 varDir = "/var/lib/rainloop";
4 activationScript = {
5 deps = [ "wrappers" ];
6 text = ''
7 install -m 0755 -o ${apache.user} -g ${apache.group} -d ${varDir}
8 install -m 0750 -o ${apache.user} -g ${apache.group} -d ${varDir}/phpSessions
9 install -m 0750 -o ${apache.user} -g ${apache.group} -d ${varDir}/data
10 '';
11 };
12 webRoot = pkgs.rainloop-community.override { dataPath = "${varDir}/data"; };
13 apache = rec {
14 user = "wwwrun";
15 group = "wwwrun";
16 modules = [ "proxy_fcgi" ];
17 webappName = "tools_rainloop";
18 root = "/run/current-system/webapps/${webappName}";
19 vhostConf = ''
20 Alias /rainloop "${root}"
21 <Directory "${root}">
22 DirectoryIndex index.php
23 AllowOverride All
24 Options -FollowSymlinks
25 Require all granted
26
27 <FilesMatch "\.php$">
28 SetHandler "proxy:unix:${phpFpm.socket}|fcgi://localhost"
29 </FilesMatch>
30 </Directory>
31
32 <DirectoryMatch "${root}/data">
33 Require all denied
34 </DirectoryMatch>
35 '';
36 };
37 phpFpm = rec {
38 serviceDeps = [ "postgresql.service" ];
39 basedir = builtins.concatStringsSep ":" [ webRoot varDir ];
40 socket = "/var/run/phpfpm/rainloop.sock";
41 pool = ''
42 listen = ${socket}
43 user = ${apache.user}
44 group = ${apache.group}
45 listen.owner = ${apache.user}
46 listen.group = ${apache.group}
47 pm = ondemand
48 pm.max_children = 60
49 pm.process_idle_timeout = 60
50
51 ; Needed to avoid clashes in browser cookies (same domain)
52 php_value[session.name] = RainloopPHPSESSID
53 php_admin_value[upload_max_filesize] = 200M
54 php_admin_value[post_max_size] = 200M
55 php_admin_value[open_basedir] = "${basedir}:/tmp"
56 php_admin_value[session.save_path] = "${varDir}/phpSessions"
57 '';
58 };
59}
diff --git a/modules/private/websites/tools/mail/roundcubemail.nix b/modules/private/websites/tools/mail/roundcubemail.nix
new file mode 100644
index 0000000..8bb60d6
--- /dev/null
+++ b/modules/private/websites/tools/mail/roundcubemail.nix
@@ -0,0 +1,125 @@
1{ env, roundcubemail, roundcubemail-plugins, roundcubemail-skins, phpPackages, apacheHttpd }:
2rec {
3 varDir = "/var/lib/roundcubemail";
4 activationScript = {
5 deps = [ "wrappers" ];
6 text = ''
7 install -m 0755 -o ${apache.user} -g ${apache.group} -d ${varDir} \
8 ${varDir}/cache ${varDir}/logs
9 install -m 0750 -o ${apache.user} -g ${apache.group} -d ${varDir}/phpSessions
10 '';
11 };
12 keys = [{
13 dest = "webapps/tools-roundcube";
14 user = apache.user;
15 group = apache.group;
16 permissions = "0400";
17 text = ''
18 <?php
19 $config['db_dsnw'] = '${env.psql_url}';
20 $config['default_host'] = 'ssl://imap.immae.eu';
21 $config['username_domain'] = array(
22 "imap.immae.eu" => "mail.immae.eu"
23 );
24 $config['imap_conn_options'] = array("ssl" => array("verify_peer" => false));
25 $config['smtp_server'] = 'tls://smtp.immae.eu';
26 $config['smtp_port'] = '587';
27 $config['managesieve_host'] = 'imap.immae.eu';
28 $config['managesieve_port'] = '4190';
29 $config['managesieve_usetls'] = true;
30 $config['managesieve_conn_options'] = array("ssl" => array("verify_peer" => false));
31
32 $config['imap_cache'] = 'db';
33 $config['messages_cache'] = 'db';
34
35 $config['support_url'] = ''';
36
37 $config['des_key'] = '${env.secret}';
38
39 $config['skin'] = 'elastic';
40 $config['plugins'] = array(
41 'attachment_reminder',
42 'emoticons',
43 'filesystem_attachments',
44 'hide_blockquote',
45 'identicon',
46 'identity_select',
47 'jqueryui',
48 'markasjunk',
49 'managesieve',
50 'newmail_notifier',
51 'vcard_attachments',
52 'zipdownload',
53
54 'automatic_addressbook',
55 'message_highlight',
56 'carddav',
57 // Ne marche pas ?: 'ident_switch',
58 // Ne marche pas ?: 'thunderbird_labels',
59 );
60
61 $config['language'] = 'fr_FR';
62
63 $config['drafts_mbox'] = 'Drafts';
64 $config['junk_mbox'] = 'Junk';
65 $config['sent_mbox'] = 'Sent';
66 $config['trash_mbox'] = 'Trash';
67 $config['default_folders'] = array('INBOX', 'Drafts', 'Sent', 'Junk', 'Trash');
68 $config['draft_autosave'] = 60;
69 $config['enable_installer'] = false;
70 $config['log_driver'] = 'file';
71 $config['temp_dir'] = '${varDir}/cache';
72 $config['mime_types'] = '${apacheHttpd}/conf/mime.types';
73 '';
74 }];
75 webRoot = (roundcubemail.override { roundcube_config = "/var/secrets/webapps/tools-roundcube"; }).withPlugins
76 (builtins.attrValues roundcubemail-plugins) (builtins.attrValues roundcubemail-skins);
77 apache = rec {
78 user = "wwwrun";
79 group = "wwwrun";
80 modules = [ "proxy_fcgi" ];
81 webappName = "tools_roundcubemail";
82 root = "/run/current-system/webapps/${webappName}";
83 vhostConf = ''
84 Alias /roundcube "${root}"
85 <Directory "${root}">
86 DirectoryIndex index.php
87 AllowOverride All
88 Options FollowSymlinks
89 Require all granted
90
91 <FilesMatch "\.php$">
92 SetHandler "proxy:unix:${phpFpm.socket}|fcgi://localhost"
93 </FilesMatch>
94 </Directory>
95 '';
96 };
97 phpFpm = rec {
98 serviceDeps = [ "postgresql.service" ];
99 basedir = builtins.concatStringsSep ":" (
100 [ webRoot "/var/secrets/webapps/tools-roundcube" varDir ]
101 ++ webRoot.plugins
102 ++ webRoot.skins);
103 phpConfig = ''
104 date.timezone = 'CET'
105 extension=${phpPackages.imagick}/lib/php/extensions/imagick.so
106 '';
107 socket = "/var/run/phpfpm/roundcubemail.sock";
108 pool = ''
109 user = ${apache.user}
110 group = ${apache.group}
111 listen.owner = ${apache.user}
112 listen.group = ${apache.group}
113 pm = ondemand
114 pm.max_children = 60
115 pm.process_idle_timeout = 60
116
117 ; Needed to avoid clashes in browser cookies (same domain)
118 php_value[session.name] = RoundcubemailPHPSESSID
119 php_admin_value[upload_max_filesize] = 200M
120 php_admin_value[post_max_size] = 200M
121 php_admin_value[open_basedir] = "${basedir}:${apacheHttpd}/conf/mime.types:/tmp"
122 php_admin_value[session.save_path] = "${varDir}/phpSessions"
123 '';
124 };
125}
diff --git a/modules/private/websites/tools/mail/www/index.html b/modules/private/websites/tools/mail/www/index.html
new file mode 100644
index 0000000..3727c42
--- /dev/null
+++ b/modules/private/websites/tools/mail/www/index.html
@@ -0,0 +1,73 @@
1<!doctype html>
2<html lang="fr">
3 <head>
4 <meta charset="UTF-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <title>E-mail configuration</title>
7 <style type="text/css">
8 body {
9 padding-top: 1em;
10 padding-left: 5px;
11 padding-right: 5px;
12 text-align: left;
13 margin: auto;
14 font: 20px Helvetica, sans-serif;
15 color: #333;
16 height: 100%;
17 min-height: 100%;
18 }
19 article {
20 text-align: justify;
21 display: block;
22 max-width: 850px;
23 margin: 0 auto;
24 padding-top: 30px;
25 }
26 span.code {
27 font-family: monospace;
28 }
29 </style>
30 </head>
31 <body>
32 <p>
33 Email configuration. For automatic configuration in your smart e-mail
34 client, use <span class="code">login@mail.immae.eu</span>. If it
35 doesn’t work, the details are there:
36 <ul>
37 <li>IMAP: <span class="code">imap.immae.eu</span>
38 <ul>
39 <li>No unencrypted access</li>
40 <li>STARTTLS: 143 (recommended)</li>
41 <li>SSL: 993</li>
42 </ul>
43 </li>
44 <li>POP3: <span class="code">pop3.immae.eu</span>
45 <ul>
46 <li>No unencrypted access</li>
47 <li>STARTTLS: 110 (recommended)</li>
48 <li>SSL: 995</li>
49 </ul>
50 </li>
51 <li>SMTP: <span class="code">smtp.immae.eu</span>
52 <ul>
53 <li>No unencrypted access</li>
54 <li>STARTTLS: 587</li>
55 </ul>
56 </li>
57 <li>Sieve: <span class="code">imap.immae.eu</span>
58 <ul>
59 <li>No unencrypted access</li>
60 <li>STARTTLS: 4190</li>
61 </ul>
62 </li>
63 </ul>
64 </p>
65 <p>Webmails:
66 <ul>
67 <li><a href="/roundcube">Roundcube</a></li>
68 <li><a href="/rainloop">Rainloop</a> (experimental)</li>
69 </ul>
70 </p>
71 </body>
72</html>
73