diff options
author | Ismaël Bouya <ismael.bouya@normalesup.org> | 2023-10-04 01:35:06 +0200 |
---|---|---|
committer | Ismaël Bouya <ismael.bouya@normalesup.org> | 2023-10-04 02:11:48 +0200 |
commit | 1a64deeb894dc95e2645a75771732c6cc53a79ad (patch) | |
tree | 1b9df4838f894577a09b9b260151756272efeb53 /systems/eldiron/websites/mail | |
parent | fa25ffd4583cc362075cd5e1b4130f33306103f0 (diff) | |
download | Nix-1a64deeb894dc95e2645a75771732c6cc53a79ad.tar.gz Nix-1a64deeb894dc95e2645a75771732c6cc53a79ad.tar.zst Nix-1a64deeb894dc95e2645a75771732c6cc53a79ad.zip |
Squash changes containing private information
There were a lot of changes since the previous commit, but a lot of them
contained personnal information about users. All thos changes got
stashed into a single commit (history is kept in a different place) and
private information was moved in a separate private repository
Diffstat (limited to 'systems/eldiron/websites/mail')
-rw-r--r-- | systems/eldiron/websites/mail/default.nix | 141 | ||||
-rw-r--r-- | systems/eldiron/websites/mail/mta-sts.nix | 42 | ||||
-rw-r--r-- | systems/eldiron/websites/mail/rainloop.nix | 54 | ||||
-rw-r--r-- | systems/eldiron/websites/mail/roundcubemail.nix | 119 | ||||
-rw-r--r-- | systems/eldiron/websites/mail/www/index.html | 74 |
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, ... }: | ||
2 | let | ||
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; | ||
13 | in | ||
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, ... }: | ||
2 | let | ||
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; | ||
21 | in | ||
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 }: | ||
2 | rec { | ||
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 }: | ||
2 | rec { | ||
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 | |||