aboutsummaryrefslogtreecommitdiff
path: root/tw/services
diff options
context:
space:
mode:
authorTimo Wilken2024-02-25 21:29:43 +0100
committerTimo Wilken2024-02-25 23:36:55 +0100
commit0c6999726c122ad9c3b89b1ed4e674017b1aeec4 (patch)
tree84e3bd881cf49aa8ca87b9159baaa06cd411bd78 /tw/services
parentb412b0e44c540353481762430b946741872e88f4 (diff)
Add Paperless-ngx service
Diffstat (limited to 'tw/services')
-rw-r--r--tw/services/docker.scm10
-rw-r--r--tw/services/paperless.scm117
2 files changed, 124 insertions, 3 deletions
diff --git a/tw/services/docker.scm b/tw/services/docker.scm
index 8361991f..46c7a933 100644
--- a/tw/services/docker.scm
+++ b/tw/services/docker.scm
@@ -61,7 +61,9 @@ following run.")
(docker-args (list-of-strings '()) "Extra command-line arguments to pass to
@code{docker run}.")
(docker-cli (package docker-cli) "The package containing the Docker
-executable to use."))
+executable to use.")
+ (extra-requirements (list-of-symbols '()) "Any Shepherd services on the host
+system that this container relies on."))
(define (docker-container-shepherd-service config)
(match-record config <docker-container-configuration>
@@ -75,7 +77,8 @@ executable to use."))
read-only-root?
remove-after-stop?
docker-args
- docker-cli)
+ docker-cli
+ extra-requirements)
(let ((docker-run-args
`(,@(if read-only-root? '("--read-only") '())
@@ -100,7 +103,8 @@ executable to use."))
(shepherd-service
(provision (list (string->symbol
(string-append "docker-container-" (maybe-value name image)))))
- (requirement `(dockerd ,@(if (string=? network-type "none") '() '(networking))))
+ (requirement `(dockerd ,@(if (string=? network-type "none") '() '(networking))
+ ,@extra-requirements))
(documentation (format #f "Run a Docker container called ~s from the image ~s."
(maybe-value name) image))
(start #~(lambda ()
diff --git a/tw/services/paperless.scm b/tw/services/paperless.scm
new file mode 100644
index 00000000..6db99f65
--- /dev/null
+++ b/tw/services/paperless.scm
@@ -0,0 +1,117 @@
+(define-module (tw services paperless)
+ #:use-module (gnu)
+ #:use-module ((gnu packages admin) #:select (shadow))
+ #:use-module (gnu services)
+ #:use-module (gnu services configuration)
+ #:use-module (gnu services databases)
+ #:use-module (guix records)
+ #:use-module (tw services docker)
+ #:use-module (tw services restic)
+ #:use-module (tw services web)
+ #:export (paperless-service-type
+ paperless-configuration))
+
+(define %paperless-user "paperless")
+(define %paperless-uid 481) ; randomly chosen to avoid collisions
+
+(define-configuration/no-serialization paperless-configuration
+ (container (string "ghcr.io/paperless-ngx/paperless-ngx:2.5") "Container image to run.")
+ (domain (string "localhost") "The external domain which will resolve to this
+Grafana instance.")
+ (bind-address (string "127.0.0.1") "The host IP to bind to.")
+ (data-path (string "/var/lib/paperless") "The path to store data in, on the host.")
+ (secret-key-file string "A file name containing a @code{PAPERLESS_SECRET_KEY=...}
+ assignment. This is used to create session tokens, and must be changed from
+the default. Make sure this file is readable only by the root user."))
+
+(define (paperless-accounts config)
+ (list (user-account
+ (name %paperless-user)
+ (uid %paperless-uid)
+ (group %paperless-user)
+ (comment "Paperless server user")
+ (system? #t)
+ (home-directory (paperless-configuration-data-path config))
+ (shell (file-append shadow "/sbin/nologin")))
+ (user-group
+ (name %paperless-user)
+ (id %paperless-uid)
+ (system? #t))))
+
+(define (paperless-environment config)
+ (match-record config <paperless-configuration> (domain bind-address)
+ (plain-file "paperless.env" (string-append "\
+PAPERLESS_BIND_ADDR=" bind-address "
+PAPERLESS_URL=https://" domain "
+PAPERLESS_OCR_LANGUAGES=eng deu fra por
+PAPERLESS_TIME_ZONE=Europe/Berlin
+PAPERLESS_UID=" (number->string %paperless-uid) "
+PAPERLESS_GID=" (number->string %paperless-uid) "
+"))))
+
+(define (paperless-docker-service config)
+ (match-record config <paperless-configuration> (container data-path secret-key-file)
+ (list (docker-container-configuration
+ (name "paperless")
+ (image container)
+ (read-only-root? #f) ; wrapper script runs "apt" in container
+ (volumes
+ ;; We need to mount each subdir separately because the container
+ ;; image specifies volumes to be mounted there otherwise.
+ (map (lambda (subdir)
+ (list (string-append data-path "/" subdir)
+ (string-append "/usr/src/paperless/" subdir)
+ #t))
+ '("consume" "data" "export" "media")))
+ (environment-files
+ (list (paperless-environment config) secret-key-file))
+ (network-type "host")
+ ;; Paperless connects to redis://localhost:6379 (default port) by default.
+ (extra-requirements '(redis))))))
+
+(define (paperless-reverse-proxy config)
+ (match-record config <paperless-configuration> (domain bind-address)
+ (if (string=? domain "localhost") (list)
+ (list (https-reverse-proxy-configuration
+ (domains (list domain))
+ ;; The container runs on port 8000 and has a health check with
+ ;; that port hardcoded, so just use that.
+ (destination-port 8000)
+ (destination-ip
+ (if (string=? bind-address "0.0.0.0")
+ "127.0.0.1"
+ bind-address)))))))
+
+(define %paperless-backup-repo
+ (restic-local-repository (path "/var/backups/paperless")))
+(define %paperless-backup-password
+ (restic-password-source
+ (type 'file)
+ (name "/etc/restic/lud-paperless")))
+
+(define (paperless-backups config)
+ (match-record config <paperless-configuration> (data-path)
+ (list (restic-scheduled-backup
+ (schedule #~"0 5 * * *")
+ (paths (list data-path))
+ (repo %paperless-backup-repo)
+ (password %paperless-backup-password)))))
+
+(define (paperless-backup-cleanup config)
+ (list (restic-scheduled-cleanup
+ (schedule #~"0 12 * * *")
+ (repo %paperless-backup-repo)
+ (password %paperless-backup-password)
+ (keep-daily 30)
+ (keep-monthly -1))))
+
+(define paperless-service-type
+ (service-type
+ (name 'paperless)
+ (extensions
+ (list (service-extension docker-container-service-type paperless-docker-service)
+ (service-extension account-service-type paperless-accounts)
+ (service-extension https-reverse-proxy-service-type paperless-reverse-proxy)
+ (service-extension restic-backup-service-type paperless-backups)
+ (service-extension restic-cleanup-service-type paperless-backup-cleanup)))
+ (description "Paperless server, running under Docker.")))