services: Add Agate Gemini service.

* gnu/services/web.scm (<agate-configuration>): New record type.
(agate-accounts, agate-shepherd-service): New procedures.
(agate-service-type): New variable.
* doc/guix.texi (Web Services): Document it.

Signed-off-by: Nicolas Goaziou <mail@nicolasgoaziou.fr>
This commit is contained in:
Alexandru-Sergiu Marton 2021-02-14 20:57:31 +02:00 committed by Nicolas Goaziou
parent c1ee055cba
commit 2b5a81dfd3
No known key found for this signature in database
GPG Key ID: DA00B4F048E92F2D
2 changed files with 198 additions and 3 deletions

@ -81,7 +81,7 @@ Copyright @copyright{} 2020 R Veera Kumar@*
Copyright @copyright{} 2020 Pierre Langlois@*
Copyright @copyright{} 2020 pinoaffe@*
Copyright @copyright{} 2020 André Batista@*
Copyright @copyright{} 2020 Alexandru-Sergiu Marton@*
Copyright @copyright{} 2020, 2021 Alexandru-Sergiu Marton@*
Copyright @copyright{} 2020 raingloom@*
Copyright @copyright{} 2020 Daniel Brooks@*
Copyright @copyright{} 2020 John Soo@*
@ -25322,6 +25322,93 @@ gmnisrv} and @command{man gmnisrv.ini}.
@end table
@end deftp
@subsubheading Agate
@cindex agate
The @uref{gemini://qwertqwefsday.eu/agate.gmi, Agate}
(@uref{https://github.com/mbrubeck/agate, GitHub page over HTTPS})
program is a simple @uref{https://gemini.circumlunar.space/, Gemini}
protocol server written in Rust.
@deffn {Scheme Variable} agate-service-type
This is the type of the agate service, whose value should be an
@code{agate-service-type} object, as in this example:
@lisp
(service agate-service-type
(agate-configuration
(content "/srv/gemini")
(cert "/srv/cert.pem")
(key "/srv/key.rsa")))
@end lisp
The example above represents the minimal tweaking necessary to get Agate
up and running. Specifying the path to the certificate and key is
always necessary, as the Gemini protocol requires TLS by default.
To obtain a certificate and a key, you could, for example, use OpenSSL,
running a command similar to the following example:
@example
openssl req -x509 -newkey rsa:4096 -keyout key.rsa -out cert.pem \
-days 3650 -nodes -subj "/CN=example.com"
@end example
Of course, you'll have to replace @i{example.com} with your own domain
name, and then point the Agate configuration towards the path of the
generated key and certificate.
@end deffn
@deftp {Data Type} agate-configuration
Data type representing the configuration of Agate.
@table @asis
@item @code{package} (default: @code{agate})
The package object of the Agate server.
@item @code{content} (default: @file{"/srv/gemini"})
The directory from which Agate will serve files.
@item @code{cert} (default: @code{#f})
The path to the TLS certificate PEM file to be used for encrypted
connections. Must be filled in with a value from the user.
@item @code{key} (default: @code{#f})
The path to the PKCS8 private key file to be used for encrypted
connections. Must be filled in with a value from the user.
@item @code{addr} (default: @code{'("0.0.0.0:1965" "[::]:1965")})
A list of the addresses to listen on.
@item @code{hostname} (default: @code{#f})
The domain name of this Gemini server. Optional.
@item @code{lang} (default: @code{#f})
RFC 4646 language code(s) for text/gemini documents. Optional.
@item @code{silent?} (default: @code{#f})
Set to @code{#t} to disable logging output.
@item @code{serve-secret?} (default: @code{#f})
Set to @code{#t} to serve secret files (files/directories starting with
a dot).
@item @code{log-ip?} (default: @code{#t})
Whether or not to output IP addresses when logging.
@item @code{user} (default: @code{"agate"})
Owner of the @code{agate} process.
@item @code{group} (default: @code{"agate"})
Owner's group of the @code{agate} process.
@item @code{log-file} (default: @file{"/var/log/agate.log"})
The file which should store the logging output of Agate.
@end table
@end deftp
@node Certificate Services
@subsection Certificate Services

@ -14,7 +14,7 @@
;;; Copyright © 2020 Tobias Geerinckx-Rice <me@tobias.gr>
;;; Copyright © 2020 Arun Isaac <arunisaac@systemreboot.net>
;;; Copyright © 2020 Oleg Pykhalov <go.wigust@gmail.com>
;;; Copyright © 2020 Alexandru-Sergiu Marton <brown121407@posteo.ro>
;;; Copyright © 2020, 2021 Alexandru-Sergiu Marton <brown121407@posteo.ro>
;;;
;;; This file is part of GNU Guix.
;;;
@ -50,6 +50,7 @@
#:use-module (gnu packages guile)
#:use-module (gnu packages logging)
#:use-module (gnu packages mail)
#:use-module (gnu packages rust-apps)
#:use-module (guix packages)
#:use-module (guix records)
#:use-module (guix modules)
@ -263,7 +264,25 @@
gmnisrv-configuration-package
gmnisrv-configuration-config-file
gmnisrv-service-type))
gmnisrv-service-type
agate-configuration
agate-configuration?
agate-configuration-package
agate-configuration-content
agate-configuration-cert
agate-configuration-key
agate-configuration-addr
agate-configuration-hostname
agate-configuration-lang
agate-configuration-silent
agate-configuration-serve-secret
agate-configuration-log-ip
agate-configuration-user
agate-configuration-group
agate-configuration-log-file
agate-service-type))
;;; Commentary:
;;;
@ -1885,3 +1904,92 @@ root=/srv/gemini
"Run the gmnisrv Gemini server.")
(default-value
(gmnisrv-configuration))))
(define-record-type* <agate-configuration>
agate-configuration make-agate-configuration
agate-configuration?
(package agate-configuration-package
(default agate))
(content agate-configuration-content
(default "/srv/gemini"))
(cert agate-configuration-cert
(default #f))
(key agate-configuration-key
(default #f))
(addr agate-configuration-addr
(default '("0.0.0.0:1965" "[::]:1965")))
(hostname agate-configuration-hostname
(default #f))
(lang agate-configuration-lang
(default #f))
(silent? agate-configuration-silent
(default #f))
(serve-secret? agate-configuration-serve-secret
(default #f))
(log-ip? agate-configuration-log-ip
(default #t))
(user agate-configuration-user
(default "agate"))
(group agate-configuration-group
(default "agate"))
(log-file agate-configuration-log
(default "/var/log/agate.log")))
(define agate-shepherd-service
(match-lambda
(($ <agate-configuration> package content cert key addr
hostname lang silent? serve-secret?
log-ip? user group log-file)
(list (shepherd-service
(provision '(agate))
(requirement '(networking))
(documentation "Run the agate Gemini server.")
(start (let ((agate (file-append package "/bin/agate")))
#~(make-forkexec-constructor
(list #$agate
"--content" #$content
"--cert" #$cert
"--key" #$key
"--addr" #$@addr
#$@(if lang
(list "--lang" lang)
'())
#$@(if hostname
(list "--hostname" hostname)
'())
#$@(if silent? '("--silent") '())
#$@(if serve-secret? '("--serve-secret") '())
#$@(if log-ip? '("--log-ip") '()))
#:user #$user #:group #$group
#:log-file #$log-file)))
(stop #~(make-kill-destructor)))))))
(define agate-accounts
(match-lambda
(($ <agate-configuration> _ _ _ _ _
_ _ _ _
_ user group _)
`(,@(if (equal? group "agate")
'()
(list (user-group (name "agate") (system? #t))))
,(user-group
(name group)
(system? #t))
,(user-account
(name user)
(group group)
(supplementary-groups '("agate"))
(system? #t)
(comment "agate server user")
(home-directory "/var/empty")
(shell (file-append shadow "/sbin/nologin")))))))
(define agate-service-type
(service-type
(name 'guix)
(extensions
(list (service-extension account-service-type
agate-accounts)
(service-extension shepherd-root-service-type
agate-shepherd-service)))
(default-value (agate-configuration))))