nixos-config/config/fudo/webmail.nix

319 lines
8.8 KiB
Nix

{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.fudo.webmail;
inherit (lib.strings) concatStringsSep;
webmail-user = "webmail-php";
webmail-group = "webmail-php";
base-data-path = "/var/rainloop";
fastcgi-conf = builtins.toFile "fastcgi.conf" ''
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;
fastcgi_param REQUEST_SCHEME $scheme;
fastcgi_param HTTPS $https if_not_empty;
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;
fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;
# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param REDIRECT_STATUS 200;
'';
site-packages = mapAttrs (site: site-cfg:
pkgs.rainloop-community.overrideAttrs (oldAttrs: {
# Not sure how to correctly specify this arg...
#dataPath = "${base-data-path}/${site}";
# Overwriting, to correctly create data dir
installPhase = ''
mkdir $out
cp -r rainloop/* $out
rm -rf $out/data
ln -s ${base-data-path}/${site} $out/data
ln -s ${site-cfg.favicon} $out/favicon.ico
'';
}))
cfg.sites;
siteOpts = { site-host, ... }: {
options = {
title = mkOption {
type = types.str;
description = "Webmail site title";
example = "My Webmail";
};
debug = mkOption {
type = types.bool;
description = "Turn debug logs on.";
default = false;
};
mail-server = mkOption {
type = types.str;
description = "Mail server from which to send & recieve email.";
default = "mail.fudo.org";
};
favicon = mkOption {
type = types.str;
description = "URL of the site favicon";
example = "https://www.somepage.com/fav.ico";
};
messages-per-page = mkOption {
type = types.int;
description = "Default number of messages to show per page";
default = 30;
};
max-upload-size = mkOption {
type = types.int;
description = "Size limit in MB for uploaded files";
default = 30;
};
theme = mkOption {
type = types.str;
description = "Default theme to use for this webmail site.";
default = "Default";
};
# Ideally, don't even allow admin logins, since they'll just add state that can be clobbered
# admin-password = mkOption {
# type = types.str;
# description = "Password to use for the admin user";
# };
domain = mkOption {
type = types.str;
description = "Domain for which the server acts as webmail server";
};
edit-mode = mkOption {
type = types.enum ["Plain" "Html" "PlainForced" "HtmlForced"];
description = "Default text editing mode for email";
default = "Html";
};
layout-mode = mkOption {
type = types.enum ["side" "bottom"];
description = "Layout mode to use for email preview.";
default = "side";
};
enable-threading = mkOption {
type = types.bool;
description = "Whether to enable threading for email.";
default = true;
};
enable-mobile = mkOption {
type = types.bool;
description = "Whether to enable a mobile site view.";
default = true;
};
database = mkOption {
type = with types; nullOr (submodule databaseOpts);
description = "Database configuration for storing contact data.";
example = {
name = "my_db";
host = "db.domain.com";
user = "my_user";
password-file = /path/to/some/file.pw;
};
default = null;
};
};
};
databaseOpts = { ... }: {
options = {
type = mkOption {
type = types.enum ["pgsql" "mysql"];
description = "Driver to use when connecting to the database.";
default = "pgsql";
};
hostname = mkOption {
type = types.str;
description = "Name of host running the database.";
example = "my-db.domain.com";
};
port = mkOption {
type = types.int;
description = "Port on which the database server is listening.";
default = 5432;
};
name = mkOption {
type = types.str;
description = "Name of the database containing contact info. <user> must have access.";
default = "rainloop_contacts";
};
user = mkOption {
type = types.str;
description = "User as which to connect to the database.";
};
password-file = mkOption {
type = types.path;
description = "Password to use when connecting to the database.";
};
};
};
in {
options.fudo.webmail = {
enable = mkEnableOption "Enable a RainLoop webmail server.";
sites = mkOption {
type = with types; (loaOf (submodule siteOpts));
description = "A map of webmail sites to site configurations.";
example = {
"webmail.domain.com" = {
title = "My Awesome Webmail";
layout-mode = "side";
favicon = "/path/to/favicon.ico";
admin-password = "shh-don't-tell";
};
};
};
};
config = mkIf cfg.enable {
users = {
users = {
${webmail-user} = {
isSystemUser = true;
description = "Webmail PHP FPM user";
group = webmail-group;
};
};
groups = {
${webmail-group} = {
members = [ webmail-user config.services.nginx.user ];
};
};
};
services = {
phpfpm = {
pools.webmail = {
settings = {
"pm" = "dynamic";
"pm.max_children" = 50;
"pm.start_servers" = 5;
"pm.min_spare_servers" = 1;
"pm.max_spare_servers" = 8;
};
# Not working....see chmod below
user = webmail-user;
group = webmail-group;
};
};
nginx = {
enable = true;
virtualHosts = mapAttrs (site: site-cfg: {
enableACME = true;
forceSSL = true;
root = "${site-packages.${site}}";
locations = {
"/" = {
index = "index.php";
};
"/data" = {
extraConfig = ''
deny all;
return 403;
'';
};
};
extraConfig = ''
location ~ \.php$ {
expires -1;
include ${fastcgi-conf};
fastcgi_index index.php;
fastcgi_pass unix:${config.services.phpfpm.pools.webmail.socket};
}
'';
})
cfg.sites;
};
};
systemd.services.nginx.preStart = let
link-configs = concatStringsSep "\n" (mapAttrsToList (site: site-cfg: let
cfg-file = builtins.toFile "${site}-rainloop.cfg" (import ./include/rainloop.nix lib site site-cfg site-packages.${site}.version);
domain-cfg = builtins.toFile "${site}-domain.cfg" ''
imap_host = "${site-cfg.mail-server}"
imap_port = 143
imap_secure = "TLS"
imap_short_login = On
sieve_use = Off
sieve_allow_raw = Off
sieve_host = ""
sieve_port = 4190
sieve_secure = "None"
smtp_host = "${site-cfg.mail-server}"
smtp_port = 587
smtp_secure = "TLS"
smtp_short_login = On
smtp_auth = On
smtp_php_mail = Off
white_list = ""
'';
in ''
mkdir -p ${base-data-path}/${site}/_data_/_default_/configs
cp ${cfg-file} ${base-data-path}/${site}/_data_/_default_/configs/application.ini
mkdir -p ${base-data-path}/${site}/_data_/_default_/domains/
cp ${domain-cfg} ${base-data-path}/${site}/_data_/_default_/domains/${site-cfg.domain}.ini
'') cfg.sites);
in ''
${link-configs}
chown -R ${webmail-user}:${webmail-group} ${base-data-path}
chmod -R ug+w ${base-data-path}
'';
systemd.services.phpfpm-webmail.postStart = ''
chown ${webmail-user}:${webmail-group} ${config.services.phpfpm.pools.webmail.socket}
'';
};
}