lib = {
# Check that there is no clash with nixos/modules/misc/ids.nix
uids = {
+ cryptpad = 386;
postfixscripts = 387;
acme = 388;
backup = 389;
};
gids = {
nagios = 11; # commented in the ids file
+ cryptpad = 386;
acme = 388;
backup = 389;
vhost = 390;
assetsTools = ./websites/tools/assets;
cloudTool = ./websites/tools/cloud;
cloudFarmTool = ./websites/tools/cloud/farm.nix;
+ cryptpadTool = ./websites/tools/cryptpad;
+ cryptpadFarmTool = ./websites/tools/cryptpad/farm.nix;
commentoTool = ./websites/tools/commento;
davTool = ./websites/tools/dav;
vpnTool = ./websites/tools/vpn;
};
};
};
+ cryptpad = mkOption {
+ description = "Cryptpad configuration";
+ type = attrsOf (submodule {
+ options = {
+ email = mkOption { type = str; description = "Admin e-mail"; };
+ admins = mkOption { type = listOf str; description = "Instance admin public keys"; };
+ port = mkOption { type = port; description = "Port to listen to"; };
+ };
+ });
+ };
ympd = mkOption {
description = "Ympd configuration";
type = submodule {
interface = "eth0";
};
eldiron = {
- processWarn = "400"; processAlert = "500";
+ processWarn = "550"; processAlert = "650";
loadWarn = "1.0"; loadAlert = "1.2";
interface = "eth0";
};
tools.assets.enable = true;
tools.cloud.enable = true;
tools.commento.enable = true;
+ tools.cryptpad.enable = true;
tools.dav.enable = true;
tools.db.enable = true;
tools.diaspora.enable = true;
{ lib, pkgs, config, ... }:
let
cfg = config.myServices.websites.ressourcerie_banon.cryptpad;
- port = config.myEnv.ports.cryptpad_ressourcerie_banon;
+ envCfg = config.myEnv.tools.cryptpad.ressourcerie_banon;
+ port = envCfg.port;
configFile = pkgs.writeText "config.js" ''
// ${pkgs.cryptpad}/lib/node_modules/cryptpad/config/config.example.js
module.exports = {
httpUnsafeOrigin: 'https://${domain}',
httpPort: ${toString port},
- adminEmail: 'devnull@mail.immae.eu',
+ adminEmail: '${envCfg.email}',
filePath: './datastore/',
archivePath: './data/archive',
pinPath: './data/pins',
logLevel: 'info',
logFeedback: false,
verbose: false,
+ inactiveTime: false,
+ adminKeys: ${builtins.toJSON envCfg.admins},
};
'';
domain = "pad.le-garage-autonome.org";
- api_domain = "pad.le-garage-autonome.org";
- files_domain = "pad.le-garage-autonome.org";
in {
options.myServices.websites.ressourcerie_banon.cryptpad.enable = lib.mkEnableOption "Enable Ressourcerie Banon’s cryptpad";
config = lib.mkIf cfg.enable {
- systemd.services.cryptpad-ressourcerie_banon = {
- description = "Cryptpad Banon Service";
- wantedBy = [ "multi-user.target" ];
- after = [ "networking.target" ];
- serviceConfig = {
- DynamicUser = true;
- Environment = [
- "CRYPTPAD_CONFIG=${configFile}"
- "HOME=%S/cryptpad/ressourcerie_banon"
- ];
- ExecStart = "${pkgs.cryptpad}/bin/cryptpad";
- PrivateTmp = true;
- Restart = "always";
- StateDirectory = "cryptpad/ressourcerie_banon";
- WorkingDirectory = "%S/cryptpad/ressourcerie_banon";
- };
+ myServices.tools.cryptpad.farm.hosts.ressourcerie_banon = {
+ inherit domain port;
+ config = configFile;
};
services.websites.env.production.modules = [ "proxy_wstunnel" ];
services.websites.env.production.vhostConfs.ressourcerie_banon_cryptpad = {
certName = "ressourcerie_banon";
addToCerts = true;
hosts = [domain];
- root = "${pkgs.cryptpad}/lib/node_modules/cryptpad";
+ root = config.myServices.tools.cryptpad.farm.vhostRoots.ressourcerie_banon;
extraConfig = [
- ''
- RewriteEngine On
-
- Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
- Header set X-XSS-Protection "1; mode=block"
- Header set X-Content-Type-Options "nosniff"
- Header set Access-Control-Allow-Origin "*"
- Header set Permissions-Policy "interest-cohort=()"
-
- Header set Cross-Origin-Resource-Policy "cross-origin"
- <If "%{REQUEST_URI} =~ m#^/(sheet|presentation|doc)/.*$#">
- Header set Cross-Origin-Opener-Policy "same-origin"
- </If>
- Header set Cross-Origin-Embedder-Policy "require-corp"
-
- ErrorDocument 404 /customize.dist/404.html
-
- <If "%{QUERY_STRING} =~ m#ver=.*?#">
- Header set Cache-Control "max-age=31536000"
- </If>
- <If "%{REQUEST_URI} =~ m#^/.*(\/|\.html)$#">
- Header set Cache-Control "no-cache"
- </If>
-
- SetEnv styleSrc "'unsafe-inline' 'self' ${domain}"
- SetEnv connectSrc "'self' https://${domain} ${domain} https://${api_domain} blob: wss://${api_domain} ${api_domain} ${files_domain}"
- SetEnv fontSrc "'self' data: ${domain}"
- SetEnv imgSrc "'self' data: * blob: ${domain}"
- SetEnv frameSrc "'self' blob:"
- SetEnv mediaSrc "'self' data: * blob: ${domain}"
- SetEnv childSrc "https://${domain}"
- SetEnv workerSrc "https://${domain}"
- SetEnv scriptSrc "'self' resource: ${domain}"
-
- Header set Content-Security-Policy "default-src 'none'; child-src %{childSrc}e; worker-src %{workerSrc}e; media-src %{mediaSrc}e; style-src %{styleSrc}e; script-src %{scriptSrc}e; connect-src %{connectSrc}e; font-src %{fontSrc}e; img-src %{imgSrc}e; frame-src %{frameSrc}e;"
-
- RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
- RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]
- RewriteRule .* ws://localhost:${toString port}%{REQUEST_URI} [P,NE,QSA,L]
-
- RewriteRule ^/customize/(.*)$ /customize.dist/$1 [L]
-
- ProxyPassMatch "^/(api/(config|broadcast).*)$" "http://localhost:${toString port}/$1"
- ProxyPassReverse /api http://localhost:${toString port}/api
- ProxyPreserveHost On
- RequestHeader set X-Real-IP %{REMOTE_ADDR}s
-
- <LocationMatch /blob/>
- Header set Cache-Control "max-age=31536000"
- Header set Access-Control-Allow-Origin "*"
- Header set Access-Control-Allow-Methods "GET, POST, OPTIONS"
- Header set Access-Control-Allow-Headers "DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range,Content-Length"
- Header set Access-Control-Expose-Headers "DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range,Content-Length"
-
- RewriteCond %{REQUEST_METHOD} OPTIONS
- RewriteRule ^(.*)$ $1 [R=204,L]
- </LocationMatch>
-
- <LocationMatch /block/>
- Header set Cache-Control "max-age=0"
- </locationMatch>
-
- RewriteRule ^/(register|login|settings|user|pad|drive|poll|slide|code|whiteboard|file|media|profile|contacts|todo|filepicker|debug|kanban|sheet|support|admin|notifications|teams|calendar|presentation|doc)$ $1/ [R=302,L]
-
- RewriteCond %{DOCUMENT_ROOT}/www/%{REQUEST_URI} -f
- RewriteRule (.*) /www/$1 [L]
-
- RewriteCond %{DOCUMENT_ROOT}/www/%{REQUEST_URI}/index.html -f
- RewriteRule (.*) /www/$1/index.html [L]
-
- RewriteCond %{DOCUMENT_ROOT}/customize.dist/%{REQUEST_URI} -f
- RewriteRule (.*) /customize.dist/$1 [L]
-
- <Directory ${pkgs.cryptpad}/lib/node_modules/cryptpad/www>
- AllowOverride None
- Require all granted
- DirectoryIndex index.html
- </Directory>
- <Directory ${pkgs.cryptpad}/lib/node_modules/cryptpad/customize.dist>
- AllowOverride None
- Require all granted
- DirectoryIndex index.html
- </Directory>
- ''
+ config.myServices.tools.cryptpad.farm.vhosts.ressourcerie_banon
];
};
};
--- /dev/null
+{ config, pkgs, lib, ... }:
+let
+ cfg = config.myServices.websites.tools.cryptpad;
+ envCfg = config.myEnv.tools.cryptpad.immaeEu;
+ domain = "cryptpad.immae.eu";
+ port = envCfg.port;
+ configFile = pkgs.writeText "config.js" ''
+ // ${pkgs.cryptpad}/lib/node_modules/cryptpad/config/config.example.js
+ module.exports = {
+ httpUnsafeOrigin: 'https://${domain}',
+ httpPort: ${toString port},
+ adminEmail: '${envCfg.email}',
+ filePath: './datastore/',
+ archivePath: './data/archive',
+ pinPath: './data/pins',
+ taskPath: './data/tasks',
+ blockPath: './block',
+ blobPath: './blob',
+ blobStagingPath: './data/blobstage',
+ decreePath: './data/decrees',
+ logPath: './data/logs',
+ logToStdout: false,
+ logLevel: 'info',
+ logFeedback: false,
+ verbose: false,
+ inactiveTime: false,
+ maxUploadSize: 100 * 1024 * 1024,
+ adminKeys: ${builtins.toJSON envCfg.admins},
+ };
+ '';
+in
+{
+ options.myServices.websites.tools.cryptpad.enable = lib.mkEnableOption "Enable Cryptpad";
+ config = lib.mkIf cfg.enable {
+ myServices.tools.cryptpad.farm.hosts.immaeEu = {
+ inherit domain port;
+ config = configFile;
+ };
+ services.websites.env.tools.modules = [ "proxy_wstunnel" ];
+ services.websites.env.tools.vhostConfs.cryptpad = {
+ certName = "eldiron";
+ addToCerts = true;
+ hosts = [domain];
+ root = config.myServices.tools.cryptpad.farm.vhostRoots.immaeEu;
+ extraConfig = [
+ config.myServices.tools.cryptpad.farm.vhosts.immaeEu
+ ];
+ };
+ };
+}
--- /dev/null
+{ pkgs, config, lib, ... }:
+let
+ cfg = config.myServices.tools.cryptpad.farm;
+ toService = name:
+ let
+ inherit (cfg.hosts.${name}) package config;
+ in {
+ description = "Cryptpad ${name} Service";
+ wantedBy = [ "multi-user.target" ];
+ after = [ "networking.target" ];
+ serviceConfig = {
+ User = "cryptpad";
+ Group = "cryptpad";
+ Environment = [
+ "CRYPTPAD_CONFIG=${config}"
+ "HOME=%S/cryptpad/${name}"
+ ];
+ ExecStart = "${package}/bin/cryptpad";
+ PrivateTmp = true;
+ Restart = "always";
+ StateDirectory = "cryptpad/${name}";
+ WorkingDirectory = "%S/cryptpad/${name}";
+ };
+ };
+ toVhostRoot = name: "${cfg.hosts.${name}.package}/lib/node_modules/cryptpad";
+ toVhost = name:
+ let
+ inherit (cfg.hosts.${name}) package domain port;
+ api_domain = domain;
+ files_domain = domain;
+ in ''
+ RewriteEngine On
+
+ Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
+ Header set X-XSS-Protection "1; mode=block"
+ Header set X-Content-Type-Options "nosniff"
+ Header set Access-Control-Allow-Origin "*"
+ Header set Permissions-Policy "interest-cohort=()"
+
+ Header set Cross-Origin-Resource-Policy "cross-origin"
+ <If "%{REQUEST_URI} =~ m#^/(sheet|presentation|doc)/.*$#">
+ Header set Cross-Origin-Opener-Policy "same-origin"
+ </If>
+ Header set Cross-Origin-Embedder-Policy "require-corp"
+
+ ErrorDocument 404 /customize.dist/404.html
+
+ <If "%{QUERY_STRING} =~ m#ver=.*?#">
+ Header set Cache-Control "max-age=31536000"
+ </If>
+ <If "%{REQUEST_URI} =~ m#^/.*(\/|\.html)$#">
+ Header set Cache-Control "no-cache"
+ </If>
+
+ SetEnv styleSrc "'unsafe-inline' 'self' ${domain}"
+ SetEnv connectSrc "'self' https://${domain} ${domain} https://${api_domain} blob: wss://${api_domain} ${api_domain} ${files_domain}"
+ SetEnv fontSrc "'self' data: ${domain}"
+ SetEnv imgSrc "'self' data: * blob: ${domain}"
+ SetEnv frameSrc "'self' blob:"
+ SetEnv mediaSrc "'self' data: * blob: ${domain}"
+ SetEnv childSrc "https://${domain}"
+ SetEnv workerSrc "https://${domain}"
+ SetEnv scriptSrc "'self' 'unsafe-eval' 'unsafe-inline' resource: ${domain}"
+
+ Header set Content-Security-Policy "default-src 'none'; child-src %{childSrc}e; worker-src %{workerSrc}e; media-src %{mediaSrc}e; style-src %{styleSrc}e; script-src %{scriptSrc}e; connect-src %{connectSrc}e; font-src %{fontSrc}e; img-src %{imgSrc}e; frame-src %{frameSrc}e;"
+
+ RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
+ RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]
+ RewriteRule .* ws://localhost:${toString port}%{REQUEST_URI} [P,NE,QSA,L]
+
+ RewriteRule ^/customize/(.*)$ /customize.dist/$1 [L]
+
+ ProxyPassMatch "^/(api/(config|broadcast).*)$" "http://localhost:${toString port}/$1"
+ ProxyPassReverse /api http://localhost:${toString port}/api
+ ProxyPreserveHost On
+ RequestHeader set X-Real-IP %{REMOTE_ADDR}s
+
+ Alias /blob /var/lib/cryptpad/${name}/blob
+ <Directory /var/lib/cryptpad/${name}/blob>
+ Require all granted
+ AllowOverride None
+ </Directory>
+ Alias /block /var/lib/cryptpad/${name}/block
+ <Directory /var/lib/cryptpad/${name}/block>
+ Require all granted
+ AllowOverride None
+ </Directory>
+ <LocationMatch /blob/>
+ Header set Cache-Control "max-age=31536000"
+ Header set Access-Control-Allow-Origin "*"
+ Header set Access-Control-Allow-Methods "GET, POST, OPTIONS"
+ Header set Access-Control-Allow-Headers "DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range,Content-Length"
+ Header set Access-Control-Expose-Headers "DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range,Content-Length"
+
+ RewriteCond %{REQUEST_METHOD} OPTIONS
+ RewriteRule ^(.*)$ $1 [R=204,L]
+ </LocationMatch>
+
+ <LocationMatch /block/>
+ Header set Cache-Control "max-age=0"
+ </locationMatch>
+
+ RewriteRule ^/(register|login|settings|user|pad|drive|poll|slide|code|whiteboard|file|media|profile|contacts|todo|filepicker|debug|kanban|sheet|support|admin|notifications|teams|calendar|presentation|doc)$ $1/ [R=302,L]
+
+ RewriteCond %{DOCUMENT_ROOT}/www/%{REQUEST_URI} -f
+ RewriteRule (.*) /www/$1 [L]
+
+ RewriteCond %{DOCUMENT_ROOT}/www/%{REQUEST_URI}/index.html -f
+ RewriteRule (.*) /www/$1/index.html [L]
+
+ RewriteCond %{DOCUMENT_ROOT}/customize.dist/%{REQUEST_URI} -f
+ RewriteRule (.*) /customize.dist/$1 [L]
+
+ <Directory ${package}/lib/node_modules/cryptpad/www>
+ AllowOverride None
+ Require all granted
+ DirectoryIndex index.html
+ </Directory>
+ <Directory ${package}/lib/node_modules/cryptpad/customize.dist>
+ AllowOverride None
+ Require all granted
+ DirectoryIndex index.html
+ </Directory>
+ '';
+in
+{
+ options.myServices.tools.cryptpad.farm = {
+ hosts = lib.mkOption {
+ default = {};
+ description = "Hosts to install";
+ type = lib.types.attrsOf (lib.types.submodule {
+ options = {
+ port = lib.mkOption {
+ type = lib.types.port;
+ };
+ package = lib.mkOption {
+ type = lib.types.package;
+ description = "Cryptpad package to use";
+ default = pkgs.cryptpad;
+ };
+ domain = lib.mkOption {
+ type = lib.types.str;
+ description = "Domain for main host";
+ };
+ config = lib.mkOption {
+ type = lib.types.path;
+ description = "Path to configuration";
+ };
+ };
+ });
+ };
+ vhosts = lib.mkOption {
+ description = "Instance vhosts configs";
+ readOnly = true;
+ type = lib.types.attrsOf lib.types.str;
+ default = lib.genAttrs (builtins.attrNames cfg.hosts) toVhost;
+ };
+ vhostRoots = lib.mkOption {
+ description = "Instance vhosts document roots";
+ readOnly = true;
+ type = lib.types.attrsOf lib.types.path;
+ default = lib.genAttrs (builtins.attrNames cfg.hosts) toVhostRoot;
+ };
+ };
+ config = {
+ users.users = lib.optionalAttrs (cfg.hosts != {}) {
+ cryptpad = {
+ uid = config.ids.uids.cryptpad;
+ group = "cryptpad";
+ description = "Cryptpad user";
+ };
+ };
+ users.groups = lib.optionalAttrs (cfg.hosts != {}) {
+ cryptpad = {
+ gid = config.ids.gids.cryptpad;
+ };
+ };
+ systemd.services = lib.listToAttrs (map (n: lib.nameValuePair "cryptpad-${n}" (toService n)) (builtins.attrNames cfg.hosts));
+ };
+}
-Subproject commit dc2397900948d968bd5e1a32447d486edc626c4c
+Subproject commit 3bdfad457df0e47a409f1cf183e515b7a9836838