gnu: emacs-ebib: Update to 2.39.3.
[jackhill/guix/guix.git] / gnu / services / web.scm
1 ;;; GNU Guix --- Functional package management for GNU
2 ;;; Copyright © 2015 David Thompson <davet@gnu.org>
3 ;;; Copyright © 2015-2022 Ludovic Courtès <ludo@gnu.org>
4 ;;; Copyright © 2016 Nikita <nikita@n0.is>
5 ;;; Copyright © 2016, 2017, 2018 Julien Lepiller <julien@lepiller.eu>
6 ;;; Copyright © 2017, 2018, 2019 Christopher Baines <mail@cbaines.net>
7 ;;; Copyright © 2017 nee <nee-git@hidamari.blue>
8 ;;; Copyright © 2017, 2018 Clément Lassieur <clement@lassieur.org>
9 ;;; Copyright © 2018 Pierre-Antoine Rouby <pierre-antoine.rouby@inria.fr>
10 ;;; Copyright © 2018 Marius Bakke <mbakke@fastmail.com>
11 ;;; Copyright © 2019, 2020 Florian Pelz <pelzflorian@pelzflorian.de>
12 ;;; Copyright © 2020, 2022 Ricardo Wurmus <rekado@elephly.net>
13 ;;; Copyright © 2020 Tobias Geerinckx-Rice <me@tobias.gr>
14 ;;; Copyright © 2020 Arun Isaac <arunisaac@systemreboot.net>
15 ;;; Copyright © 2020 Oleg Pykhalov <go.wigust@gmail.com>
16 ;;; Copyright © 2020, 2021 Alexandru-Sergiu Marton <brown121407@posteo.ro>
17 ;;; Copyright © 2022 Simen Endsjø <simendsjo@gmail.com>
18 ;;;
19 ;;; This file is part of GNU Guix.
20 ;;;
21 ;;; GNU Guix is free software; you can redistribute it and/or modify it
22 ;;; under the terms of the GNU General Public License as published by
23 ;;; the Free Software Foundation; either version 3 of the License, or (at
24 ;;; your option) any later version.
25 ;;;
26 ;;; GNU Guix is distributed in the hope that it will be useful, but
27 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
28 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 ;;; GNU General Public License for more details.
30 ;;;
31 ;;; You should have received a copy of the GNU General Public License
32 ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
33
34 (define-module (gnu services web)
35 #:use-module (gnu services)
36 #:use-module (gnu services shepherd)
37 #:use-module (gnu services admin)
38 #:use-module (gnu services getmail)
39 #:use-module (gnu services mail)
40 #:use-module (gnu system pam)
41 #:use-module (gnu system shadow)
42 #:use-module (gnu packages admin)
43 #:use-module (gnu packages base)
44 #:use-module (gnu packages databases)
45 #:use-module (gnu packages web)
46 #:use-module (gnu packages patchutils)
47 #:use-module (gnu packages php)
48 #:use-module (gnu packages python)
49 #:use-module (gnu packages gnupg)
50 #:use-module (gnu packages guile)
51 #:use-module (gnu packages logging)
52 #:use-module (gnu packages mail)
53 #:use-module (gnu packages rust-apps)
54 #:use-module (guix packages)
55 #:use-module (guix records)
56 #:use-module (guix modules)
57 #:use-module (guix utils)
58 #:use-module (guix gexp)
59 #:use-module ((guix store) #:select (text-file))
60 #:use-module ((guix utils) #:select (version-major))
61 #:use-module ((guix packages) #:select (package-version))
62 #:use-module (srfi srfi-1)
63 #:use-module (srfi srfi-9)
64 #:use-module (ice-9 match)
65 #:use-module (ice-9 format)
66 #:export (httpd-configuration
67 httpd-configuration?
68 httpd-configuration-package
69 httpd-configuration-pid-file
70 httpd-configuration-config
71
72 httpd-virtualhost
73 httpd-virtualhost?
74 httpd-virtualhost-addresses-and-ports
75 httpd-virtualhost-contents
76
77 httpd-config-file
78 httpd-config-file?
79 httpd-config-file-modules
80 httpd-config-file-server-root
81 httpd-config-file-server-name
82 httpd-config-file-listen
83 httpd-config-file-pid-file
84 httpd-config-file-error-log
85 httpd-config-file-user
86 httpd-config-file-group
87
88 httpd-module
89 httpd-module?
90 %default-httpd-modules
91
92 httpd-service-type
93
94 nginx-configuration
95 nginx-configuration?
96 nginx-configuration-nginx
97 nginx-configuration-shepherd-requirement
98 nginx-configuration-log-directory
99 nginx-configuration-run-directory
100 nginx-configuration-server-blocks
101 nginx-configuration-upstream-blocks
102 nginx-configuration-server-names-hash-bucket-size
103 nginx-configuration-server-names-hash-bucket-max-size
104 nginx-configuration-modules
105 nginx-configuration-global-directives
106 nginx-configuration-extra-content
107 nginx-configuration-file
108
109 nginx-server-configuration
110 nginx-server-configuration?
111 nginx-server-configuration-listen
112 nginx-server-configuration-server-name
113 nginx-server-configuration-root
114 nginx-server-configuration-locations
115 nginx-server-configuration-index
116 nginx-server-configuration-ssl-certificate
117 nginx-server-configuration-ssl-certificate-key
118 nginx-server-configuration-server-tokens?
119 nginx-server-configuration-raw-content
120
121 nginx-upstream-configuration
122 nginx-upstream-configuration?
123 nginx-upstream-configuration-name
124 nginx-upstream-configuration-servers
125 nginx-upstream-configuration-extra-content
126
127 nginx-location-configuration
128 nginx-location-configuration?
129 nginx-location-configuration-uri
130 nginx-location-configuration-body
131
132 nginx-named-location-configuration
133 nginx-named-location-configuration?
134 nginx-named-location-configuration-name
135 nginx-named-location-configuration-body
136
137 nginx-service
138 nginx-service-type
139
140 fcgiwrap-configuration
141 fcgiwrap-configuration?
142 fcgiwrap-service-type
143
144 php-fpm-configuration
145 make-php-fpm-configuration
146 php-fpm-configuration?
147 php-fpm-configuration-php
148 php-fpm-configuration-socket
149 php-fpm-configuration-user
150 php-fpm-configuration-group
151 php-fpm-configuration-socket-user
152 php-fpm-configuration-socket-group
153 php-fpm-configuration-pid-file
154 php-fpm-configuration-log-file
155 php-fpm-configuration-process-manager
156 php-fpm-configuration-display-errors
157 php-fpm-configuration-timezone
158 php-fpm-configuration-workers-log-file
159 php-fpm-configuration-file
160 php-fpm-configuration-php-ini-file
161
162 php-fpm-dynamic-process-manager-configuration
163 make-php-fpm-dynamic-process-manager-configuration
164 php-fpm-dynamic-process-manager-configuration?
165 php-fpm-dynamic-process-manager-configuration-max-children
166 php-fpm-dynamic-process-manager-configuration-start-servers
167 php-fpm-dynamic-process-manager-configuration-min-spare-servers
168 php-fpm-dynamic-process-manager-configuration-max-spare-servers
169
170 php-fpm-static-process-manager-configuration
171 make-php-fpm-static-process-manager-configuration
172 php-fpm-static-process-manager-configuration?
173 php-fpm-static-process-manager-configuration-max-children
174
175 php-fpm-on-demand-process-manager-configuration
176 make-php-fpm-on-demand-process-manager-configuration
177 php-fpm-on-demand-process-manager-configuration?
178 php-fpm-on-demand-process-manager-configuration-max-children
179 php-fpm-on-demand-process-manager-configuration-process-idle-timeout
180
181 php-fpm-service-type
182 nginx-php-location
183
184 cat-avatar-generator-service
185
186 hpcguix-web-configuration
187 hpcguix-web-configuration?
188 hpcguix-web-service-type
189
190 tailon-configuration-file
191 tailon-configuration-file?
192 tailon-configuration-file-files
193 tailon-configuration-file-bind
194 tailon-configuration-file-relative-root
195 tailon-configuration-file-allow-transfers?
196 tailon-configuration-file-follow-names?
197 tailon-configuration-file-tail-lines
198 tailon-configuration-file-allowed-commands
199 tailon-configuration-file-debug?
200 tailon-configuration-file-http-auth
201 tailon-configuration-file-users
202
203 tailon-configuration
204 tailon-configuration?
205 tailon-configuration-config-file
206 tailon-configuration-package
207
208 tailon-service-type
209
210 anonip-configuration
211 anonip-configuration?
212 anonip-configuration-anonip
213 anonip-configuration-input
214 anonip-configuration-output
215 anonip-configuration-skip-private?
216 anonip-configuration-column
217 anonip-configuration-replacement
218 anonip-configuration-ipv4mask
219 anonip-configuration-ipv6mask
220 anonip-configuration-increment
221 anonip-configuration-delimiter
222 anonip-configuration-regex
223 anonip-service-type
224
225 varnish-configuration
226 varnish-configuration?
227 varnish-configuration-package
228 varnish-configuration-name
229 varnish-configuration-backend
230 varnish-configuration-vcl
231 varnish-configuration-listen
232 varnish-configuration-storage
233 varnish-configuration-parameters
234 varnish-configuration-extra-options
235
236 varnish-service-type
237
238 patchwork-database-configuration
239 patchwork-database-configuration?
240 patchwork-database-configuration-engine
241 patchwork-database-configuration-name
242 patchwork-database-configuration-user
243 patchwork-database-configuration-password
244 patchwork-database-configuration-host
245 patchwork-database-configuration-port
246
247 patchwork-settings-module
248 patchwork-settings-module?
249 patchwork-settings-module-database-configuration
250 patchwork-settings-module-secret-key
251 patchwork-settings-module-allowed-hosts
252 patchwork-settings-module-default-from-email
253 patchwork-settings-module-static-url
254 patchwork-settings-module-admins
255 patchwork-settings-module-debug?
256 patchwork-settings-module-enable-rest-api?
257 patchwork-settings-module-enable-xmlrpc?
258 patchwork-settings-module-force-https-links?
259 patchwork-settings-module-extra-settings
260
261 patchwork-configuration
262 patchwork-configuration?
263 patchwork-configuration-patchwork
264 patchwork-configuration-settings-module
265 patchwork-configuration-domain
266
267 patchwork-virtualhost
268 patchwork-service-type
269
270 mumi-configuration
271 mumi-configuration?
272 mumi-configuration-mumi
273 mumi-configuration-mailer?
274 mumi-configuration-sender
275 mumi-configuration-smtp
276
277 mumi-service-type
278
279 gmnisrv-configuration
280 gmnisrv-configuration?
281 gmnisrv-configuration-package
282 gmnisrv-configuration-config-file
283
284 gmnisrv-service-type
285
286 agate-configuration
287 agate-configuration?
288 agate-configuration-package
289 agate-configuration-content
290 agate-configuration-cert
291 agate-configuration-key
292 agate-configuration-addr
293 agate-configuration-hostname
294 agate-configuration-lang
295 agate-configuration-silent
296 agate-configuration-serve-secret
297 agate-configuration-log-ip
298 agate-configuration-user
299 agate-configuration-group
300 agate-configuration-log-file
301
302 agate-service-type))
303
304 ;;; Commentary:
305 ;;;
306 ;;; Web services.
307 ;;;
308 ;;; Code:
309
310 (define-record-type* <httpd-module>
311 httpd-module make-httpd-module
312 httpd-module?
313 (name httpd-load-module-name)
314 (file httpd-load-module-file))
315
316 ;; Default modules for the httpd-service-type, taken from etc/httpd/httpd.conf
317 ;; file in the httpd package.
318 (define %default-httpd-modules
319 (map (match-lambda
320 ((name file)
321 (httpd-module
322 (name name)
323 (file file))))
324 '(("authn_file_module" "modules/mod_authn_file.so")
325 ("authn_core_module" "modules/mod_authn_core.so")
326 ("authz_host_module" "modules/mod_authz_host.so")
327 ("authz_groupfile_module" "modules/mod_authz_groupfile.so")
328 ("authz_user_module" "modules/mod_authz_user.so")
329 ("authz_core_module" "modules/mod_authz_core.so")
330 ("access_compat_module" "modules/mod_access_compat.so")
331 ("auth_basic_module" "modules/mod_auth_basic.so")
332 ("reqtimeout_module" "modules/mod_reqtimeout.so")
333 ("filter_module" "modules/mod_filter.so")
334 ("mime_module" "modules/mod_mime.so")
335 ("log_config_module" "modules/mod_log_config.so")
336 ("env_module" "modules/mod_env.so")
337 ("headers_module" "modules/mod_headers.so")
338 ("setenvif_module" "modules/mod_setenvif.so")
339 ("version_module" "modules/mod_version.so")
340 ("unixd_module" "modules/mod_unixd.so")
341 ("status_module" "modules/mod_status.so")
342 ("autoindex_module" "modules/mod_autoindex.so")
343 ("dir_module" "modules/mod_dir.so")
344 ("alias_module" "modules/mod_alias.so"))))
345
346 (define-record-type* <httpd-config-file>
347 httpd-config-file make-httpd-config-file
348 httpd-config-file?
349 (modules httpd-config-file-modules
350 (default %default-httpd-modules))
351 (server-root httpd-config-file-server-root
352 (default httpd))
353 (server-name httpd-config-file-server-name
354 (default #f))
355 (document-root httpd-config-file-document-root
356 (default "/srv/http"))
357 (listen httpd-config-file-listen
358 (default '("80")))
359 (pid-file httpd-config-file-pid-file
360 (default "/var/run/httpd"))
361 (error-log httpd-config-file-error-log
362 (default "/var/log/httpd/error_log"))
363 (user httpd-config-file-user
364 (default "httpd"))
365 (group httpd-config-file-group
366 (default "httpd"))
367 (extra-config httpd-config-file-extra-config
368 (default
369 (list "TypesConfig etc/httpd/mime.types"))))
370
371 (define-gexp-compiler (httpd-config-file-compiler
372 (file <httpd-config-file>) system target)
373 (match file
374 (($ <httpd-config-file> load-modules server-root server-name
375 document-root listen pid-file error-log
376 user group extra-config)
377 (gexp->derivation
378 "httpd.conf"
379 #~(call-with-output-file (ungexp output "out")
380 (lambda (port)
381 (display
382 (string-append
383 (ungexp-splicing
384 `(,@(append-map
385 (match-lambda
386 (($ <httpd-module> name module)
387 `("LoadModule " ,name " " ,module "\n")))
388 load-modules)
389 ,@`("ServerRoot " ,server-root "\n")
390 ,@(if server-name
391 `("ServerName " ,server-name "\n")
392 '())
393 ,@`("DocumentRoot " ,document-root "\n")
394 ,@(append-map
395 (lambda (listen-value)
396 `("Listen " ,listen-value "\n"))
397 listen)
398 ,@(if pid-file
399 `("Pidfile " ,pid-file "\n")
400 '())
401 ,@(if error-log
402 `("ErrorLog " ,error-log "\n")
403 '())
404 ,@(if user
405 `("User " ,user "\n")
406 '())
407 ,@(if group
408 `("Group " ,group "\n")
409 '())
410 "\n\n"
411 ,@extra-config)))
412 port)))
413 #:local-build? #t))))
414
415 (define-record-type <httpd-virtualhost>
416 (httpd-virtualhost addresses-and-ports contents)
417 httpd-virtualhost?
418 (addresses-and-ports httpd-virtualhost-addresses-and-ports)
419 (contents httpd-virtualhost-contents))
420
421 (define-record-type* <httpd-configuration>
422 httpd-configuration make-httpd-configuration
423 httpd-configuration?
424 (package httpd-configuration-package
425 (default httpd))
426 (pid-file httpd-configuration-pid-file
427 (default "/var/run/httpd"))
428 (config httpd-configuration-config
429 (default (httpd-config-file))))
430
431 (define %httpd-accounts
432 (list (user-group (name "httpd") (system? #t))
433 (user-account
434 (name "httpd")
435 (group "httpd")
436 (system? #t)
437 (comment "Apache HTTPD server user")
438 (home-directory "/var/empty")
439 (shell (file-append shadow "/sbin/nologin")))))
440
441 (define httpd-shepherd-services
442 (match-lambda
443 (($ <httpd-configuration> package pid-file config)
444 (list (shepherd-service
445 (provision '(httpd))
446 (documentation "The Apache HTTP Server")
447 (requirement '(networking))
448 (start #~(make-forkexec-constructor
449 `(#$(file-append package "/bin/httpd")
450 #$@(if config
451 (list "-f" config)
452 '()))
453 #:pid-file #$pid-file))
454 (stop #~(make-kill-destructor)))))))
455
456 (define httpd-activation
457 (match-lambda
458 (($ <httpd-configuration> package pid-file config)
459 (match-record
460 config
461 <httpd-config-file>
462 (error-log document-root)
463 #~(begin
464 (use-modules (guix build utils))
465
466 (mkdir-p #$(dirname error-log))
467 (mkdir-p #$document-root))))))
468
469 (define (httpd-process-extensions original-config extension-configs)
470 (let ((config (httpd-configuration-config
471 original-config)))
472 (if (httpd-config-file? config)
473 (httpd-configuration
474 (inherit original-config)
475 (config
476 (httpd-config-file
477 (inherit config)
478 (extra-config
479 (append (httpd-config-file-extra-config config)
480 (append-map
481 (match-lambda
482 (($ <httpd-virtualhost>
483 addresses-and-ports
484 contents)
485 `(,(string-append
486 "\n<VirtualHost " addresses-and-ports ">\n")
487 ,@contents
488 "\n</VirtualHost>\n"))
489 ((? string? x)
490 `("\n" ,x "\n"))
491 ((? list? x)
492 `("\n" ,@x "\n")))
493 extension-configs)))))))))
494
495 (define httpd-service-type
496 (service-type (name 'httpd)
497 (extensions
498 (list (service-extension shepherd-root-service-type
499 httpd-shepherd-services)
500 (service-extension activation-service-type
501 httpd-activation)
502 (service-extension account-service-type
503 (const %httpd-accounts))))
504 (compose concatenate)
505 (extend httpd-process-extensions)
506 (default-value
507 (httpd-configuration))
508 (description "Run the Apache httpd Web server.")))
509
510 (define-record-type* <nginx-server-configuration>
511 nginx-server-configuration make-nginx-server-configuration
512 nginx-server-configuration?
513 (listen nginx-server-configuration-listen
514 (default '("80" "443 ssl")))
515 (server-name nginx-server-configuration-server-name
516 (default (list 'default)))
517 (root nginx-server-configuration-root
518 (default "/srv/http"))
519 (locations nginx-server-configuration-locations
520 (default '()))
521 (index nginx-server-configuration-index
522 (default (list "index.html")))
523 (try-files nginx-server-configuration-try-files
524 (default '()))
525 (ssl-certificate nginx-server-configuration-ssl-certificate
526 (default #f))
527 (ssl-certificate-key nginx-server-configuration-ssl-certificate-key
528 (default #f))
529 (server-tokens? nginx-server-configuration-server-tokens?
530 (default #f))
531 (raw-content nginx-server-configuration-raw-content
532 (default '())))
533
534 (define-record-type* <nginx-upstream-configuration>
535 nginx-upstream-configuration make-nginx-upstream-configuration
536 nginx-upstream-configuration?
537 (name nginx-upstream-configuration-name)
538 (servers nginx-upstream-configuration-servers)
539 (extra-content nginx-upstream-configuration-extra-content
540 (default '())))
541
542 (define-record-type* <nginx-location-configuration>
543 nginx-location-configuration make-nginx-location-configuration
544 nginx-location-configuration?
545 (uri nginx-location-configuration-uri
546 (default #f))
547 (body nginx-location-configuration-body))
548
549 (define-record-type* <nginx-named-location-configuration>
550 nginx-named-location-configuration make-nginx-named-location-configuration
551 nginx-named-location-configuration?
552 (name nginx-named-location-configuration-name
553 (default #f))
554 (body nginx-named-location-configuration-body))
555
556 (define-record-type* <nginx-configuration>
557 nginx-configuration make-nginx-configuration
558 nginx-configuration?
559 (nginx nginx-configuration-nginx ;file-like
560 (default nginx))
561 (shepherd-requirement nginx-configuration-shepherd-requirement
562 (default '())) ;list of symbols
563 (log-directory nginx-configuration-log-directory ;string
564 (default "/var/log/nginx"))
565 (run-directory nginx-configuration-run-directory ;string
566 (default "/var/run/nginx"))
567 (server-blocks nginx-configuration-server-blocks
568 (default '())) ;list of <nginx-server-configuration>
569 (upstream-blocks nginx-configuration-upstream-blocks
570 (default '())) ;list of <nginx-upstream-configuration>
571 (server-names-hash-bucket-size nginx-configuration-server-names-hash-bucket-size
572 (default #f))
573 (server-names-hash-bucket-max-size nginx-configuration-server-names-hash-bucket-max-size
574 (default #f))
575 (modules nginx-configuration-modules (default '()))
576 (global-directives nginx-configuration-global-directives
577 (default '((events . ()))))
578 (lua-package-path nginx-lua-package-path ;list of file-like
579 (default #f))
580 (lua-package-cpath nginx-lua-package-cpath ;list of file-like
581 (default #f))
582 (extra-content nginx-configuration-extra-content
583 (default ""))
584 (file nginx-configuration-file ;#f | string | file-like
585 (default #f)))
586
587 (define (config-domain-strings names)
588 "Return a string denoting the nginx config representation of NAMES, a list
589 of domain names."
590 (map (match-lambda
591 ('default "_ ")
592 ((? string? str) (list str " ")))
593 names))
594
595 (define (config-index-strings names)
596 "Return a string denoting the nginx config representation of NAMES, a list
597 of index files."
598 (map (match-lambda
599 ((? string? str) (list str " ")))
600 names))
601
602 (define (emit-load-module module)
603 (list "load_module " module ";\n"))
604
605 (define emit-global-directive
606 (match-lambda
607 ((key . (? list? alist))
608 (format #f "~a { ~{~a~}}~%" key (map emit-global-directive alist)))
609 ((key . value)
610 (format #f "~a ~a;~%" key value))))
611
612 (define emit-nginx-location-config
613 (match-lambda
614 (($ <nginx-location-configuration> uri body)
615 (list
616 " location " uri " {\n"
617 (map (lambda (x) (list " " x "\n")) body)
618 " }\n"))
619 (($ <nginx-named-location-configuration> name body)
620 (list
621 " location @" name " {\n"
622 (map (lambda (x) (list " " x "\n")) body)
623 " }\n"))))
624
625 (define (emit-nginx-server-config server)
626 (let ((listen (nginx-server-configuration-listen server))
627 (server-name (nginx-server-configuration-server-name server))
628 (ssl-certificate (nginx-server-configuration-ssl-certificate server))
629 (ssl-certificate-key
630 (nginx-server-configuration-ssl-certificate-key server))
631 (root (nginx-server-configuration-root server))
632 (index (nginx-server-configuration-index server))
633 (try-files (nginx-server-configuration-try-files server))
634 (server-tokens? (nginx-server-configuration-server-tokens? server))
635 (locations (nginx-server-configuration-locations server))
636 (raw-content (nginx-server-configuration-raw-content server)))
637 (define-syntax-parameter <> (syntax-rules ()))
638 (define-syntax-rule (and/l x tail ...)
639 (let ((x* x))
640 (if x*
641 (syntax-parameterize ((<> (identifier-syntax x*)))
642 (list tail ...))
643 '())))
644 (list
645 " server {\n"
646 (map (lambda (directive) (list " listen " directive ";\n")) listen)
647 " server_name " (config-domain-strings server-name) ";\n"
648 (and/l ssl-certificate " ssl_certificate " <> ";\n")
649 (and/l ssl-certificate-key " ssl_certificate_key " <> ";\n")
650 (if (not (equal? "" root))
651 (list " root " root ";\n")
652 "")
653 (if (not (null? index))
654 (list " index " (config-index-strings index) ";\n")
655 "")
656 (if (not (nil? try-files))
657 (and/l (config-index-strings try-files) " try_files " <> ";\n")
658 "")
659 " server_tokens " (if server-tokens? "on" "off") ";\n"
660 "\n"
661 (map emit-nginx-location-config locations)
662 "\n"
663 (map (lambda (x) (list " " x "\n")) raw-content)
664 " }\n")))
665
666 (define (emit-nginx-upstream-config upstream)
667 (list
668 " upstream " (nginx-upstream-configuration-name upstream) " {\n"
669 (map (lambda (server)
670 (simple-format #f " server ~A;\n" server))
671 (nginx-upstream-configuration-servers upstream))
672 (let ((extra-content
673 (nginx-upstream-configuration-extra-content upstream)))
674 (if (and extra-content (not (null? extra-content)))
675 (cons
676 "\n"
677 (map (lambda (line)
678 (simple-format #f " ~A\n" line))
679 (flatten extra-content)))
680 '()))
681 " }\n"))
682
683 (define (flatten . lst)
684 "Return a list that recursively concatenates all sub-lists of LST."
685 (define (flatten1 head out)
686 (if (list? head)
687 (fold-right flatten1 out head)
688 (cons head out)))
689 (fold-right flatten1 '() lst))
690
691 (define (default-nginx-config config)
692 (match-record config
693 <nginx-configuration>
694 (nginx log-directory run-directory
695 server-blocks upstream-blocks
696 server-names-hash-bucket-size
697 server-names-hash-bucket-max-size
698 modules
699 global-directives
700 lua-package-path
701 lua-package-cpath
702 extra-content)
703 (apply mixed-text-file "nginx.conf"
704 (flatten
705 "user nginx nginx;\n"
706 "pid " run-directory "/pid;\n"
707 "error_log " log-directory "/error.log info;\n"
708 (map emit-load-module modules)
709 (map emit-global-directive global-directives)
710 "http {\n"
711 " client_body_temp_path " run-directory "/client_body_temp;\n"
712 " proxy_temp_path " run-directory "/proxy_temp;\n"
713 " fastcgi_temp_path " run-directory "/fastcgi_temp;\n"
714 " uwsgi_temp_path " run-directory "/uwsgi_temp;\n"
715 " scgi_temp_path " run-directory "/scgi_temp;\n"
716 " access_log " log-directory "/access.log;\n"
717 " include " nginx "/share/nginx/conf/mime.types;\n"
718 (if lua-package-path
719 #~(format #f " lua_package_path ~s;~%"
720 (string-join (map (lambda (path)
721 (string-append path "/lib/?.lua"))
722 '#$lua-package-path)
723 ";"))
724 "")
725 (if lua-package-cpath
726 #~(format #f " lua_package_cpath ~s;~%"
727 (string-join (map (lambda (cpath)
728 (string-append cpath "/lib/lua/?.lua"))
729 '#$lua-package-cpath)
730 ";"))
731 "")
732 (if server-names-hash-bucket-size
733 (string-append
734 " server_names_hash_bucket_size "
735 (number->string server-names-hash-bucket-size)
736 ";\n")
737 "")
738 (if server-names-hash-bucket-max-size
739 (string-append
740 " server_names_hash_bucket_max_size "
741 (number->string server-names-hash-bucket-max-size)
742 ";\n")
743 "")
744 "\n"
745 (map emit-nginx-upstream-config upstream-blocks)
746 (map emit-nginx-server-config server-blocks)
747 extra-content
748 "\n}\n"))))
749
750 (define %nginx-accounts
751 (list (user-group (name "nginx") (system? #t))
752 (user-account
753 (name "nginx")
754 (group "nginx")
755 (system? #t)
756 (comment "nginx server user")
757 (home-directory "/var/empty")
758 (shell (file-append shadow "/sbin/nologin")))))
759
760 (define (nginx-activation config)
761 (match-record config
762 <nginx-configuration>
763 (nginx log-directory run-directory file)
764 #~(begin
765 (use-modules (guix build utils))
766
767 (format #t "creating nginx log directory '~a'~%" #$log-directory)
768 (mkdir-p #$log-directory)
769 (format #t "creating nginx run directory '~a'~%" #$run-directory)
770 (mkdir-p #$run-directory)
771 (format #t "creating nginx temp directories '~a/{client_body,proxy,fastcgi,uwsgi,scgi}_temp'~%" #$run-directory)
772 (mkdir-p (string-append #$run-directory "/client_body_temp"))
773 (mkdir-p (string-append #$run-directory "/proxy_temp"))
774 (mkdir-p (string-append #$run-directory "/fastcgi_temp"))
775 (mkdir-p (string-append #$run-directory "/uwsgi_temp"))
776 (mkdir-p (string-append #$run-directory "/scgi_temp"))
777 ;; Start-up logs. Once configuration is loaded, nginx switches to
778 ;; log-directory.
779 (mkdir-p (string-append #$run-directory "/logs"))
780 ;; Check configuration file syntax.
781 (system* (string-append #$nginx "/sbin/nginx")
782 "-c" #$(or file
783 (default-nginx-config config))
784 "-p" #$run-directory
785 "-t"))))
786
787 (define (nginx-shepherd-service config)
788 (match-record config
789 <nginx-configuration>
790 (nginx file run-directory shepherd-requirement)
791 (let* ((nginx-binary (file-append nginx "/sbin/nginx"))
792 (pid-file (in-vicinity run-directory "pid"))
793 (nginx-action
794 (lambda args
795 #~(lambda _
796 (invoke #$nginx-binary "-c"
797 #$(or file
798 (default-nginx-config config))
799 #$@args)
800 (match '#$args
801 (("-s" . _) #f)
802 (_
803 ;; When FILE is true, we cannot be sure that PID-FILE will
804 ;; be created, so assume it won't show up. When FILE is
805 ;; false, read PID-FILE.
806 #$(if file
807 #~#t
808 #~(read-pid-file #$pid-file))))))))
809
810 (list (shepherd-service
811 (provision '(nginx))
812 (documentation "Run the nginx daemon.")
813 (requirement `(user-processes loopback ,@shepherd-requirement))
814 (modules `((ice-9 match)
815 ,@%default-modules))
816 (start (nginx-action "-p" run-directory))
817 (stop (nginx-action "-s" "stop"))
818 (actions
819 (list
820 (shepherd-action
821 (name 'reload)
822 (documentation "Reload nginx configuration file and restart worker processes.
823 This has the effect of killing old worker processes and starting new ones, using
824 the same configuration file. It is useful for situations where the same nginx
825 configuration file can point to different things after a reload, such as
826 renewed TLS certificates, or @code{include}d files.")
827 (procedure (nginx-action "-s" "reload"))))))))))
828
829 (define nginx-service-type
830 (service-type (name 'nginx)
831 (extensions
832 (list (service-extension shepherd-root-service-type
833 nginx-shepherd-service)
834 (service-extension activation-service-type
835 nginx-activation)
836 (service-extension account-service-type
837 (const %nginx-accounts))))
838 (compose concatenate)
839 (extend (lambda (config servers)
840 (nginx-configuration
841 (inherit config)
842 (server-blocks
843 (append (nginx-configuration-server-blocks config)
844 servers)))))
845 (default-value (nginx-configuration))
846 (description "Run the nginx Web server.")))
847
848 (define-record-type* <fcgiwrap-configuration> fcgiwrap-configuration
849 make-fcgiwrap-configuration
850 fcgiwrap-configuration?
851 (package fcgiwrap-configuration-package ;file-like
852 (default fcgiwrap))
853 (socket fcgiwrap-configuration-socket
854 (default "tcp:127.0.0.1:9000"))
855 (user fcgiwrap-configuration-user
856 (default "fcgiwrap"))
857 (group fcgiwrap-configuration-group
858 (default "fcgiwrap")))
859
860 (define fcgiwrap-accounts
861 (match-lambda
862 (($ <fcgiwrap-configuration> package socket user group)
863 (filter identity
864 (list
865 (and (equal? group "fcgiwrap")
866 (user-group
867 (name "fcgiwrap")
868 (system? #t)))
869 (and (equal? user "fcgiwrap")
870 (user-account
871 (name "fcgiwrap")
872 (group group)
873 (system? #t)
874 (comment "Fcgiwrap Daemon")
875 (home-directory "/var/empty")
876 (shell (file-append shadow "/sbin/nologin")))))))))
877
878 (define fcgiwrap-shepherd-service
879 (match-lambda
880 (($ <fcgiwrap-configuration> package socket user group)
881 (list (shepherd-service
882 (provision '(fcgiwrap))
883 (documentation "Run the fcgiwrap daemon.")
884 (requirement '(networking))
885 (start #~(make-forkexec-constructor
886 '(#$(file-append package "/sbin/fcgiwrap")
887 "-s" #$socket)
888 #:user #$user #:group #$group
889 #:log-file "/var/log/fcgiwrap.log"))
890 (stop #~(make-kill-destructor)))))))
891
892 (define fcgiwrap-activation
893 (match-lambda
894 (($ <fcgiwrap-configuration> package socket user group)
895 #~(begin
896 ;; When listening on a unix socket, create a parent directory for the
897 ;; socket with the correct permissions.
898 (when (string-prefix? "unix:" #$socket)
899 (let ((run-directory
900 (dirname (substring #$socket (string-length "unix:")))))
901 (mkdir-p run-directory)
902 (chown run-directory
903 (passwd:uid (getpw #$user))
904 (group:gid (getgr #$group)))))))))
905
906 (define fcgiwrap-service-type
907 (service-type (name 'fcgiwrap)
908 (extensions
909 (list (service-extension shepherd-root-service-type
910 fcgiwrap-shepherd-service)
911 (service-extension account-service-type
912 fcgiwrap-accounts)
913 (service-extension activation-service-type
914 fcgiwrap-activation)))
915 (default-value (fcgiwrap-configuration))
916 (description "Run FastCGI, an interface between the front-end
917 and the back-end of a Web service.")))
918
919 (define-record-type* <php-fpm-configuration> php-fpm-configuration
920 make-php-fpm-configuration
921 php-fpm-configuration?
922 (php php-fpm-configuration-php ;file-like
923 (default php))
924 (socket php-fpm-configuration-socket
925 (default (string-append "/var/run/php"
926 (version-major (package-version php))
927 "-fpm.sock")))
928 (user php-fpm-configuration-user
929 (default "php-fpm"))
930 (group php-fpm-configuration-group
931 (default "php-fpm"))
932 (socket-user php-fpm-configuration-socket-user
933 (default "php-fpm"))
934 (socket-group php-fpm-configuration-socket-group
935 (default "nginx"))
936 (pid-file php-fpm-configuration-pid-file
937 (default (string-append "/var/run/php"
938 (version-major (package-version php))
939 "-fpm.pid")))
940 (log-file php-fpm-configuration-log-file
941 (default (string-append "/var/log/php"
942 (version-major (package-version php))
943 "-fpm.log")))
944 (process-manager php-fpm-configuration-process-manager
945 (default (php-fpm-dynamic-process-manager-configuration)))
946 (display-errors php-fpm-configuration-display-errors
947 (default #f))
948 (timezone php-fpm-configuration-timezone
949 (default #f))
950 (workers-log-file php-fpm-configuration-workers-log-file
951 (default (string-append "/var/log/php"
952 (version-major (package-version php))
953 "-fpm.www.log")))
954 (file php-fpm-configuration-file ;#f | file-like
955 (default #f))
956 (php-ini-file php-fpm-configuration-php-ini-file ;#f | file-like
957 (default #f)))
958
959 (define-record-type* <php-fpm-dynamic-process-manager-configuration>
960 php-fpm-dynamic-process-manager-configuration
961 make-php-fpm-dynamic-process-manager-configuration
962 php-fpm-dynamic-process-manager-configuration?
963 (max-children php-fpm-dynamic-process-manager-configuration-max-children
964 (default 5))
965 (start-servers php-fpm-dynamic-process-manager-configuration-start-servers
966 (default 2))
967 (min-spare-servers php-fpm-dynamic-process-manager-configuration-min-spare-servers
968 (default 1))
969 (max-spare-servers php-fpm-dynamic-process-manager-configuration-max-spare-servers
970 (default 3)))
971
972 (define-record-type* <php-fpm-static-process-manager-configuration>
973 php-fpm-static-process-manager-configuration
974 make-php-fpm-static-process-manager-configuration
975 php-fpm-static-process-manager-configuration?
976 (max-children php-fpm-static-process-manager-configuration-max-children
977 (default 5)))
978
979 (define-record-type* <php-fpm-on-demand-process-manager-configuration>
980 php-fpm-on-demand-process-manager-configuration
981 make-php-fpm-on-demand-process-manager-configuration
982 php-fpm-on-demand-process-manager-configuration?
983 (max-children php-fpm-on-demand-process-manager-configuration-max-children
984 (default 5))
985 (process-idle-timeout php-fpm-on-demand-process-manager-configuration-process-idle-timeout
986 (default 10)))
987
988 (define php-fpm-accounts
989 (match-lambda
990 (($ <php-fpm-configuration> php socket user group socket-user socket-group _ _ _ _ _ _)
991 `(,@(if (equal? group "php-fpm")
992 '()
993 (list (user-group (name "php-fpm") (system? #t))))
994 ,(user-group
995 (name group)
996 (system? #t))
997 ,(user-account
998 (name user)
999 (group group)
1000 (supplementary-groups '("php-fpm"))
1001 (system? #t)
1002 (comment "php-fpm daemon user")
1003 (home-directory "/var/empty")
1004 (shell (file-append shadow "/sbin/nologin")))))))
1005
1006 (define (default-php-fpm-config socket user group socket-user socket-group
1007 pid-file log-file pm display-errors timezone workers-log-file)
1008 (apply mixed-text-file "php-fpm.conf"
1009 (flatten
1010 "[global]\n"
1011 "pid =" pid-file "\n"
1012 "error_log =" log-file "\n"
1013 "[www]\n"
1014 "user =" user "\n"
1015 "group =" group "\n"
1016 "listen =" socket "\n"
1017 "listen.owner =" socket-user "\n"
1018 "listen.group =" socket-group "\n"
1019
1020 (if timezone
1021 (string-append "php_admin_value[date.timezone] = \"" timezone "\"\n")
1022 "")
1023
1024 (match pm
1025 (($ <php-fpm-dynamic-process-manager-configuration>
1026 pm.max-children
1027 pm.start-servers
1028 pm.min-spare-servers
1029 pm.max-spare-servers)
1030 (list
1031 "pm = dynamic\n"
1032 "pm.max_children =" (number->string pm.max-children) "\n"
1033 "pm.start_servers =" (number->string pm.start-servers) "\n"
1034 "pm.min_spare_servers =" (number->string pm.min-spare-servers) "\n"
1035 "pm.max_spare_servers =" (number->string pm.max-spare-servers) "\n"))
1036
1037 (($ <php-fpm-static-process-manager-configuration>
1038 pm.max-children)
1039 (list
1040 "pm = static\n"
1041 "pm.max_children =" (number->string pm.max-children) "\n"))
1042
1043 (($ <php-fpm-on-demand-process-manager-configuration>
1044 pm.max-children
1045 pm.process-idle-timeout)
1046 (list
1047 "pm = ondemand\n"
1048 "pm.max_children =" (number->string pm.max-children) "\n"
1049 "pm.process_idle_timeout =" (number->string pm.process-idle-timeout) "s\n")))
1050
1051
1052 "php_flag[display_errors] = " (if display-errors "on" "off") "\n"
1053
1054 (if workers-log-file
1055 (list "catch_workers_output = yes\n"
1056 "php_admin_value[error_log] =" workers-log-file "\n"
1057 "php_admin_flag[log_errors] = on\n")
1058 (list "catch_workers_output = no\n")))))
1059
1060 (define php-fpm-shepherd-service
1061 (match-lambda
1062 (($ <php-fpm-configuration> php socket user group socket-user socket-group
1063 pid-file log-file pm display-errors
1064 timezone workers-log-file file php-ini-file)
1065 (list (shepherd-service
1066 (provision '(php-fpm))
1067 (documentation "Run the php-fpm daemon.")
1068 (requirement '(networking))
1069 (start #~(make-forkexec-constructor
1070 '(#$(file-append php "/sbin/php-fpm")
1071 "--fpm-config"
1072 #$(or file
1073 (default-php-fpm-config socket user group
1074 socket-user socket-group pid-file log-file
1075 pm display-errors timezone workers-log-file))
1076 #$@(if php-ini-file
1077 `("-c" ,php-ini-file)
1078 '()))
1079 #:pid-file #$pid-file))
1080 (stop #~(make-kill-destructor)))))))
1081
1082 (define (php-fpm-activation config)
1083 #~(begin
1084 (use-modules (guix build utils))
1085 (let* ((user (getpwnam #$(php-fpm-configuration-user config)))
1086 (touch (lambda (file-name)
1087 (call-with-output-file file-name (const #t))))
1088 (workers-log-file
1089 #$(php-fpm-configuration-workers-log-file config))
1090 (init-log-file
1091 (lambda (file-name)
1092 (when workers-log-file
1093 (when (not (file-exists? file-name))
1094 (touch file-name))
1095 (chown file-name (passwd:uid user) (passwd:gid user))
1096 (chmod file-name #o660)))))
1097 (init-log-file #$(php-fpm-configuration-log-file config))
1098 (init-log-file workers-log-file))))
1099
1100
1101 (define php-fpm-service-type
1102 (service-type
1103 (name 'php-fpm)
1104 (description
1105 "Run @command{php-fpm} to provide a fastcgi socket for calling php through
1106 a webserver.")
1107 (extensions
1108 (list (service-extension shepherd-root-service-type
1109 php-fpm-shepherd-service)
1110 (service-extension activation-service-type
1111 php-fpm-activation)
1112 (service-extension account-service-type
1113 php-fpm-accounts)))
1114 (default-value (php-fpm-configuration))))
1115
1116 (define* (nginx-php-location
1117 #:key
1118 (nginx-package nginx)
1119 (socket (string-append "/var/run/php"
1120 (version-major (package-version php))
1121 "-fpm.sock")))
1122 "Return a nginx-location-configuration that makes nginx run .php files."
1123 (nginx-location-configuration
1124 (uri "~ \\.php$")
1125 (body (list
1126 "fastcgi_split_path_info ^(.+\\.php)(/.+)$;"
1127 (string-append "fastcgi_pass unix:" socket ";")
1128 "fastcgi_index index.php;"
1129 (list "include " nginx-package "/share/nginx/conf/fastcgi.conf;")))))
1130
1131 (define* (cat-avatar-generator-service
1132 #:key
1133 (cache-dir "/var/cache/cat-avatar-generator")
1134 (package cat-avatar-generator)
1135 (configuration (nginx-server-configuration)))
1136 (simple-service
1137 'cat-http-server nginx-service-type
1138 (list (nginx-server-configuration
1139 (inherit configuration)
1140 (locations
1141 (cons
1142 (let ((base (nginx-php-location)))
1143 (nginx-location-configuration
1144 (inherit base)
1145 (body (list (string-append "fastcgi_param CACHE_DIR \""
1146 cache-dir "\";")
1147 (nginx-location-configuration-body base)))))
1148 (nginx-server-configuration-locations configuration)))
1149 (root #~(string-append #$package
1150 "/share/web/cat-avatar-generator"))))))
1151
1152 \f
1153 (define-record-type* <hpcguix-web-configuration>
1154 hpcguix-web-configuration make-hpcguix-web-configuration
1155 hpcguix-web-configuration?
1156
1157 (package hpcguix-web-package (default hpcguix-web)) ;file-like
1158
1159 ;; Specs is gexp of hpcguix-web configuration file
1160 (specs hpcguix-web-configuration-specs)
1161 (address hpcguix-web-configuration-address (default "127.0.0.1"))
1162 (port hpcguix-web-configuration-port (default 5000)))
1163
1164 (define %hpcguix-web-accounts
1165 (list (user-group
1166 (name "hpcguix-web")
1167 (system? #t))
1168 (user-account
1169 (name "hpcguix-web")
1170 (group "hpcguix-web")
1171 (system? #t)
1172 (comment "hpcguix-web")
1173 (home-directory "/var/empty")
1174 (shell (file-append shadow "/sbin/nologin")))))
1175
1176 (define %hpcguix-web-activation
1177 (with-imported-modules '((guix build utils))
1178 #~(begin
1179 (use-modules (guix build utils)
1180 (ice-9 ftw))
1181
1182 (let ((home-dir "/var/cache/guix/web")
1183 (user (getpwnam "hpcguix-web")))
1184 (mkdir-p home-dir)
1185 (chown home-dir (passwd:uid user) (passwd:gid user))
1186 (chmod home-dir #o755)
1187
1188 ;; Remove stale 'packages.json.lock' file (and other lock files, if
1189 ;; any) since that would prevent 'packages.json' from being updated.
1190 (for-each (lambda (lock)
1191 (delete-file (string-append home-dir "/" lock)))
1192 (scandir home-dir
1193 (lambda (file)
1194 (string-suffix? ".lock" file))))))))
1195
1196 (define %hpcguix-web-log-file
1197 "/var/log/hpcguix-web.log")
1198
1199 (define %hpcguix-web-log-rotations
1200 (list (log-rotation
1201 (files (list %hpcguix-web-log-file))
1202 (frequency 'weekly))))
1203
1204 (define (hpcguix-web-shepherd-service config)
1205 (let ((specs (hpcguix-web-configuration-specs config))
1206 (hpcguix-web (hpcguix-web-package config)))
1207 (with-imported-modules (source-module-closure
1208 '((gnu build shepherd)))
1209 (shepherd-service
1210 (documentation "hpcguix-web daemon")
1211 (provision '(hpcguix-web))
1212 (requirement '(networking))
1213 (start #~(make-forkexec-constructor
1214 (list #$(file-append hpcguix-web "/bin/hpcguix-web")
1215 (string-append "--listen="
1216 #$(hpcguix-web-configuration-address
1217 config))
1218 "-p"
1219 #$(number->string
1220 (hpcguix-web-configuration-port config))
1221 (string-append "--config="
1222 #$(scheme-file "hpcguix-web.scm" specs)))
1223 #:user "hpcguix-web"
1224 #:group "hpcguix-web"
1225 #:environment-variables
1226 (list "XDG_CACHE_HOME=/var/cache/guix/web"
1227 "SSL_CERT_DIR=/etc/ssl/certs")
1228 #:log-file #$%hpcguix-web-log-file))
1229 (stop #~(make-kill-destructor))))))
1230
1231 (define hpcguix-web-service-type
1232 (service-type
1233 (name 'hpcguix-web)
1234 (description "Run the hpcguix-web server.")
1235 (extensions
1236 (list (service-extension account-service-type
1237 (const %hpcguix-web-accounts))
1238 (service-extension activation-service-type
1239 (const %hpcguix-web-activation))
1240 (service-extension rottlog-service-type
1241 (const %hpcguix-web-log-rotations))
1242 (service-extension shepherd-root-service-type
1243 (compose list hpcguix-web-shepherd-service))))))
1244
1245 \f
1246 ;;;
1247 ;;; Tailon
1248 ;;;
1249
1250 (define-record-type* <tailon-configuration-file>
1251 tailon-configuration-file make-tailon-configuration-file
1252 tailon-configuration-file?
1253 (files tailon-configuration-file-files
1254 (default '("/var/log")))
1255 (bind tailon-configuration-file-bind
1256 (default "localhost:8080"))
1257 (relative-root tailon-configuration-file-relative-root
1258 (default #f))
1259 (allow-transfers? tailon-configuration-file-allow-transfers?
1260 (default #t))
1261 (follow-names? tailon-configuration-file-follow-names?
1262 (default #t))
1263 (tail-lines tailon-configuration-file-tail-lines
1264 (default 200))
1265 (allowed-commands tailon-configuration-file-allowed-commands
1266 (default '("tail" "grep" "awk")))
1267 (debug? tailon-configuration-file-debug?
1268 (default #f))
1269 (wrap-lines tailon-configuration-file-wrap-lines
1270 (default #t))
1271 (http-auth tailon-configuration-file-http-auth
1272 (default #f))
1273 (users tailon-configuration-file-users
1274 (default #f)))
1275
1276 (define (tailon-configuration-files-string files)
1277 (string-append
1278 "\n"
1279 (string-join
1280 (map
1281 (lambda (x)
1282 (string-append
1283 " - "
1284 (cond
1285 ((string? x)
1286 (simple-format #f "'~A'" x))
1287 ((list? x)
1288 (string-join
1289 (cons (simple-format #f "'~A':" (car x))
1290 (map
1291 (lambda (x) (simple-format #f " - '~A'" x))
1292 (cdr x)))
1293 "\n"))
1294 (else (error x)))))
1295 files)
1296 "\n")))
1297
1298 (define-gexp-compiler (tailon-configuration-file-compiler
1299 (file <tailon-configuration-file>) system target)
1300 (match file
1301 (($ <tailon-configuration-file> files bind relative-root
1302 allow-transfers? follow-names?
1303 tail-lines allowed-commands debug?
1304 wrap-lines http-auth users)
1305 (text-file
1306 "tailon-config.yaml"
1307 (string-concatenate
1308 (filter-map
1309 (match-lambda
1310 ((key . #f) #f)
1311 ((key . value) (string-append key ": " value "\n")))
1312
1313 `(("files" . ,(tailon-configuration-files-string files))
1314 ("bind" . ,bind)
1315 ("relative-root" . ,relative-root)
1316 ("allow-transfers" . ,(if allow-transfers? "true" "false"))
1317 ("follow-names" . ,(if follow-names? "true" "false"))
1318 ("tail-lines" . ,(number->string tail-lines))
1319 ("commands" . ,(string-append "["
1320 (string-join allowed-commands ", ")
1321 "]"))
1322 ("debug" . ,(if debug? "true" #f))
1323 ("wrap-lines" . ,(if wrap-lines "true" "false"))
1324 ("http-auth" . ,http-auth)
1325 ("users" . ,(if users
1326 (string-concatenate
1327 (cons "\n"
1328 (map (match-lambda
1329 ((user . pass)
1330 (string-append
1331 " " user ":" pass)))
1332 users)))
1333 #f)))))))))
1334
1335 (define-record-type* <tailon-configuration>
1336 tailon-configuration make-tailon-configuration
1337 tailon-configuration?
1338 (config-file tailon-configuration-config-file
1339 (default (tailon-configuration-file)))
1340 (package tailon-configuration-package
1341 (default tailon)))
1342
1343 (define tailon-shepherd-service
1344 (match-lambda
1345 (($ <tailon-configuration> config-file package)
1346 (list (shepherd-service
1347 (provision '(tailon))
1348 (documentation "Run the tailon daemon.")
1349 (start #~(make-forkexec-constructor
1350 `(,(string-append #$package "/bin/tailon")
1351 "-c" ,#$config-file)
1352 #:user "tailon"
1353 #:group "tailon"))
1354 (stop #~(make-kill-destructor)))))))
1355
1356 (define %tailon-accounts
1357 (list (user-group (name "tailon") (system? #t))
1358 (user-account
1359 (name "tailon")
1360 (group "tailon")
1361 (system? #t)
1362 (comment "tailon")
1363 (home-directory "/var/empty")
1364 (shell (file-append shadow "/sbin/nologin")))))
1365
1366 (define tailon-service-type
1367 (service-type
1368 (name 'tailon)
1369 (description
1370 "Run Tailon, a Web application for monitoring, viewing, and searching log
1371 files.")
1372 (extensions
1373 (list (service-extension shepherd-root-service-type
1374 tailon-shepherd-service)
1375 (service-extension account-service-type
1376 (const %tailon-accounts))))
1377 (compose concatenate)
1378 (extend (lambda (parameter files)
1379 (tailon-configuration
1380 (inherit parameter)
1381 (config-file
1382 (let ((old-config-file
1383 (tailon-configuration-config-file parameter)))
1384 (tailon-configuration-file
1385 (inherit old-config-file)
1386 (files (append (tailon-configuration-file-files old-config-file)
1387 files))))))))
1388 (default-value (tailon-configuration))))
1389
1390
1391 \f
1392 ;;;
1393 ;;; Log anonymization
1394 ;;;
1395
1396 (define-record-type* <anonip-configuration>
1397 anonip-configuration make-anonip-configuration
1398 anonip-configuration?
1399 (anonip anonip-configuration-anonip ;file-like
1400 (default anonip))
1401 (input anonip-configuration-input) ;string
1402 (output anonip-configuration-output) ;string
1403 (skip-private? anonip-configuration-skip-private? ;boolean
1404 (default #f))
1405 (column anonip-configuration-column ;number
1406 (default #f))
1407 (replacement anonip-configuration-replacement ;string
1408 (default #f))
1409 (ipv4mask anonip-configuration-ipv4mask ;number
1410 (default #f))
1411 (ipv6mask anonip-configuration-ipv6mask ;number
1412 (default #f))
1413 (increment anonip-configuration-increment ;number
1414 (default #f))
1415 (delimiter anonip-configuration-delimiter ;string
1416 (default #f))
1417 (regex anonip-configuration-regex ;string
1418 (default #f)))
1419
1420 (define (anonip-activation config)
1421 (with-imported-modules '((guix build utils))
1422 #~(begin
1423 (use-modules (guix build utils))
1424 (for-each
1425 (lambda (directory)
1426 (mkdir-p directory)
1427 (chmod directory #o755))
1428 (list (dirname #$(anonip-configuration-input config))
1429 (dirname #$(anonip-configuration-output config)))))))
1430
1431 (define (anonip-shepherd-service config)
1432 (let ((input (anonip-configuration-input config))
1433 (output (anonip-configuration-output config))
1434 (optional
1435 (lambda (accessor option)
1436 (or (and=> (accessor config)
1437 (lambda (value)
1438 (list
1439 (format #false "~a=~a"
1440 option value))))
1441 (list)))))
1442 (list
1443 (shepherd-service
1444 (provision
1445 (list (symbol-append 'anonip- (string->symbol output))))
1446 (requirement '(user-processes))
1447 (documentation
1448 "Anonimyze the given log file location with anonip.")
1449 (start
1450 #~(lambda ()
1451 (define (spawn)
1452 (fork+exec-command
1453 (append
1454 (list #$(file-append (anonip-configuration-anonip config)
1455 "/bin/anonip")
1456 (string-append "--input=" #$input)
1457 (string-append "--output=" #$output))
1458 (if #$(anonip-configuration-skip-private? config)
1459 '("--skip-private") (list))
1460 '#$(optional anonip-configuration-column "--column")
1461 '#$(optional anonip-configuration-ipv4mask "--ipv4mask")
1462 '#$(optional anonip-configuration-ipv6mask "--ipv6mask")
1463 '#$(optional anonip-configuration-increment "--increment")
1464 '#$(optional anonip-configuration-replacement
1465 "--replacement")
1466 '#$(optional anonip-configuration-delimiter "--delimiter")
1467 '#$(optional anonip-configuration-regex "--regex"))
1468 ;; Run in a UTF-8 locale
1469 #:environment-variables
1470 (list (string-append "GUIX_LOCPATH=" #$glibc-utf8-locales
1471 "/lib/locale")
1472 "LC_ALL=en_US.utf8")))
1473
1474 (let ((stat (stat #$input #f)))
1475 (cond ((not stat)
1476 (mknod #$input 'fifo #o600 0)
1477 (spawn))
1478 ((eq? 'fifo (stat:type stat))
1479 (spawn))
1480 (else
1481 (format #t "'~a' is not a FIFO; bailing out~%"
1482 #$input)
1483 #f)))))
1484 (stop #~(make-kill-destructor))))))
1485
1486 (define anonip-service-type
1487 (service-type
1488 (name 'anonip)
1489 (extensions
1490 (list (service-extension shepherd-root-service-type
1491 anonip-shepherd-service)
1492 (service-extension activation-service-type
1493 anonip-activation)))
1494 (description
1495 "Provide web server log anonymization with @command{anonip}.")))
1496
1497 \f
1498 ;;;
1499 ;;; Varnish
1500 ;;;
1501
1502 (define-record-type* <varnish-configuration>
1503 varnish-configuration make-varnish-configuration
1504 varnish-configuration?
1505 (package varnish-configuration-package ;file-like
1506 (default varnish))
1507 (name varnish-configuration-name ;string
1508 (default "default"))
1509 (backend varnish-configuration-backend ;string
1510 (default "localhost:8080"))
1511 (vcl varnish-configuration-vcl ;#f | <file-like>
1512 (default #f))
1513 (listen varnish-configuration-listen ;list of strings
1514 (default '("localhost:80")))
1515 (storage varnish-configuration-storage ;list of strings
1516 (default '("malloc,128m")))
1517 (parameters varnish-configuration-parameters ;list of string pairs
1518 (default '()))
1519 (extra-options varnish-configuration-extra-options ;list of strings
1520 (default '())))
1521
1522 (define %varnish-accounts
1523 (list (user-group
1524 (name "varnish")
1525 (system? #t))
1526 (user-account
1527 (name "varnish")
1528 (group "varnish")
1529 (system? #t)
1530 (comment "Varnish Cache User")
1531 (home-directory "/var/varnish")
1532 (shell (file-append shadow "/sbin/nologin")))))
1533
1534 (define varnish-shepherd-service
1535 (match-lambda
1536 (($ <varnish-configuration> package name backend vcl listen storage
1537 parameters extra-options)
1538 (list (shepherd-service
1539 (provision (list (symbol-append 'varnish- (string->symbol name))))
1540 (documentation (string-append "The Varnish Web Accelerator"
1541 " (" name ")"))
1542 (requirement '(networking))
1543 (start #~(make-forkexec-constructor
1544 (list #$(file-append package "/sbin/varnishd")
1545 "-n" #$name
1546 #$@(if vcl
1547 #~("-f" #$vcl)
1548 #~("-b" #$backend))
1549 #$@(append-map (lambda (a) (list "-a" a)) listen)
1550 #$@(append-map (lambda (s) (list "-s" s)) storage)
1551 #$@(append-map (lambda (p)
1552 (list "-p" (format #f "~a=~a"
1553 (car p) (cdr p))))
1554 parameters)
1555 #$@extra-options)
1556 ;; Varnish will drop privileges to the "varnish" user when
1557 ;; it exists. Not passing #:user here allows the service
1558 ;; to bind to ports < 1024.
1559 #:pid-file (if (string-prefix? "/" #$name)
1560 (string-append #$name "/_.pid")
1561 (string-append "/var/varnish/" #$name "/_.pid"))))
1562 (stop #~(make-kill-destructor)))))))
1563
1564 (define varnish-service-type
1565 (service-type
1566 (name 'varnish)
1567 (description "Run the Varnish cache server.")
1568 (extensions
1569 (list (service-extension account-service-type
1570 (const %varnish-accounts))
1571 (service-extension shepherd-root-service-type
1572 varnish-shepherd-service)))
1573 (default-value
1574 (varnish-configuration))))
1575
1576 \f
1577 ;;;
1578 ;;; Patchwork
1579 ;;;
1580
1581 (define-record-type* <patchwork-database-configuration>
1582 patchwork-database-configuration make-patchwork-database-configuration
1583 patchwork-database-configuration?
1584 (engine patchwork-database-configuration-engine
1585 (default "django.db.backends.postgresql_psycopg2"))
1586 (name patchwork-database-configuration-name
1587 (default "patchwork"))
1588 (user patchwork-database-configuration-user
1589 (default "httpd"))
1590 (password patchwork-database-configuration-password
1591 (default ""))
1592 (host patchwork-database-configuration-host
1593 (default ""))
1594 (port patchwork-database-configuration-port
1595 (default "")))
1596
1597 (define-record-type* <patchwork-settings-module>
1598 patchwork-settings-module make-patchwork-settings-module
1599 patchwork-settings-module?
1600 (database-configuration patchwork-settings-module-database-configuration
1601 (default (patchwork-database-configuration)))
1602 (secret-key-file patchwork-settings-module-secret-key-file
1603 (default "/etc/patchwork/django-secret-key"))
1604 (allowed-hosts patchwork-settings-module-allowed-hosts)
1605 (default-from-email patchwork-settings-module-default-from-email)
1606 (static-url patchwork-settings-module-static-url
1607 (default "/static/"))
1608 (admins patchwork-settings-module-admins
1609 (default '()))
1610 (debug? patchwork-settings-module-debug?
1611 (default #f))
1612 (enable-rest-api? patchwork-settings-module-enable-rest-api?
1613 (default #t))
1614 (enable-xmlrpc? patchwork-settings-module-enable-xmlrpc?
1615 (default #t))
1616 (force-https-links? patchwork-settings-module-force-https-links?
1617 (default #t))
1618 (extra-settings patchwork-settings-module-extra-settings
1619 (default "")))
1620
1621 (define-record-type* <patchwork-configuration>
1622 patchwork-configuration make-patchwork-configuration
1623 patchwork-configuration?
1624 (patchwork patchwork-configuration-patchwork
1625 (default patchwork))
1626 (domain patchwork-configuration-domain)
1627 (settings-module patchwork-configuration-settings-module)
1628 (static-path patchwork-configuration-static-url
1629 (default "/static/"))
1630 (getmail-retriever-config getmail-retriever-config))
1631
1632 ;; Django uses a Python module for configuration, so this compiler generates a
1633 ;; Python module from the configuration record.
1634 (define-gexp-compiler (patchwork-settings-module-compiler
1635 (file <patchwork-settings-module>) system target)
1636 (match file
1637 (($ <patchwork-settings-module> database-configuration secret-key-file
1638 allowed-hosts default-from-email
1639 static-url admins debug? enable-rest-api?
1640 enable-xmlrpc? force-https-links?
1641 extra-configuration)
1642 (gexp->derivation
1643 "patchwork-settings"
1644 (with-imported-modules '((guix build utils))
1645 #~(let ((output #$output))
1646 (define (create-__init__.py filename)
1647 (call-with-output-file filename
1648 (lambda (port) (display "" port))))
1649
1650 (use-modules (guix build utils)
1651 (srfi srfi-1))
1652
1653 (mkdir-p (string-append output "/guix/patchwork"))
1654 (create-__init__.py
1655 (string-append output "/guix/__init__.py"))
1656 (create-__init__.py
1657 (string-append output "/guix/patchwork/__init__.py"))
1658
1659 (call-with-output-file
1660 (string-append output "/guix/patchwork/settings.py")
1661 (lambda (port)
1662 (display
1663 (string-append "from patchwork.settings.base import *
1664
1665 # Configuration from Guix
1666 with open('" #$secret-key-file "') as f:
1667 SECRET_KEY = f.read().strip()
1668
1669 ALLOWED_HOSTS = [
1670 " #$(string-concatenate
1671 (map (lambda (allowed-host)
1672 (string-append " '" allowed-host "'\n"))
1673 allowed-hosts))
1674 "]
1675
1676 DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
1677
1678 DEFAULT_FROM_EMAIL = '" #$default-from-email "'
1679 SERVER_EMAIL = DEFAULT_FROM_EMAIL
1680 NOTIFICATION_FROM_EMAIL = DEFAULT_FROM_EMAIL
1681
1682 ADMINS = [
1683 " #$(string-concatenate
1684 (map (match-lambda
1685 ((name email-address)
1686 (string-append
1687 "('" name "','" email-address "'),")))
1688 admins))
1689 "]
1690
1691 DEBUG = " #$(if debug? "True" "False") "
1692
1693 ENABLE_REST_API = " #$(if enable-rest-api? "True" "False") "
1694 ENABLE_XMLRPC = " #$(if enable-xmlrpc? "True" "False") "
1695
1696 FORCE_HTTPS_LINKS = " #$(if force-https-links? "True" "False") "
1697
1698 DATABASES = {
1699 'default': {
1700 " #$(match database-configuration
1701 (($ <patchwork-database-configuration>
1702 engine name user password host port)
1703 (string-append
1704 " 'ENGINE': '" engine "',\n"
1705 " 'NAME': '" name "',\n"
1706 " 'USER': '" user "',\n"
1707 " 'PASSWORD': '" password "',\n"
1708 " 'HOST': '" host "',\n"
1709 " 'PORT': '" port "',\n"))) "
1710 },
1711 }
1712
1713 " #$(if debug?
1714 #~(string-append "STATIC_ROOT = '"
1715 #$(file-append patchwork "/share/patchwork/htdocs")
1716 "'")
1717 #~(string-append "STATIC_URL = '" #$static-url "'")) "
1718
1719 STATICFILES_STORAGE = (
1720 'django.contrib.staticfiles.storage.StaticFilesStorage'
1721 )
1722
1723 # Guix Extra Configuration
1724 " #$extra-configuration "
1725 ") port)))
1726 #t))
1727 #:local-build? #t))))
1728
1729 (define patchwork-virtualhost
1730 (match-lambda
1731 (($ <patchwork-configuration> patchwork domain
1732 settings-module static-path
1733 getmail-retriever-config)
1734 (define wsgi.py
1735 (file-append patchwork
1736 (string-append
1737 "/lib/python"
1738 (version-major+minor
1739 (package-version python))
1740 "/site-packages/patchwork/wsgi.py")))
1741
1742 (httpd-virtualhost
1743 "*:8080"
1744 `("ServerAdmin admin@example.com`
1745 ServerName " ,domain "
1746
1747 LogFormat \"%v %h %l %u %t \\\"%r\\\" %>s %b \\\"%{Referer}i\\\" \\\"%{User-Agent}i\\\"\" customformat
1748 LogLevel info
1749 CustomLog \"/var/log/httpd/" ,domain "-access_log\" customformat
1750
1751 ErrorLog /var/log/httpd/error.log
1752
1753 WSGIScriptAlias / " ,wsgi.py "
1754 WSGIDaemonProcess " ,(package-name patchwork) " user=httpd group=httpd processes=1 threads=2 display-name=%{GROUP} lang='en_US.UTF-8' locale='en_US.UTF-8' python-path=" ,settings-module "
1755 WSGIProcessGroup " ,(package-name patchwork) "
1756 WSGIPassAuthorization On
1757
1758 <Files " ,wsgi.py ">
1759 Require all granted
1760 </Files>
1761
1762 " ,@(if static-path
1763 `("Alias " ,static-path " " ,patchwork "/share/patchwork/htdocs/")
1764 '())
1765 "
1766 <Directory \"/srv/http/" ,domain "/\">
1767 AllowOverride None
1768 Options MultiViews Indexes SymlinksIfOwnerMatch IncludesNoExec
1769 Require method GET POST OPTIONS
1770 </Directory>")))))
1771
1772 (define (patchwork-httpd-configuration patchwork-configuration)
1773 (list "WSGISocketPrefix /var/run/mod_wsgi"
1774 (list "LoadModule wsgi_module "
1775 (file-append mod-wsgi "/modules/mod_wsgi.so"))
1776 (patchwork-virtualhost patchwork-configuration)))
1777
1778 (define (patchwork-django-admin-gexp patchwork settings-module)
1779 #~(lambda command
1780 (let ((pid (primitive-fork))
1781 (user (getpwnam "httpd")))
1782 (if (eq? pid 0)
1783 (dynamic-wind
1784 (const #t)
1785 (lambda ()
1786 (setgid (passwd:gid user))
1787 (setuid (passwd:uid user))
1788
1789 (setenv "DJANGO_SETTINGS_MODULE" "guix.patchwork.settings")
1790 (setenv "PYTHONPATH" #$settings-module)
1791 (primitive-exit
1792 (if (zero?
1793 (apply system*
1794 #$(file-append patchwork "/bin/patchwork-admin")
1795 command))
1796 0
1797 1)))
1798 (lambda ()
1799 (primitive-exit 1)))
1800 (zero? (cdr (waitpid pid)))))))
1801
1802 (define (patchwork-django-admin-action patchwork settings-module)
1803 (shepherd-action
1804 (name 'django-admin)
1805 (documentation
1806 "Run a django admin command for patchwork")
1807 (procedure (patchwork-django-admin-gexp patchwork settings-module))))
1808
1809 (define patchwork-shepherd-services
1810 (match-lambda
1811 (($ <patchwork-configuration> patchwork domain
1812 settings-module static-path
1813 getmail-retriever-config)
1814 (define secret-key-file-creation-gexp
1815 (if (patchwork-settings-module? settings-module)
1816 (with-extensions (list guile-gcrypt)
1817 #~(let ((secret-key-file
1818 #$(patchwork-settings-module-secret-key-file
1819 settings-module)))
1820 (use-modules (guix build utils)
1821 (gcrypt random))
1822
1823 (unless (file-exists? secret-key-file)
1824 (mkdir-p (dirname secret-key-file))
1825 (call-with-output-file secret-key-file
1826 (lambda (port)
1827 (display (random-token 30 'very-strong) port)))
1828 (let* ((pw (getpwnam "httpd"))
1829 (uid (passwd:uid pw))
1830 (gid (passwd:gid pw)))
1831 (chown secret-key-file uid gid)
1832 (chmod secret-key-file #o400)))))
1833 #~()))
1834
1835 (list (shepherd-service
1836 (requirement '(postgres))
1837 (provision (list (string->symbol
1838 (string-append (package-name patchwork)
1839 "-setup"))))
1840 (start
1841 #~(lambda ()
1842 (define run-django-admin-command
1843 #$(patchwork-django-admin-gexp patchwork
1844 settings-module))
1845
1846 #$secret-key-file-creation-gexp
1847
1848 (run-django-admin-command "migrate")))
1849 (stop #~(const #f))
1850 (actions
1851 (list (patchwork-django-admin-action patchwork
1852 settings-module)))
1853 (respawn? #f)
1854 (documentation "Setup Patchwork."))))))
1855
1856 (define patchwork-getmail-configs
1857 (match-lambda
1858 (($ <patchwork-configuration> patchwork domain
1859 settings-module static-path
1860 getmail-retriever-config)
1861 (list
1862 (getmail-configuration
1863 (name (string->symbol (package-name patchwork)))
1864 (user "httpd")
1865 (directory (string-append
1866 "/var/lib/getmail/" (package-name patchwork)))
1867 (rcfile
1868 (getmail-configuration-file
1869 (retriever getmail-retriever-config)
1870 (destination
1871 (getmail-destination-configuration
1872 (type "MDA_external")
1873 (path (file-append patchwork "/bin/patchwork-admin"))
1874 (extra-parameters
1875 '((arguments . ("parsemail"))))))
1876 (options
1877 (getmail-options-configuration
1878 (read-all #f)
1879 (delivered-to #f)
1880 (received #f)))))
1881 (idle (assq-ref
1882 (getmail-retriever-configuration-extra-parameters
1883 getmail-retriever-config)
1884 'mailboxes))
1885 (environment-variables
1886 (list "DJANGO_SETTINGS_MODULE=guix.patchwork.settings"
1887 #~(string-append "PYTHONPATH=" #$settings-module))))))))
1888
1889 (define patchwork-service-type
1890 (service-type
1891 (name 'patchwork-setup)
1892 (extensions
1893 (list (service-extension httpd-service-type
1894 patchwork-httpd-configuration)
1895 (service-extension shepherd-root-service-type
1896 patchwork-shepherd-services)
1897 (service-extension getmail-service-type
1898 patchwork-getmail-configs)))
1899 (description
1900 "Patchwork patch tracking system.")))
1901
1902 \f
1903 ;;;
1904 ;;; Mumi.
1905 ;;;
1906
1907 (define-record-type* <mumi-configuration>
1908 mumi-configuration make-mumi-configuration
1909 mumi-configuration?
1910 (mumi mumi-configuration-mumi (default mumi))
1911 (mailer? mumi-configuration-mailer? (default #t))
1912 (sender mumi-configuration-sender (default #f))
1913 (smtp mumi-configuration-smtp (default #f)))
1914
1915 (define %mumi-activation
1916 (with-imported-modules '((guix build utils))
1917 #~(begin
1918 (use-modules (guix build utils))
1919
1920 (mkdir-p "/var/mumi/db")
1921 (mkdir-p "/var/mumi/mails")
1922 (let* ((pw (getpwnam "mumi"))
1923 (uid (passwd:uid pw))
1924 (gid (passwd:gid pw)))
1925 (chown "/var/mumi" uid gid)
1926 (chown "/var/mumi/mails" uid gid)
1927 (chown "/var/mumi/db" uid gid)))))
1928
1929 (define %mumi-accounts
1930 (list (user-group (name "mumi") (system? #t))
1931 (user-account
1932 (name "mumi")
1933 (group "mumi")
1934 (system? #t)
1935 (comment "Mumi web server")
1936 (home-directory "/var/empty")
1937 (shell (file-append shadow "/sbin/nologin")))))
1938
1939 (define %mumi-log "/var/log/mumi.log")
1940
1941 (define %mumi-mailer-log "/var/log/mumi.mailer.log")
1942
1943 (define %mumi-worker-log "/var/log/mumi.worker.log")
1944
1945 (define (mumi-shepherd-services config)
1946 (define environment
1947 #~(list "LC_ALL=en_US.utf8"
1948 (string-append "GUIX_LOCPATH=" #$glibc-utf8-locales
1949 "/lib/locale")))
1950
1951 (match config
1952 (($ <mumi-configuration> mumi mailer? sender smtp)
1953 (list (shepherd-service
1954 (provision '(mumi))
1955 (documentation "Mumi bug-tracking web interface.")
1956 (requirement '(networking))
1957 (start #~(make-forkexec-constructor
1958 `(#$(file-append mumi "/bin/mumi") "web"
1959 ,@(if #$mailer? '() '("--disable-mailer")))
1960 #:environment-variables #$environment
1961 #:user "mumi" #:group "mumi"
1962 #:log-file #$%mumi-log))
1963 (stop #~(make-kill-destructor)))
1964 (shepherd-service
1965 (provision '(mumi-worker))
1966 (documentation "Mumi bug-tracking web interface database worker.")
1967 (requirement '(networking))
1968 (start #~(make-forkexec-constructor
1969 '(#$(file-append mumi "/bin/mumi") "worker")
1970 #:environment-variables #$environment
1971 #:user "mumi" #:group "mumi"
1972 #:log-file #$%mumi-worker-log))
1973 (stop #~(make-kill-destructor)))
1974 (shepherd-service
1975 (provision '(mumi-mailer))
1976 (documentation "Mumi bug-tracking web interface mailer.")
1977 (requirement '(networking))
1978 (start #~(make-forkexec-constructor
1979 `(#$(file-append mumi "/bin/mumi") "mailer"
1980 ,@(if #$sender
1981 (list (string-append "--sender=" #$sender))
1982 '())
1983 ,@(if #$smtp
1984 (list (string-append "--smtp=" #$smtp))
1985 '()))
1986 #:environment-variables #$environment
1987 #:user "mumi" #:group "mumi"
1988 #:log-file #$%mumi-mailer-log))
1989 (stop #~(make-kill-destructor)))))))
1990
1991 (define %mumi-log-rotations
1992 (list (log-rotation
1993 (files (list %mumi-log
1994 %mumi-mailer-log
1995 %mumi-worker-log)))))
1996
1997 (define mumi-service-type
1998 (service-type
1999 (name 'mumi)
2000 (extensions
2001 (list (service-extension activation-service-type
2002 (const %mumi-activation))
2003 (service-extension account-service-type
2004 (const %mumi-accounts))
2005 (service-extension shepherd-root-service-type
2006 mumi-shepherd-services)
2007 (service-extension rottlog-service-type
2008 (const %mumi-log-rotations))))
2009 (description
2010 "Run Mumi, a Web interface to the Debbugs bug-tracking server.")
2011 (default-value
2012 (mumi-configuration))))
2013
2014 (define %default-gmnisrv-config-file
2015 (plain-file "gmnisrv.ini" "
2016 listen=0.0.0.0:1965 [::]:1965
2017
2018 [:tls]
2019 store=/var/lib/gemini/certs
2020
2021 organization=gmnisrv on Guix user
2022
2023 [localhost]
2024 root=/srv/gemini
2025 "))
2026
2027 (define-record-type* <gmnisrv-configuration>
2028 gmnisrv-configuration make-gmnisrv-configuration
2029 gmnisrv-configuration?
2030 (package gmnisrv-configuration-package
2031 (default gmnisrv))
2032 (config-file gmnisrv-configuration-config-file
2033 (default %default-gmnisrv-config-file)))
2034
2035 (define gmnisrv-shepherd-service
2036 (match-lambda
2037 (($ <gmnisrv-configuration> package config-file)
2038 (list (shepherd-service
2039 (provision '(gmnisrv))
2040 (requirement '(networking))
2041 (documentation "Run the gmnisrv Gemini server.")
2042 (start (let ((gmnisrv (file-append package "/bin/gmnisrv")))
2043 #~(make-forkexec-constructor
2044 (list #$gmnisrv "-C" #$config-file)
2045 #:user "gmnisrv" #:group "gmnisrv"
2046 #:log-file "/var/log/gmnisrv.log")))
2047 (stop #~(make-kill-destructor)))))))
2048
2049 (define %gmnisrv-accounts
2050 (list (user-group (name "gmnisrv") (system? #t))
2051 (user-account
2052 (name "gmnisrv")
2053 (group "gmnisrv")
2054 (system? #t)
2055 (comment "gmnisrv Gemini server")
2056 (home-directory "/var/empty")
2057 (shell (file-append shadow "/sbin/nologin")))))
2058
2059 (define %gmnisrv-activation
2060 (with-imported-modules '((guix build utils))
2061 #~(begin
2062 (use-modules (guix build utils))
2063
2064 (mkdir-p "/var/lib/gemini/certs")
2065 (let* ((pw (getpwnam "gmnisrv"))
2066 (uid (passwd:uid pw))
2067 (gid (passwd:gid pw)))
2068 (chown "/var/lib/gemini" uid gid)
2069 (chown "/var/lib/gemini/certs" uid gid)))))
2070
2071 (define gmnisrv-service-type
2072 (service-type
2073 (name 'guix)
2074 (extensions
2075 (list (service-extension activation-service-type
2076 (const %gmnisrv-activation))
2077 (service-extension account-service-type
2078 (const %gmnisrv-accounts))
2079 (service-extension shepherd-root-service-type
2080 gmnisrv-shepherd-service)))
2081 (description
2082 "Run the gmnisrv Gemini server.")
2083 (default-value
2084 (gmnisrv-configuration))))
2085
2086 (define-record-type* <agate-configuration>
2087 agate-configuration make-agate-configuration
2088 agate-configuration?
2089 (package agate-configuration-package
2090 (default agate))
2091 (content agate-configuration-content
2092 (default "/srv/gemini"))
2093 (cert agate-configuration-cert
2094 (default #f))
2095 (key agate-configuration-key
2096 (default #f))
2097 (addr agate-configuration-addr
2098 (default '("0.0.0.0:1965" "[::]:1965")))
2099 (hostname agate-configuration-hostname
2100 (default #f))
2101 (lang agate-configuration-lang
2102 (default #f))
2103 (silent? agate-configuration-silent
2104 (default #f))
2105 (serve-secret? agate-configuration-serve-secret
2106 (default #f))
2107 (log-ip? agate-configuration-log-ip
2108 (default #t))
2109 (user agate-configuration-user
2110 (default "agate"))
2111 (group agate-configuration-group
2112 (default "agate"))
2113 (log-file agate-configuration-log
2114 (default "/var/log/agate.log")))
2115
2116 (define agate-shepherd-service
2117 (match-lambda
2118 (($ <agate-configuration> package content cert key addr
2119 hostname lang silent? serve-secret?
2120 log-ip? user group log-file)
2121 (list (shepherd-service
2122 (provision '(agate))
2123 (requirement '(networking))
2124 (documentation "Run the agate Gemini server.")
2125 (start (let ((agate (file-append package "/bin/agate")))
2126 #~(make-forkexec-constructor
2127 (list #$agate
2128 "--content" #$content
2129 "--cert" #$cert
2130 "--key" #$key
2131 "--addr" #$@addr
2132 #$@(if lang
2133 (list "--lang" lang)
2134 '())
2135 #$@(if hostname
2136 (list "--hostname" hostname)
2137 '())
2138 #$@(if silent? '("--silent") '())
2139 #$@(if serve-secret? '("--serve-secret") '())
2140 #$@(if log-ip? '("--log-ip") '()))
2141 #:user #$user #:group #$group
2142 #:log-file #$log-file)))
2143 (stop #~(make-kill-destructor)))))))
2144
2145 (define agate-accounts
2146 (match-lambda
2147 (($ <agate-configuration> _ _ _ _ _
2148 _ _ _ _
2149 _ user group _)
2150 `(,@(if (equal? group "agate")
2151 '()
2152 (list (user-group (name "agate") (system? #t))))
2153 ,(user-group
2154 (name group)
2155 (system? #t))
2156 ,(user-account
2157 (name user)
2158 (group group)
2159 (supplementary-groups '("agate"))
2160 (system? #t)
2161 (comment "agate server user")
2162 (home-directory "/var/empty")
2163 (shell (file-append shadow "/sbin/nologin")))))))
2164
2165 (define agate-service-type
2166 (service-type
2167 (name 'agate)
2168 (extensions
2169 (list (service-extension account-service-type
2170 agate-accounts)
2171 (service-extension shepherd-root-service-type
2172 agate-shepherd-service)))
2173 (default-value (agate-configuration))
2174 (description "Run Agate, a simple Gemini protocol server written in
2175 Rust.")))