aboutsummaryrefslogtreecommitdiff
path: root/systems/eldiron/websites/mail
diff options
context:
space:
mode:
Diffstat (limited to 'systems/eldiron/websites/mail')
-rw-r--r--systems/eldiron/websites/mail/default.nix141
-rw-r--r--systems/eldiron/websites/mail/mta-sts.nix42
-rw-r--r--systems/eldiron/websites/mail/rainloop.nix54
-rw-r--r--systems/eldiron/websites/mail/roundcubemail.nix119
-rw-r--r--systems/eldiron/websites/mail/www/index.html74
5 files changed, 430 insertions, 0 deletions
diff --git a/systems/eldiron/websites/mail/default.nix b/systems/eldiron/websites/mail/default.nix
new file mode 100644
index 0000000..0a0342b
--- /dev/null
+++ b/systems/eldiron/websites/mail/default.nix
@@ -0,0 +1,141 @@
1{ lib, pkgs, config, ... }:
2let
3 roundcubemail = pkgs.callPackage ./roundcubemail.nix {
4 roundcubemail = pkgs.webapps-roundcubemail;
5 env = config.myEnv.tools.roundcubemail;
6 inherit config;
7 };
8 rainloop = pkgs.callPackage ./rainloop.nix {
9 rainloop = pkgs.rainloop-community;
10 };
11 cfg = config.myServices.websites.tools.email;
12 pcfg = config.services.phpfpm.pools;
13in
14{
15 options.myServices.websites.tools.email = {
16 enable = lib.mkEnableOption "enable email website";
17 };
18
19 imports = [
20 ./mta-sts.nix
21 ];
22
23 config = lib.mkIf cfg.enable {
24 #myServices.chatonsProperties.services.mail-rainloop = {
25 # file.datetime = "2022-08-22T00:30:00";
26 # service = {
27 # name = "Rainloop";
28 # description = "Simple, modern & fast web-based email client";
29 # website = "https://mail.immae.eu/rainloop";
30 # logo = "https://www.rainloop.net/static/img/logo-16x16.png";
31 # status.level = "ERROR";
32 # status.description = "Stopped due to CVE-2022-29360";
33 # registration."" = ["MEMBER" "CLIENT"];
34 # registration.load = "OPEN";
35 # install.type = "PACKAGE";
36 # };
37 # software = {
38 # name = "Rainloop";
39 # website = "https://www.rainloop.net/";
40 # license.url = "https://www.rainloop.net/licensing/";
41 # license.name = "GNU Affero General Public License v3.0";
42 # version = rainloop.webRoot.version;
43 # source.url = "https://github.com/RainLoop/rainloop-webmail";
44 # };
45 #};
46 #myServices.chatonsProperties.services.mail-roundcube = {
47 # file.datetime = "2022-08-22T00:30:00";
48 # service = {
49 # name = "Roundcube";
50 # description = "The Roundcube Webmail suite";
51 # website = "https://mail.immae.eu/roundcube";
52 # logo = "https://mail.immae.eu/roundcube/skins/elastic/images/favicon.ico";
53 # status.level = "OK";
54 # status.description = "OK";
55 # registration."" = ["MEMBER" "CLIENT"];
56 # registration.load = "OPEN";
57 # install.type = "PACKAGE";
58 # };
59 # software = {
60 # name = "Roundcube";
61 # website = "https://roundcube.net/";
62 # license.url = "https://github.com/roundcube/roundcubemail/blob/master/LICENSE";
63 # license.name = "GNU General Public License v3.0";
64 # version = roundcubemail.webRoot.version;
65 # source.url = "https://github.com/roundcube/roundcubemail";
66 # modules = map (a: a.pluginName) roundcubemail.webRoot.plugins ++ map (a: a.skinName) roundcubemail.webRoot.skins;
67 # };
68 #};
69
70 myServices.dns.zones."immae.eu".subdomains.mail =
71 with config.myServices.dns.helpers; ips servers.eldiron.ips.main;
72
73 secrets.keys = roundcubemail.keys;
74
75 services.websites.env.tools.modules =
76 [ "proxy_fcgi" ]
77 ++ rainloop.apache.modules
78 ++ roundcubemail.apache.modules;
79
80 security.acme.certs.mail.extraDomainNames = [ "mail.immae.eu" ];
81 services.websites.env.tools.vhostConfs.mail = {
82 certName = "mail";
83 hosts = ["mail.immae.eu"];
84 root = ./www;
85 extraConfig = [
86 (rainloop.apache.vhostConf pcfg.rainloop.socket)
87 (roundcubemail.apache.vhostConf pcfg.roundcubemail.socket)
88 ''
89 <Directory ${./www}>
90 Require all granted
91 Options -Indexes
92 </Directory>
93 ''
94 ];
95 };
96 systemd.services = {
97 phpfpm-rainloop = {
98 after = lib.mkAfter rainloop.phpFpm.serviceDeps;
99 wants = rainloop.phpFpm.serviceDeps;
100 };
101 phpfpm-roundcubemail = {
102 after = lib.mkAfter roundcubemail.phpFpm.serviceDeps;
103 wants = roundcubemail.phpFpm.serviceDeps;
104 };
105 };
106
107 services.phpfpm.pools.roundcubemail = {
108 user = "wwwrun";
109 group = "wwwrun";
110 settings = roundcubemail.phpFpm.pool;
111 phpOptions = config.services.phpfpm.phpOptions + ''
112 date.timezone = 'CET'
113 '';
114 phpPackage = pkgs.php72.withExtensions({ enabled, all }: enabled ++ [ all.imagick all.redis ]);
115 };
116 services.phpfpm.pools.rainloop = {
117 user = "wwwrun";
118 group = "wwwrun";
119 settings = rainloop.phpFpm.pool;
120 phpPackage = pkgs.php72.withExtensions({ enabled, all }: enabled ++ [ all.redis ]);
121 };
122 system.activationScripts = {
123 roundcubemail = roundcubemail.activationScript;
124 rainloop = rainloop.activationScript;
125 };
126 myServices.monitoring.fromMasterActivatedPlugins = [ "http" ];
127 myServices.monitoring.fromMasterObjects.service = [
128 {
129 service_description = "roundcube website is running on mail.immae.eu";
130 host_name = config.hostEnv.fqdn;
131 use = "external-web-service";
132 check_command = ["check_https" "mail.immae.eu" "/roundcube/" "<title>Roundcube"];
133
134 servicegroups = "webstatus-webapps,webstatus-email";
135 _webstatus_name = "Roundcube";
136 _webstatus_url = "https://mail.immae.eu/roundcube/";
137 }
138 ];
139 };
140
141}
diff --git a/systems/eldiron/websites/mail/mta-sts.nix b/systems/eldiron/websites/mail/mta-sts.nix
new file mode 100644
index 0000000..2438702
--- /dev/null
+++ b/systems/eldiron/websites/mail/mta-sts.nix
@@ -0,0 +1,42 @@
1{ lib, pkgs, config, ... }:
2let
3 getDomains = p: lib.mapAttrsToList (n: v: v) (lib.filterAttrs (n: v: v.receive) p.emailPolicies);
4 bydomain = builtins.mapAttrs (n: getDomains) config.myServices.dns.zones;
5 domains = lib.flatten (builtins.attrValues bydomain);
6 mxes = lib.mapAttrsToList
7 (n: v: v.mx.subdomain)
8 (lib.attrsets.filterAttrs (n: v: v.mx.enable) config.myEnv.servers);
9 file = d: pkgs.writeText "mta-sts-${d.fqdn}.txt" (
10 builtins.concatStringsSep "\r\n" ([ "version: STSv1" "mode: testing" ]
11 ++ (map (v: "mx: ${v}.${d.domain}") mxes)
12 ++ [ "max_age: 604800" ]
13 ));
14 root = pkgs.runCommand "mta-sts_root" {} ''
15 mkdir -p $out
16 ${builtins.concatStringsSep "\n" (map (d:
17 "cp ${file d} $out/${d.fqdn}.txt"
18 ) domains)}
19 '';
20 cfg = config.myServices.websites.tools.email;
21in
22{
23 config = lib.mkIf cfg.enable {
24 security.acme.certs.mail.extraDomainNames = ["mta-sts.mail.immae.eu"] ++ map (v: "mta-sts.${v.fqdn}") domains;
25 services.websites.env.tools.vhostConfs.mta_sts = {
26 certName = "mail";
27 hosts = ["mta-sts.mail.immae.eu"] ++ map (v: "mta-sts.${v.fqdn}") domains;
28 root = root;
29 extraConfig = [
30 ''
31 RewriteEngine on
32 RewriteCond %{HTTP_HOST} ^mta-sts.(.*)$
33 RewriteRule ^/.well-known/mta-sts.txt$ %{DOCUMENT_ROOT}/%1.txt [L]
34 <Directory ${root}>
35 Require all granted
36 Options -Indexes
37 </Directory>
38 ''
39 ];
40 };
41 };
42}
diff --git a/systems/eldiron/websites/mail/rainloop.nix b/systems/eldiron/websites/mail/rainloop.nix
new file mode 100644
index 0000000..f821005
--- /dev/null
+++ b/systems/eldiron/websites/mail/rainloop.nix
@@ -0,0 +1,54 @@
1{ lib, rainloop, 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}/data
9 '';
10 };
11 webRoot = rainloop.override { dataPath = "${varDir}/data"; };
12 apache = rec {
13 user = "wwwrun";
14 group = "wwwrun";
15 modules = [ "proxy_fcgi" ];
16 root = webRoot;
17 vhostConf = socket: ''
18 Alias /rainloop "${root}"
19 <Directory "${root}">
20 DirectoryIndex index.php
21 AllowOverride All
22 Options -FollowSymlinks
23 Require all denied
24
25 <FilesMatch "\.php$">
26 SetHandler "proxy:unix:${socket}|fcgi://localhost"
27 </FilesMatch>
28 </Directory>
29
30 <DirectoryMatch "${root}/data">
31 Require all denied
32 </DirectoryMatch>
33 '';
34 };
35 phpFpm = rec {
36 serviceDeps = [ "postgresql.service" ];
37 basedir = builtins.concatStringsSep ":" [ webRoot varDir ];
38 pool = {
39 "listen.owner" = apache.user;
40 "listen.group" = apache.group;
41 "pm" = "ondemand";
42 "pm.max_children" = "60";
43 "pm.process_idle_timeout" = "60";
44
45 # Needed to avoid clashes in browser cookies (same domain)
46 "php_value[session.name]" = "RainloopPHPSESSID";
47 "php_admin_value[upload_max_filesize]" = "200M";
48 "php_admin_value[post_max_size]" = "200M";
49 "php_admin_value[open_basedir]" = "${basedir}:/tmp";
50 "php_admin_value[session.save_handler]" = "redis";
51 "php_admin_value[session.save_path]" = "'unix:///run/redis-php-sessions/redis.sock?persistent=1&prefix=Tools:Rainloop:'";
52 };
53 };
54}
diff --git a/systems/eldiron/websites/mail/roundcubemail.nix b/systems/eldiron/websites/mail/roundcubemail.nix
new file mode 100644
index 0000000..21a10fe
--- /dev/null
+++ b/systems/eldiron/websites/mail/roundcubemail.nix
@@ -0,0 +1,119 @@
1{ env, roundcubemail, apacheHttpd, config }:
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 '';
10 };
11 keys."webapps/tools-roundcube" = {
12 user = apache.user;
13 group = apache.group;
14 permissions = "0400";
15 text =
16 let
17 psql_url = with env.postgresql; "pgsql://${user}:${password}@unix(${socket}:${port})/${database}";
18 in ''
19 <?php
20 $config['db_dsnw'] = '${psql_url}';
21 $config['default_host'] = 'ssl://imap.immae.eu';
22 $config['username_domain'] = array(
23 "imap.immae.eu" => "mail.immae.eu"
24 );
25 $config['imap_conn_options'] = array("ssl" => array("verify_peer" => false));
26 $config['smtp_server'] = 'tls://smtp.immae.eu';
27 $config['smtp_port'] = '587';
28 $config['managesieve_host'] = 'imap.immae.eu';
29 $config['managesieve_port'] = '4190';
30 $config['managesieve_usetls'] = true;
31 $config['managesieve_conn_options'] = array("ssl" => array("verify_peer" => false));
32
33 $config['imap_cache'] = 'db';
34 $config['messages_cache'] = 'db';
35
36 $config['support_url'] = ''';
37
38 $config['des_key'] = '${env.secret}';
39
40 $config['skin'] = 'elastic';
41 $config['plugins'] = array(
42 'attachment_reminder',
43 'emoticons',
44 'filesystem_attachments',
45 'hide_blockquote',
46 'identicon',
47 'identity_select',
48 'jqueryui',
49 'markasjunk',
50 'managesieve',
51 'newmail_notifier',
52 'vcard_attachments',
53 'zipdownload',
54
55 'automatic_addressbook',
56 'message_highlight',
57 'carddav',
58 // Ne marche pas ?: 'ident_switch',
59 // Ne marche pas ?: 'thunderbird_labels',
60 );
61
62 $config['language'] = 'fr_FR';
63
64 $config['drafts_mbox'] = 'Drafts';
65 $config['junk_mbox'] = 'Junk';
66 $config['sent_mbox'] = 'Sent';
67 $config['trash_mbox'] = 'Trash';
68 $config['default_folders'] = array('INBOX', 'Drafts', 'Sent', 'Junk', 'Trash');
69 $config['draft_autosave'] = 60;
70 $config['enable_installer'] = false;
71 $config['log_driver'] = 'file';
72 $config['temp_dir'] = '${varDir}/cache';
73 $config['mime_types'] = '${apacheHttpd}/conf/mime.types';
74 '';
75 keyDependencies = [ apacheHttpd ];
76 };
77 webRoot = (roundcubemail.override { roundcube_config = config.secrets.fullPaths."webapps/tools-roundcube"; }).withPlugins (p: [ p.automatic_addressbook p.carddav p.contextmenu p.contextmenu_folder p.html5_notifier p.ident_switch p.message_highlight p.thunderbird_labels ]);
78 apache = rec {
79 user = "wwwrun";
80 group = "wwwrun";
81 modules = [ "proxy_fcgi" ];
82 root = webRoot;
83 vhostConf = socket: ''
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:${socket}|fcgi://localhost"
93 </FilesMatch>
94 </Directory>
95 '';
96 };
97 phpFpm = rec {
98 serviceDeps = [ "postgresql.service" ];
99 basedir = builtins.concatStringsSep ":" (
100 [ webRoot config.secrets.fullPaths."webapps/tools-roundcube" varDir ]
101 ++ webRoot.plugins
102 ++ webRoot.skins);
103 pool = {
104 "listen.owner" = apache.user;
105 "listen.group" = apache.group;
106 "pm" = "ondemand";
107 "pm.max_children" = "60";
108 "pm.process_idle_timeout" = "60";
109
110 # Needed to avoid clashes in browser cookies (same domain)
111 "php_value[session.name]" = "RoundcubemailPHPSESSID";
112 "php_admin_value[upload_max_filesize]" = "200M";
113 "php_admin_value[post_max_size]" = "200M";
114 "php_admin_value[open_basedir]" = "${basedir}:${apacheHttpd}/conf/mime.types:/tmp";
115 "php_admin_value[session.save_handler]" = "redis";
116 "php_admin_value[session.save_path]" = "'unix:///run/redis-php-sessions/redis.sock?persistent=1&prefix=Tools:Roundcubemail:'";
117 };
118 };
119}
diff --git a/systems/eldiron/websites/mail/www/index.html b/systems/eldiron/websites/mail/www/index.html
new file mode 100644
index 0000000..88b0ebd
--- /dev/null
+++ b/systems/eldiron/websites/mail/www/index.html
@@ -0,0 +1,74 @@
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</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</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 <li>SSL: 465</li>
56 </ul>
57 </li>
58 <li>Sieve: <span class="code">imap.immae.eu</span>
59 <ul>
60 <li>No unencrypted access</li>
61 <li>STARTTLS: 4190</li>
62 </ul>
63 </li>
64 </ul>
65 </p>
66 <p>Webmails:
67 <ul>
68 <li><a href="/roundcube">Roundcube</a></li>
69 <li><a href="/rainloop">Rainloop</a> (experimental)</li>
70 </ul>
71 </p>
72 </body>
73</html>
74