nix

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

commit e8a377b93f599ae55bce87f5a20cf248328ade7d
parent b1ae195bc988f1ed3fe62226f1356a2bb73f40d2
Author: mtmn <miro@haravara.org>
Date:   Tue,  7 Jul 2026 21:43:00 +0200

nix: add etherpad module

Diffstat:
Mhosts/nixaran/configuration.nix | 0
Amodules/services/etherpad.nix | 172+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msecrets.nix | 2++
Asecrets/etherpad-admin-password.age | 0
Asecrets/etherpad-user-password.age | 0
5 files changed, 174 insertions(+), 0 deletions(-)

diff --git a/hosts/nixaran/configuration.nix b/hosts/nixaran/configuration.nix Binary files differ. diff --git a/modules/services/etherpad.nix b/modules/services/etherpad.nix @@ -0,0 +1,172 @@ +{ + config, + lib, + pkgs, + haravara, + ... +}: let + cfg = config.services.haravara.etherpad; + stateDir = "/var/lib/etherpad"; +in { + options.services.haravara.etherpad = { + enable = lib.mkEnableOption "Etherpad collaborative editor"; + + domain = lib.mkOption { + type = lib.types.str; + description = "Public domain for the Etherpad instance"; + }; + + port = lib.mkOption { + type = lib.types.port; + default = 9090; + description = "Local TCP port for Etherpad to listen on"; + }; + + image = lib.mkOption { + type = lib.types.str; + default = "etherpad/etherpad@sha256:044e5b58686f22e2c8b792ed0a7c35a83986458e1ee91f12119276c1e2572bce"; + description = "OCI image reference (pinned by digest) for Etherpad"; + }; + + title = lib.mkOption { + type = lib.types.str; + default = "Etherpad"; + description = "Title shown in the Etherpad UI"; + }; + + adminPasswordFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; + default = null; + description = "Path to a file containing the admin user password. If null, no admin user is created."; + }; + + userPasswordFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; + default = null; + description = "Path to a file containing the shared non-admin user password. If null, no user account is created."; + }; + + dbType = lib.mkOption { + type = lib.types.str; + default = "sqlite"; + description = "UeberDB database driver (e.g. dirty, sqlite, postgres, mysql)"; + }; + + dbFilename = lib.mkOption { + type = lib.types.str; + default = "etherpad.sqlite3"; + description = "Database filename when dbType is sqlite or dirty, relative to the state directory"; + }; + + extraEnvironment = lib.mkOption { + type = lib.types.attrsOf lib.types.str; + default = {}; + description = "Additional environment variables passed to the Etherpad container"; + }; + + authLabel = haravara.authLabelOption; + }; + + config = lib.mkIf cfg.enable { + # The Etherpad container image runs as UID 5001 (user "etherpad", group 0). + # Match that ownership on the host bind-mount so the process can read/write. + systemd = { + tmpfiles.rules = [ + "d ${stateDir} 0750 5001 0 -" + ]; + + services.etherpad-init-state = { + description = "Ensure Etherpad state directory ownership"; + before = ["podman-etherpad.service"]; + requiredBy = ["podman-etherpad.service"]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + User = "root"; + Group = "root"; + ExecStart = pkgs.writeShellScript "etherpad-init-state" '' + set -euo pipefail + install -d -m 0750 -o 5001 -g 0 ${stateDir} + ''; + }; + }; + }; + + virtualisation.oci-containers = { + backend = "podman"; + + containers.etherpad = { + inherit (cfg) image; + autoStart = true; + ports = ["127.0.0.1:${toString cfg.port}:9001"]; + volumes = [ + "${stateDir}:/opt/etherpad-lite/var:Z" + ]; + environment = + { + TITLE = cfg.title; + PORT = "9001"; + IP = "0.0.0.0"; + TRUST_PROXY = "true"; + DB_TYPE = cfg.dbType; + DB_FILENAME = "/opt/etherpad-lite/var/${cfg.dbFilename}"; + LOGLEVEL = "INFO"; + DISABLE_IP_LOGGING = "true"; + SHOW_SETTINGS_IN_ADMIN_PAGE = "false"; + SKIN_NAME = "colibris"; + SKIN_VARIANTS = "super-light-toolbar super-light-editor light-background"; + 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!"; + SHOW_RECENT_PADS = "false"; + REQUIRE_AUTHENTICATION = "true"; + REQUIRE_AUTHORIZATION = "false"; + EDIT_ONLY = "true"; + AUTHENTICATION_METHOD = "apikey"; + } + // cfg.extraEnvironment; + environmentFiles = lib.optionals (cfg.adminPasswordFile != null || cfg.userPasswordFile != null) [ + "/run/etherpad-admin-password.env" + ]; + }; + }; + + systemd.services = { + etherpad-init-password = lib.mkIf (cfg.adminPasswordFile != null || cfg.userPasswordFile != null) { + description = "Prepare Etherpad password environment file"; + before = ["podman-etherpad.service"]; + requiredBy = ["podman-etherpad.service"]; + unitConfig = {}; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + User = "root"; + Group = "root"; + PrivateTmp = true; + UMask = "0077"; + ExecStart = pkgs.writeShellScript "etherpad-init-password" '' + set -euo pipefail + : > /run/etherpad-admin-password.env + ${lib.optionalString (cfg.adminPasswordFile != null) '' + pass="$(cat ${lib.escapeShellArg cfg.adminPasswordFile})" + printf 'ADMIN_PASSWORD=%s\n' "$pass" >> /run/etherpad-admin-password.env + ''} + ${lib.optionalString (cfg.userPasswordFile != null) '' + pass="$(cat ${lib.escapeShellArg cfg.userPasswordFile})" + printf 'USER_PASSWORD=%s\n' "$pass" >> /run/etherpad-admin-password.env + ''} + chmod 600 /run/etherpad-admin-password.env + ''; + }; + }; + + podman-etherpad = { + after = ["etherpad-init-state.service"]; + requires = ["etherpad-init-state.service"]; + }; + }; + + services.caddy.virtualHosts."${cfg.domain}".extraConfig = '' + ${haravara.mkAuthImport cfg.authLabel} + reverse_proxy 127.0.0.1:${toString cfg.port} + ''; + }; +} diff --git a/secrets.nix b/secrets.nix @@ -16,4 +16,6 @@ in { "secrets/lastfm-password.age".publicKeys = allKeys; "secrets/corpus.age".publicKeys = allKeys; "secrets/smtp-alerts-password.age".publicKeys = allKeys; + "secrets/etherpad-admin-password.age".publicKeys = allKeys; + "secrets/etherpad-user-password.age".publicKeys = allKeys; } diff --git a/secrets/etherpad-admin-password.age b/secrets/etherpad-admin-password.age Binary files differ. diff --git a/secrets/etherpad-user-password.age b/secrets/etherpad-user-password.age Binary files differ.