summaryrefslogtreecommitdiff
path: root/tw/services/restic.scm
blob: 424a3a3568896f843f4c78a4f3af6646702b9db6 (about) (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
(define-module (tw services restic)
  #:use-module (gnu)
  #:use-module ((gnu packages admin)
                #:select (shadow))
  #:use-module (gnu services)
  #:use-module (gnu services configuration)
  #:use-module (gnu services shepherd)
  #:use-module (guix gexp)
  #:use-module (guix packages)
  #:use-module (tw packages restic)
  #:export (restic-server-service-type
            restic-server-configuration))

(define-maybe/no-serialization integer)
(define-maybe/no-serialization string)

;; TODO: implement --tls, --tls-cert and --tls-key, maybe using certbot-service-type?
;; TODO: implement --log
(define-configuration/no-serialization restic-server-configuration
  (repository-path (string "/var/lib/restic") "The directory containing
restic's repositories and @code{.htpasswd} file, unless otherwise configured
using @code{htpasswd-file}.")
  (restic-server (package restic-rest-server) "The restic REST server package to use.")
  (bind-address (string ":8000") "The listen address (including port) to bind to.")
  (htpasswd-file (maybe-string %unset-value) "Location of @code{.htpasswd}
file (default: @code{REPOSITORY-PATH/.htpasswd}).  Use @code{htpasswd} from
the @code{httpd} package to create and/or update this file.")
  (auth? (boolean #t) "Whether to authenticate users at all (using .htpasswd).")
  (verify-upload? (boolean #t) "Whether to verify the integrity of uploaded
data.  @emph{Do not disable} unless the restic server is to be run on a very
low-power device.")
  (append-only? (boolean #f) "Whether to run the restic server in append-only mode.")
  (max-repository-size (maybe-integer %unset-value) "Maximum repository size
in bytes, if any.")
  (private-repos-only? (boolean #f) "Whether to let users only access their
private restic repos.")
  (prometheus? (boolean #f) "Whether to serve Prometheus metrics.")
  (prometheus-auth? (boolean #t) "Whether to require authentication as the
@code{metrics} user to access the Prometheus /metrics endpoint."))

(define (restic-server-arguments config)
  "Turn CONFIG into a list of arguments to the restic-rest-server executable."
  `("--path" ,(restic-server-configuration-repository-path config)
    "--listen" ,(restic-server-configuration-bind-address config)
    ,@(let ((htpasswd-file (restic-server-configuration-htpasswd-file config)))
        (if (string? htpasswd-file) `("--htpasswd-file" ,htpasswd-file) '()))
    ,@(if (restic-server-configuration-auth? config) '() '("--no-auth"))
    ,@(if (restic-server-configuration-verify-upload? config) '() '("--no-verify-upload"))
    ,@(if (restic-server-configuration-append-only? config) '("--append-only") '())
    ,@(let ((max-size (restic-server-configuration-max-repository-size config)))
        (if (integer? max-size) `("--max-size" ,max-size) '()))
    ,@(if (restic-server-configuration-private-repos-only? config) '("--private-repos") '())
    ,@(if (restic-server-configuration-prometheus? config) '("--prometheus") '())
    ,@(if (restic-server-configuration-prometheus-auth? config) '() '("--prometheus-no-auth"))))

(define (restic-server-service config)
  "Create a `shepherd-service' for the restic REST server from CONFIG."
  (list (shepherd-service
         (provision '(restic-server))
         (requirement '(networking))
         (documentation "Run the Restic REST server to serve backup repositories via HTTP.")
         (start #~(make-forkexec-constructor
                   (list #$(file-append (restic-server-configuration-restic-server config)
                                        "/bin/restic-rest-server")
                         #$@(restic-server-arguments config))
                   #:user "restic" #:group "restic"))
         (stop #~(make-kill-destructor)))))

(define (restic-server-accounts config)
  "Create user accounts and groups for the restic REST server defined in CONFIG."
  (list (user-account
         (name "restic")
         (group "restic")
         (comment "Restic server user")
         (system? #t)
         (home-directory (restic-server-configuration-repository-path config))
         (shell (file-append shadow "/sbin/nologin")))
        (user-group
         (name "restic")
         (system? #t))))

(define restic-server-service-type
  (service-type
   (name 'restic-server)
   (extensions
    (list (service-extension shepherd-root-service-type restic-server-service)
          (service-extension account-service-type restic-server-accounts)))
   (description
    "Restic REST server, running as a service user instead of root.")))