From 16a2d980debeb14550e72fd2f2b1637d81abbe9d Mon Sep 17 00:00:00 2001 From: kurogeek Date: Thu, 7 Aug 2025 10:08:14 +0700 Subject: [PATCH] paperless service --- inventories/default.nix | 7 ++ machines/b4l/services/paperless.nix | 67 +++++++++++++++++++ modules/clan/paperless/default.nix | 24 +++++++ modules/clan/paperless/flake-module.nix | 19 ++++++ modules/clan/paperless/tests/vm/default.nix | 38 +++++++++++ .../b4l-paperless/adminpassword/machines/b4l | 1 + .../b4l/b4l-paperless/adminpassword/secret | 19 ++++++ .../adminpassword/users/kurogeek | 1 + .../b4l/b4l-paperless/subdomain/value | 1 + 9 files changed, 177 insertions(+) create mode 100644 machines/b4l/services/paperless.nix create mode 100644 modules/clan/paperless/default.nix create mode 100644 modules/clan/paperless/flake-module.nix create mode 100644 modules/clan/paperless/tests/vm/default.nix create mode 120000 vars/per-machine/b4l/b4l-paperless/adminpassword/machines/b4l create mode 100644 vars/per-machine/b4l/b4l-paperless/adminpassword/secret create mode 120000 vars/per-machine/b4l/b4l-paperless/adminpassword/users/kurogeek create mode 100644 vars/per-machine/b4l/b4l-paperless/subdomain/value diff --git a/inventories/default.nix b/inventories/default.nix index 2bb8cfd..05a65fc 100644 --- a/inventories/default.nix +++ b/inventories/default.nix @@ -83,6 +83,13 @@ }; roles.default.machines.b4l = { }; }; + paperless = { + module = { + name = "paperless"; + input = "self"; + }; + roles.default.machines.b4l = { }; + }; }; }; }; diff --git a/machines/b4l/services/paperless.nix b/machines/b4l/services/paperless.nix new file mode 100644 index 0000000..da8b651 --- /dev/null +++ b/machines/b4l/services/paperless.nix @@ -0,0 +1,67 @@ +{ config, pkgs, ... }: +let + serviceName = "${config.networking.hostName}-paperless"; + domain-name = "${ + config.clan.core.vars.generators."${serviceName}".files.subdomain.value + }.${config.networking.fqdn}"; +in +{ + clan.core.vars.generators."${serviceName}" = { + files = { + subdomain.secret = false; + adminpassword = { + secret = true; + owner = config.services.paperless.user; + group = config.services.paperless.user; + }; + }; + prompts = { + subdomain = { + persist = true; + type = "line"; + description = "Sub-domain for Paperless. Default:(paperless)"; + }; + adminpassword = { + persist = true; + type = "hidden"; + description = "Password for the admin user. Leave empty to auto-generate."; + }; + }; + + runtimeInputs = [ + pkgs.xkcdpass + pkgs.coreutils + ]; + + script = '' + prompt_domain=$(cat "$prompts"/subdomain) + if [[ -n "''${prompt_domain-}" ]]; then + echo $prompt_domain | tr -d "\n" > "$out"/subdomain + else + echo -n "paperless" > "$out"/subdomain + fi + + prompt_password=$(cat "$prompts"/adminpassword) + if [[ -n "''${prompt_password-}" ]]; then + echo "$prompt_password" | tr -d "\n" > "$out"/adminpassword + else + xkcdpass --numwords 4 --delimiter - --count 1 | tr -d "\n" > "$out"/adminpassword + fi + ''; + }; + + environment.systemPackages = [ pkgs.toybox ]; + + services.paperless = { + passwordFile = config.clan.core.vars.generators."${serviceName}".files.adminpassword.path; + }; + + services.nginx.virtualHosts."${domain-name}" = { + forceSSL = true; + useACMEHost = "${config.networking.fqdn}"; + locations."/" = { + proxyPass = "http://localhost:${builtins.toString config.services.paperless.port}"; + }; + }; + +} diff --git a/modules/clan/paperless/default.nix b/modules/clan/paperless/default.nix new file mode 100644 index 0000000..c255ecc --- /dev/null +++ b/modules/clan/paperless/default.nix @@ -0,0 +1,24 @@ +{ ... }: +{ + _class = "clan.service"; + manifest.name = "paperless"; + manifest.description = "A community-supported supercharged document management system: scan, index and archive all your documents"; + manifest.categories = [ "System" ]; + + roles.default = { + + perInstance.nixosModule = + { + lib, + config, + ... + }: + { + services.paperless = { + enable = lib.mkDefault true; + }; + + clan.core.state.paperless.folders = [ config.services.paperless.dataDir ]; + }; + }; +} diff --git a/modules/clan/paperless/flake-module.nix b/modules/clan/paperless/flake-module.nix new file mode 100644 index 0000000..b2ccf77 --- /dev/null +++ b/modules/clan/paperless/flake-module.nix @@ -0,0 +1,19 @@ +{ lib, ... }: +let + module = lib.modules.importApply ./default.nix { }; +in +{ + clan.modules = { + paperless = module; + }; + + perSystem = + { ... }: + { + clan.nixosTests.paperless = { + imports = [ ./tests/vm/default.nix ]; + + clan.modules."@clan/paperless" = module; + }; + }; +} diff --git a/modules/clan/paperless/tests/vm/default.nix b/modules/clan/paperless/tests/vm/default.nix new file mode 100644 index 0000000..8070b2e --- /dev/null +++ b/modules/clan/paperless/tests/vm/default.nix @@ -0,0 +1,38 @@ +{ + ... +}: +{ + name = "service-paperless"; + + clan = { + directory = ./.; + inventory = { + machines.server = { }; + + instances = { + paperless-test = { + module.name = "@clan/paperless"; + module.input = "self"; + roles.default.machines."server".settings = { }; + }; + }; + }; + }; + + nodes = { + server = { + services.paperless = { + }; + }; + }; + + testScript = '' + start_all() + + server.wait_for_unit("paperless-web") + + server.succeed("systemctl status paperless-web") + server.wait_for_open_port(28981) + server.succeed("curl http://127.0.0.1:28981") + ''; +} diff --git a/vars/per-machine/b4l/b4l-paperless/adminpassword/machines/b4l b/vars/per-machine/b4l/b4l-paperless/adminpassword/machines/b4l new file mode 120000 index 0000000..72e1b85 --- /dev/null +++ b/vars/per-machine/b4l/b4l-paperless/adminpassword/machines/b4l @@ -0,0 +1 @@ +../../../../../../sops/machines/b4l \ No newline at end of file diff --git a/vars/per-machine/b4l/b4l-paperless/adminpassword/secret b/vars/per-machine/b4l/b4l-paperless/adminpassword/secret new file mode 100644 index 0000000..5d6d1b0 --- /dev/null +++ b/vars/per-machine/b4l/b4l-paperless/adminpassword/secret @@ -0,0 +1,19 @@ +{ + "data": "ENC[AES256_GCM,data:NsbmiB/AWbAHRotImbG89mQjINxWyCYx5QJExqv9eVpnUg==,iv:VKGzSmYZkKQzG/Fvs3Lk6KBexqKzoVOCk33Lw0ovUjY=,tag:4kWuchFThyRuqIA/tpEL2A==,type:str]", + "sops": { + "age": [ + { + "recipient": "age1hlzrpqqgndcthq5m5yj9egfgyet2fzrxwa6ynjzwx2r22uy6m3hqr3rd06", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAxS3F6cmZQN0V0bXpSbnhJ\nQUVwa2U5cGVVLytJWjdKWnErN0tNNjFhaEJvCjRZMFFSNEdFMlY5Q2J2R0pURUt2\nMkpuWUNrT01waFVGSnhxeEF2VGhPT1kKLS0tIGNpdU4weCtza25kWExHVHJlTThw\ncXBEK2Z6RWs1ZVdjbjdPK051Yk5JVEEKrWBxciIubjp2CfLdSMuSoRaWoFEzh2Ni\nQgsFK4B/1k1nAt7hT6ihRHdaZLRGR3oZljD6obQuZt/CQX4XK/vhpA==\n-----END AGE ENCRYPTED FILE-----\n" + }, + { + "recipient": "age1sg0rvgyetdcqw7j2x983fh69kdkvqsngpe5x36e5920qa7fze3cqhj4wgx", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBmMzN5cTlrdlZhaTNxaUQ4\neHhCQWR5QVBKMEVnclFtQ2dUYzZKTitJWHdJCkFOTXVldjRJSVhmb29MY0RHcEk4\ncGtYMHZUcUIzcE0zVlp6cE0rNUlYMVUKLS0tIFhuckdZb2tFcFNIcm9tQjVyckJm\nZFVleEp4cG1GMUdOT2lhcTNKanZGR0EKwAHiw87p1/k+cOlC7TdM5ba7IrQ5nGSQ\nAWPSFjc3sX86aAQzkY/SBeQulj1tC3i4ryg09xUFg+oSPDXexpGp8g==\n-----END AGE ENCRYPTED FILE-----\n" + } + ], + "lastmodified": "2025-08-06T05:23:42Z", + "mac": "ENC[AES256_GCM,data:eK8RPnR3M4KUGFBtJ43UGq0F4hw+CL1NwoCJbzpX8W8i7pPJOXkIEi0Q4bi3ALMbUxHd5mYE5lKZj0VpPaV3f3t3AvcIg2zWamBYps5R108vwmIDd2UFtmCA496sOSJgpTNX13V8X5cK+3uYXYnd4fz9qAupvFpIpkqWqGl4kxU=,iv:/KOE9y1bzpCzI1jmXZ6mfh0jhVhOvpgS7GNIp2QxvhQ=,tag:e5gLfU+9SyxunVeuOVirhw==,type:str]", + "unencrypted_suffix": "_unencrypted", + "version": "3.10.2" + } +} diff --git a/vars/per-machine/b4l/b4l-paperless/adminpassword/users/kurogeek b/vars/per-machine/b4l/b4l-paperless/adminpassword/users/kurogeek new file mode 120000 index 0000000..970aefa --- /dev/null +++ b/vars/per-machine/b4l/b4l-paperless/adminpassword/users/kurogeek @@ -0,0 +1 @@ +../../../../../../sops/users/kurogeek \ No newline at end of file diff --git a/vars/per-machine/b4l/b4l-paperless/subdomain/value b/vars/per-machine/b4l/b4l-paperless/subdomain/value new file mode 100644 index 0000000..47e3a0c --- /dev/null +++ b/vars/per-machine/b4l/b4l-paperless/subdomain/value @@ -0,0 +1 @@ +paperless \ No newline at end of file