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