{ flake, lib, config, pkgs, ... }: with lib; let psCfg = config.pub-solar; xdg = config.home-manager.users."${psCfg.user.name}".xdg; dataDir = "/var/lib/paperless"; backupDir = "/var/lib/PaperlessBackup"; consumptionDir = "/var/lib/scandir"; scan2paperless = with pkgs; writeShellScriptBin "scan2paperless" '' DEVICE=$1 NUM_PAGES=$2 NAME=$3 if [ -z "''${DEVICE}" ] || [ -z "''${NUM_PAGES}" ] || [ -z "''${NAME}" ]; then echo "Usage: scan2paperless " exit 1 fi tmpDir=$(${coreutils}/bin/mktemp -d) files=() for i in $(seq 1 $NUM_PAGES); do fileName=$(${openssl}/bin/openssl rand -hex 12) file="$tmpDir/$fileName.jpg" echo "Start scanning page $i/$NUM_PAGES"; ${sane-backends}/bin/scanimage -d $DEVICE --format=jpeg --resolution 300 --progress -o $file echo "Finished scanning page $i"; files+=($file) done pdf="${consumptionDir}/$NAME.pdf" ${python3Packages.img2pdf}/bin/img2pdf --output $pdf ''${files[@]} echo "PDF written to $pdf" ''; in { age.secrets."paperless.env" = { file = "${flake.self}/secrets/paperless.env.age"; mode = "400"; owner = "paperless"; }; ################################# # Paperless service and proxy ################################# security.acme.certs = { "paperless.b12f.io" = {}; }; services.nginx.virtualHosts = { "paperless.b12f.io" = { forceSSL = true; useACMEHost = "paperless.b12f.io"; extraConfig = "include /etc/nginx/conf-available/authelia-location.conf;"; locations."/".proxyPass = "http://127.0.0.1:${builtins.toString config.services.paperless.port}"; locations."/".extraConfig = '' include /etc/nginx/conf-available/proxy.conf; include /etc/nginx/conf-available/authelia-authrequest.conf; ''; }; }; services.paperless = { enable = true; consumptionDir = consumptionDir; dataDir = dataDir; address = "127.0.0.1"; settings = { PAPERLESS_OCR_LANGUAGE = "nld+deu"; PAPERLESS_URL = "https://paperless.b12f.io"; PAPERLESS_DISABLE_REGULAR_LOGIN = "True"; PAPERLESS_ENABLE_HTTP_REMOTE_USER = "True"; PAPERLESS_EMAIL_TASK_CRON = "*/2 * * * *"; }; }; systemd.services.paperless-web.serviceConfig.EnvironmentFile = [ config.age.secrets."paperless.env".path ]; ################################# # Scanning ################################# hardware.sane = { enable = true; extraBackends = [pkgs.hplipWithPlugin]; }; users.users."${psCfg.user.name}".packages = with pkgs; [ scan2paperless sane-backends ]; home-manager.users."${psCfg.user.name}" = { home.sessionVariables = { SCANNER_OUTPUT_DIR = consumptionDir; }; systemd.user.sessionVariables = { SCANNER_OUTPUT_DIR = consumptionDir; }; }; ################################# # hosting.de invoice fetch ################################# age.secrets."hosting-de-invoice-sync-api-key" = { file = "${flake.self}/secrets/hosting-de-invoice-sync-api-key.age"; mode = "400"; owner = "paperless"; }; services.cron = { enable = true; systemCronJobs = [ "30 1 * * * paperless ${pkgs.fetch-hostingde-invoices}/bin/fetch-hostingde-invoices '${config.age.secrets."hosting-de-invoice-sync-api-key".path}' '${consumptionDir}'" ]; }; ################################# # Backups ################################# systemd.tmpfiles.rules = [ "d '${dataDir}' 0700 paperless users - -" "d '${backupDir}' 0700 paperless users - -" "d '${consumptionDir}' 0700 paperless users - -" "d /tmp/paperless 0700 paperless users - -" ]; age.secrets."rclone-pubsolar.conf" = { file = "${flake.self}/secrets/rclone-pubsolar.conf.age"; mode = "400"; }; age.secrets."restic-password" = { file = "${flake.self}/secrets/restic-password.age"; mode = "400"; }; services.restic.backups = { paperless = { paths = [ backupDir ]; initialize = true; passwordFile = config.age.secrets."restic-password".path; # See https://www.hosting.de/blog/verschluesselte-backups-mit-rclone-und-restic-in-nextcloud/ repository = "rclone:cloud.pub.solar:/backups/Paperless"; backupPrepareCommand = "${dataDir}/paperless-manage document_exporter ${backupDir} -c -p"; rcloneConfigFile = config.age.secrets."rclone-pubsolar.conf".path; }; }; }