mirror of
https://github.com/NixOS/nixpkgs.git
synced 2025-07-13 21:50:33 +03:00
nixos/cryptpad: init
This is a full rewrite independent of the previously removed cryptpad module, managing cryptpad's config in RFC0042 along with a shiny test. Upstream cryptpad provides two nginx configs, with many optimizations and complex settings; this uses the easier variant for now but improvements (e.g. serving blocks and js files directly through nginx) should be possible with a bit of work and care about http headers. the /checkup page of cryptpad passes all tests except HSTS, we don't seem to have any nginx config with HSTS enabled in nixpkgs so leave this as is for now. Co-authored-by: Pol Dellaiera <pol.dellaiera@protonmail.com> Co-authored-by: Michael Smith <shmitty@protonmail.com>
This commit is contained in:
parent
5f020a4166
commit
b846e8762f
6 changed files with 287 additions and 1 deletions
215
nixos/modules/services/web-apps/cryptpad.nix
Normal file
215
nixos/modules/services/web-apps/cryptpad.nix
Normal file
|
@ -0,0 +1,215 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
cfg = config.services.cryptpad;
|
||||
|
||||
inherit (lib)
|
||||
mkIf
|
||||
mkMerge
|
||||
mkOption
|
||||
strings
|
||||
types
|
||||
;
|
||||
|
||||
# The Cryptpad configuration file isn't JSON, but a JavaScript source file that assigns a JSON value
|
||||
# to a variable.
|
||||
cryptpadConfigFile = builtins.toFile "cryptpad_config.js" ''
|
||||
module.exports = ${builtins.toJSON cfg.settings}
|
||||
'';
|
||||
|
||||
# Derive domain names for Nginx configuration from Cryptpad configuration
|
||||
mainDomain = strings.removePrefix "https://" cfg.settings.httpUnsafeOrigin;
|
||||
sandboxDomain =
|
||||
if cfg.settings.httpSafeOrigin == null then
|
||||
mainDomain
|
||||
else
|
||||
strings.removePrefix "https://" cfg.settings.httpSafeOrigin;
|
||||
|
||||
in
|
||||
{
|
||||
options.services.cryptpad = {
|
||||
enable = lib.mkEnableOption "cryptpad";
|
||||
|
||||
package = lib.mkPackageOption pkgs "cryptpad" { };
|
||||
|
||||
configureNginx = mkOption {
|
||||
description = ''
|
||||
Configure Nginx as a reverse proxy for Cryptpad.
|
||||
Note that this makes some assumptions on your setup, and sets settings that will
|
||||
affect other virtualHosts running on your Nginx instance, if any.
|
||||
Alternatively you can configure a reverse-proxy of your choice.
|
||||
'';
|
||||
type = types.bool;
|
||||
default = false;
|
||||
};
|
||||
|
||||
settings = mkOption {
|
||||
description = ''
|
||||
Cryptpad configuration settings.
|
||||
See https://github.com/cryptpad/cryptpad/blob/main/config/config.example.js for a more extensive
|
||||
reference documentation.
|
||||
Test your deployed instance through `https://<domain>/checkup/`.
|
||||
'';
|
||||
type = types.submodule {
|
||||
freeformType = (pkgs.formats.json { }).type;
|
||||
options = {
|
||||
httpUnsafeOrigin = mkOption {
|
||||
type = types.str;
|
||||
example = "https://cryptpad.example.com";
|
||||
default = "";
|
||||
description = "This is the URL that users will enter to load your instance";
|
||||
};
|
||||
httpSafeOrigin = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
example = "https://cryptpad-ui.example.com. Apparently optional but recommended.";
|
||||
description = "Cryptpad sandbox URL";
|
||||
};
|
||||
httpAddress = mkOption {
|
||||
type = types.str;
|
||||
default = "127.0.0.1";
|
||||
description = "Address on which the Node.js server should listen";
|
||||
};
|
||||
httpPort = mkOption {
|
||||
type = types.int;
|
||||
default = 3000;
|
||||
description = "Port on which the Node.js server should listen";
|
||||
};
|
||||
websocketPort = mkOption {
|
||||
type = types.int;
|
||||
default = 3003;
|
||||
description = "Port for the websocket that needs to be separate";
|
||||
};
|
||||
maxWorkers = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = "Number of child processes, defaults to number of cores available";
|
||||
};
|
||||
adminKeys = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [ ];
|
||||
description = "List of public signing keys of users that can access the admin panel";
|
||||
example = [ "[cryptpad-user1@my.awesome.website/YZgXQxKR0Rcb6r6CmxHPdAGLVludrAF2lEnkbx1vVOo=]" ];
|
||||
};
|
||||
logToStdout = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Controls whether log output should go to stdout of the systemd service";
|
||||
};
|
||||
logLevel = mkOption {
|
||||
type = types.str;
|
||||
default = "info";
|
||||
description = "Controls log level";
|
||||
};
|
||||
blockDailyCheck = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Disable telemetry. This setting is only effective if the 'Disable server telemetry'
|
||||
setting in the admin menu has been untouched, and will be ignored by cryptpad once
|
||||
that option is set either way.
|
||||
Note that due to the service confinement, just enabling the option in the admin
|
||||
menu will not be able to resolve DNS and fail; this setting must be set as well.
|
||||
'';
|
||||
};
|
||||
installMethod = mkOption {
|
||||
type = types.str;
|
||||
default = "nixos";
|
||||
description = ''
|
||||
Install method is listed in telemetry if you agree to it through the consentToContact
|
||||
setting in the admin panel.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable (mkMerge [
|
||||
{
|
||||
systemd.services.cryptpad = {
|
||||
description = "Cryptpad service";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "networking.target" ];
|
||||
serviceConfig = {
|
||||
BindReadOnlyPaths = [
|
||||
cryptpadConfigFile
|
||||
# apparently needs proc for workers management
|
||||
"/proc"
|
||||
"/dev/urandom"
|
||||
] ++ (if ! cfg.settings.blockDailyCheck then [
|
||||
# allow DNS & TLS if telemetry is explicitly enabled
|
||||
"-/etc/resolv.conf"
|
||||
"-/run/systemd"
|
||||
"/etc/hosts"
|
||||
"/etc/ssl/certs/ca-certificates.crt"
|
||||
] else []);
|
||||
DynamicUser = true;
|
||||
Environment = [
|
||||
"CRYPTPAD_CONFIG=${cryptpadConfigFile}"
|
||||
"HOME=%S/cryptpad"
|
||||
];
|
||||
ExecStart = lib.getExe cfg.package;
|
||||
PrivateTmp = true;
|
||||
Restart = "always";
|
||||
StateDirectory = "cryptpad";
|
||||
WorkingDirectory = "%S/cryptpad";
|
||||
};
|
||||
confinement = {
|
||||
enable = true;
|
||||
binSh = null;
|
||||
mode = "chroot-only";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
(mkIf cfg.configureNginx {
|
||||
assertions = [
|
||||
{
|
||||
assertion = cfg.settings.httpUnsafeOrigin != "";
|
||||
message = "services.cryptpad.settings.httpUnsafeOrigin is required";
|
||||
}
|
||||
{
|
||||
assertion = strings.hasPrefix "https://" cfg.settings.httpUnsafeOrigin;
|
||||
message = "services.cryptpad.settings.httpUnsafeOrigin must start with https://";
|
||||
}
|
||||
{
|
||||
assertion =
|
||||
cfg.settings.httpSafeOrigin == null || strings.hasPrefix "https://" cfg.settings.httpSafeOrigin;
|
||||
message = "services.cryptpad.settings.httpSafeOrigin must start with https:// (or be unset)";
|
||||
}
|
||||
];
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
recommendedTlsSettings = true;
|
||||
recommendedProxySettings = true;
|
||||
recommendedOptimisation = true;
|
||||
recommendedGzipSettings = true;
|
||||
|
||||
virtualHosts = mkMerge [
|
||||
{
|
||||
"${mainDomain}" = {
|
||||
serverAliases = lib.optionals (cfg.settings.httpSafeOrigin != null) [ sandboxDomain ];
|
||||
enableACME = lib.mkDefault true;
|
||||
forceSSL = true;
|
||||
locations."/" = {
|
||||
proxyPass = "http://${cfg.settings.httpAddress}:${builtins.toString cfg.settings.httpPort}";
|
||||
extraConfig = ''
|
||||
client_max_body_size 150m;
|
||||
'';
|
||||
};
|
||||
locations."/cryptpad_websocket" = {
|
||||
proxyPass = "http://${cfg.settings.httpAddress}:${builtins.toString cfg.settings.websocketPort}";
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
})
|
||||
]);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue