nix

configuration files that power my machines
Log | Files | Refs | README | LICENSE

etherpad.nix (5819B)


      1 {
      2   config,
      3   lib,
      4   pkgs,
      5   haravara,
      6   ...
      7 }: let
      8   cfg = config.services.haravara.etherpad;
      9   stateDir = "/var/lib/etherpad";
     10 in {
     11   options.services.haravara.etherpad = {
     12     enable = lib.mkEnableOption "Etherpad collaborative editor";
     13 
     14     domain = lib.mkOption {
     15       type = lib.types.str;
     16       description = "Public domain for the Etherpad instance";
     17     };
     18 
     19     port = lib.mkOption {
     20       type = lib.types.port;
     21       default = 9090;
     22       description = "Local TCP port for Etherpad to listen on";
     23     };
     24 
     25     image = lib.mkOption {
     26       type = lib.types.str;
     27       default = "etherpad/etherpad@sha256:044e5b58686f22e2c8b792ed0a7c35a83986458e1ee91f12119276c1e2572bce";
     28       description = "OCI image reference (pinned by digest) for Etherpad";
     29     };
     30 
     31     title = lib.mkOption {
     32       type = lib.types.str;
     33       default = "Etherpad";
     34       description = "Title shown in the Etherpad UI";
     35     };
     36 
     37     adminPasswordFile = lib.mkOption {
     38       type = lib.types.nullOr lib.types.path;
     39       default = null;
     40       description = "Path to a file containing the admin user password. If null, no admin user is created.";
     41     };
     42 
     43     userPasswordFile = lib.mkOption {
     44       type = lib.types.nullOr lib.types.path;
     45       default = null;
     46       description = "Path to a file containing the shared non-admin user password. If null, no user account is created.";
     47     };
     48 
     49     dbType = lib.mkOption {
     50       type = lib.types.str;
     51       default = "sqlite";
     52       description = "UeberDB database driver (e.g. dirty, sqlite, postgres, mysql)";
     53     };
     54 
     55     dbFilename = lib.mkOption {
     56       type = lib.types.str;
     57       default = "etherpad.sqlite3";
     58       description = "Database filename when dbType is sqlite or dirty, relative to the state directory";
     59     };
     60 
     61     extraEnvironment = lib.mkOption {
     62       type = lib.types.attrsOf lib.types.str;
     63       default = {};
     64       description = "Additional environment variables passed to the Etherpad container";
     65     };
     66 
     67     authLabel = haravara.authLabelOption;
     68   };
     69 
     70   config = lib.mkIf cfg.enable {
     71     # The Etherpad container image runs as UID 5001 (user "etherpad", group 0).
     72     # Match that ownership on the host bind-mount so the process can read/write.
     73     systemd = {
     74       tmpfiles.rules = [
     75         "d ${stateDir} 0750 5001 0 -"
     76       ];
     77 
     78       services.etherpad-init-state = {
     79         description = "Ensure Etherpad state directory ownership";
     80         before = ["podman-etherpad.service"];
     81         requiredBy = ["podman-etherpad.service"];
     82         serviceConfig = {
     83           Type = "oneshot";
     84           RemainAfterExit = true;
     85           User = "root";
     86           Group = "root";
     87           ExecStart = pkgs.writeShellScript "etherpad-init-state" ''
     88             set -euo pipefail
     89             install -d -m 0750 -o 5001 -g 0 ${stateDir}
     90           '';
     91         };
     92       };
     93     };
     94 
     95     virtualisation.oci-containers = {
     96       backend = "podman";
     97 
     98       containers.etherpad = {
     99         inherit (cfg) image;
    100         autoStart = true;
    101         ports = ["127.0.0.1:${toString cfg.port}:9001"];
    102         volumes = [
    103           "${stateDir}:/opt/etherpad-lite/var:Z"
    104         ];
    105         environment =
    106           {
    107             TITLE = cfg.title;
    108             PORT = "9001";
    109             IP = "0.0.0.0";
    110             TRUST_PROXY = "true";
    111             DB_TYPE = cfg.dbType;
    112             DB_FILENAME = "/opt/etherpad-lite/var/${cfg.dbFilename}";
    113             LOGLEVEL = "INFO";
    114             DISABLE_IP_LOGGING = "true";
    115             SHOW_SETTINGS_IN_ADMIN_PAGE = "false";
    116             SKIN_NAME = "colibris";
    117             SKIN_VARIANTS = "super-light-toolbar super-light-editor light-background";
    118             DEFAULT_PAD_TEXT = "Welcome to Etherpad!\n\nThis pad text is synchronized as you type, so that everyone viewing this page sees the same text. This allows you to collaborate seamlessly on documents!";
    119             SHOW_RECENT_PADS = "false";
    120             REQUIRE_AUTHENTICATION = "true";
    121             REQUIRE_AUTHORIZATION = "false";
    122             EDIT_ONLY = "true";
    123             AUTHENTICATION_METHOD = "apikey";
    124           }
    125           // cfg.extraEnvironment;
    126         environmentFiles = lib.optionals (cfg.adminPasswordFile != null || cfg.userPasswordFile != null) [
    127           "/run/etherpad-admin-password.env"
    128         ];
    129       };
    130     };
    131 
    132     systemd.services = {
    133       etherpad-init-password = lib.mkIf (cfg.adminPasswordFile != null || cfg.userPasswordFile != null) {
    134         description = "Prepare Etherpad password environment file";
    135         before = ["podman-etherpad.service"];
    136         requiredBy = ["podman-etherpad.service"];
    137         unitConfig = {};
    138         serviceConfig = {
    139           Type = "oneshot";
    140           RemainAfterExit = true;
    141           User = "root";
    142           Group = "root";
    143           PrivateTmp = true;
    144           UMask = "0077";
    145           ExecStart = pkgs.writeShellScript "etherpad-init-password" ''
    146             set -euo pipefail
    147             : > /run/etherpad-admin-password.env
    148             ${lib.optionalString (cfg.adminPasswordFile != null) ''
    149               pass="$(cat ${lib.escapeShellArg cfg.adminPasswordFile})"
    150               printf 'ADMIN_PASSWORD=%s\n' "$pass" >> /run/etherpad-admin-password.env
    151             ''}
    152             ${lib.optionalString (cfg.userPasswordFile != null) ''
    153               pass="$(cat ${lib.escapeShellArg cfg.userPasswordFile})"
    154               printf 'USER_PASSWORD=%s\n' "$pass" >> /run/etherpad-admin-password.env
    155             ''}
    156             chmod 600 /run/etherpad-admin-password.env
    157           '';
    158         };
    159       };
    160 
    161       podman-etherpad = {
    162         after = ["etherpad-init-state.service"];
    163         requires = ["etherpad-init-state.service"];
    164       };
    165     };
    166 
    167     services.caddy.virtualHosts."${cfg.domain}".extraConfig = ''
    168       ${haravara.mkAuthImport cfg.authLabel}
    169       reverse_proxy 127.0.0.1:${toString cfg.port}
    170     '';
    171   };
    172 }