From patchwork Wed Sep 29 00:46:33 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: jgart X-Patchwork-Id: 33411 Return-Path: X-Original-To: patchwork@mira.cbaines.net Delivered-To: patchwork@mira.cbaines.net Received: by mira.cbaines.net (Postfix, from userid 113) id 4E20E27BBE1; Wed, 29 Sep 2021 01:47:31 +0100 (BST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on mira.cbaines.net X-Spam-Level: X-Spam-Status: No, score=-2.8 required=5.0 tests=BAYES_00,DKIM_SIGNED, MAILING_LIST_MULTI,RCVD_IN_MSPIKE_H2,SPF_HELO_PASS,T_DKIM_INVALID, URIBL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.2 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mira.cbaines.net (Postfix) with ESMTPS id 7A48827BBE3 for ; Wed, 29 Sep 2021 01:47:30 +0100 (BST) Received: from localhost ([::1]:45186 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1mVNkv-00046R-JA for patchwork@mira.cbaines.net; Tue, 28 Sep 2021 20:47:29 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:41720) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mVNkV-00046I-EF for guix-patches@gnu.org; Tue, 28 Sep 2021 20:47:03 -0400 Received: from debbugs.gnu.org ([209.51.188.43]:35771) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1mVNkU-0006i1-AI for guix-patches@gnu.org; Tue, 28 Sep 2021 20:47:03 -0400 Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1mVNkU-0005fD-0H for guix-patches@gnu.org; Tue, 28 Sep 2021 20:47:02 -0400 X-Loop: help-debbugs@gnu.org Subject: [bug#50882] [PATCH] services: Add darkhttpd service. References: <20210928203838.GB15388@gac.attlocal.net> In-Reply-To: <20210928203838.GB15388@gac.attlocal.net> Resent-From: jgart Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Wed, 29 Sep 2021 00:47:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 50882 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 50882@debbugs.gnu.org Cc: jgart Received: via spool by 50882-submit@debbugs.gnu.org id=B50882.163287641621760 (code B ref 50882); Wed, 29 Sep 2021 00:47:01 +0000 Received: (at 50882) by debbugs.gnu.org; 29 Sep 2021 00:46:56 +0000 Received: from localhost ([127.0.0.1]:47317 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mVNkN-0005eu-ON for submit@debbugs.gnu.org; Tue, 28 Sep 2021 20:46:56 -0400 Received: from mx1.dismail.de ([78.46.223.134]:10822) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mVNkL-0005ef-8Y for 50882@debbugs.gnu.org; Tue, 28 Sep 2021 20:46:54 -0400 Received: from mx1.dismail.de (localhost [127.0.0.1]) by mx1.dismail.de (OpenSMTPD) with ESMTP id 026d1b98 for <50882@debbugs.gnu.org>; Wed, 29 Sep 2021 02:46:46 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed; d=dismail.de; h=from:to:cc :subject:date:message-id:mime-version:content-transfer-encoding; s=20190914; bh=TcDiRlXt7iTU5zq+KI6fryf2C98W7j7PxftLMZG00+c=; b= t4vC9KMK3B2VhtPrqb7/rGBAWss2TrvUeRvNgdZIeCUovJKpFVIQ/JEq1gnWKH6C xvOdsOJ4rU1w2J+21GtUARN+F3STz/9jtP6D7DneyuBxp+gaU2J+HBtyMK/lZ01l jqut9MzfWuYSRMQhnVrEtMcI3oYw18sPxwKLltX9WxTlHyp6dQyyR7qrsax/dGsh OYZ7sg2s7u3zMo4bYYL/jcKdGs19ZFPvbNUHquLEZySEJqGlqnAAEuqPqCEfMXvc 6Kb1ywzzTjOSPCI40bqMFP0/X/lRRqr0oD6E60bv9gsvUZog2kw/k4hZrXLRqKiY eQXyXy9uPSBO/ydW7I8MdA== Received: from smtp2.dismail.de ( [10.240.26.12]) by mx1.dismail.de (OpenSMTPD) with ESMTP id ec1e5c74 for <50882@debbugs.gnu.org>; Wed, 29 Sep 2021 02:46:46 +0200 (CEST) Received: from smtp2.dismail.de (localhost [127.0.0.1]) by smtp2.dismail.de (OpenSMTPD) with ESMTP id 4f2c1fb1 for <50882@debbugs.gnu.org>; Wed, 29 Sep 2021 02:46:46 +0200 (CEST) Received: by dismail.de (OpenSMTPD) with ESMTPSA id 731f5f71 (TLSv1.3:AEAD-AES256-GCM-SHA384:256:NO); Wed, 29 Sep 2021 02:46:45 +0200 (CEST) Date: Tue, 28 Sep 2021 20:46:33 -0400 Message-Id: <20210929004633.17158-1-jgart@dismail.de> X-Mailer: git-send-email 2.33.0 MIME-Version: 1.0 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: guix-patches@gnu.org List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guix-patches-bounces+patchwork=mira.cbaines.net@gnu.org Sender: "Guix-patches" Reply-to: jgart X-ACL-Warn: , jgart via Guix-patches X-Patchwork-Original-From: jgart via Guix-patches via From: jgart X-getmail-retrieved-from-mailbox: Patches * gnu/services/web.scm (): New record type. (darkhttpd-accounts, darkhttpd-shepherd-service): New procedures. (darkhttpd-service-type): New variable. * doc/guix.texi (Web Services): Adds documentation for darkhttpd. --- doc/guix.texi | 124 +++++++++++++++++++++++++++++ gnu/services/web.scm | 184 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 306 insertions(+), 2 deletions(-) diff --git a/doc/guix.texi b/doc/guix.texi index 3124ed2ef8..6f22edba2e 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -26259,6 +26259,130 @@ The file which should store the logging output of Agate. @end table @end deftp +@subsubheading darkhttpd + +@cindex darkhttpd +@uref{https://unix4lyfe.org/darkhttpd/, darkhttpd} is a web server with a +focus on security and having a small memory footprint. + +Some security features are the following: + +@itemize +@item Logging accesses, including Referer and User-Agent. +@item Can chroot. +@item Can drop privileges. +@item Impervious to /../ sniffing. +@item Times out idle connections. +@item Drops overly long requests. +@end itemize + +@deffn {Scheme Variable} darkhttpd-service-type +This is the type of the darkhttpd service, whose value should be a +@code{darkhttpd-service-type} object, as in this example: + +@lisp +(service darkhttpd-service-type + (darkhttpd-configuration + (content "/var/www/localhost/blog") + (port 4567) + (no-server-id? #t) + (enable-ipv6? #t) + (chroot? #f))) +@end lisp + +The example above shows @code{content} directory modified as +well as @code{port}, @code{no-server-id?}, and @code{enable-ipv6?} +enabled and @code{chroot?} disabled. + +A minimal config might look like the following: + +@lisp +(service darkhttpd-service-type) +@end lisp + +@deftp {Data Type} darkhttpd-configuration +Data type representing the configuration of darkhttpd. + +@table @asis +@item @code{package} (default: @code{darkhttpd}) +The package object of the darkhttpd server. + +@item @code{content} (default: @file{"/srv/gemini"}) +The directory from which Agate will serve files. + +@item @code{port} (default: @code{"80"}) +Specifies which port to listen on for connections. +Assign 0 to let the system choose any free port for you. + +@item @code{address} (default: @code{"all"}) +If multiple interfaces are present, specifies +which one to bind the listening port to. + +@item @code{maximum-connections} (default: @code{#f}) +Specifies how many concurrent connections to accept. + +@item @code{log-file} (default: @file{"/var/log/darkhttpd.log"}) +The file which should store the logging output of @code{darkhttpd}. + +@item @code{chroot?} (default: @code{#t}) +Locks the web server into the content directory for added security. + +@item @code{daemonize?} (default: @code{#t}) +Detach from the controlling terminal and run in the background. + +@item @code{index-file} (default: @code{"index.html"}) +Default file to serve when a directory is requested. + +@item @code{do-not-serve-listing?} (default: @code{#f}) +Do not serve listing if directory is requested. + +@item @code{mimetypes} (default: @code{#f}) +This option is optional. @code{mimetypes} parses the +specified file for extension-MIME associations. + +@item @code{default-mimetype} (default: @code{"application/octet-stream"}) +Files with unknown extensions are served as this mimetype. + +@item @code{drop-user-privileges?} (default: @code{#t}) +Drops privileges to given uid after initialization. + +@item @code{drop-group-privileges?} (default: @code{#t}) +Drops privileges to given gid after initialization. + +@item @code{write-pid-file} (default: @code{#f}) +Write PID to the specified file. Note that if you are +using @{chroot?}, then the pidfile will be set relative +to the directory set with the @{content} option. + +@item @code{disable-keep-alive?} (default: @code{#f}) +Disables HTTP Keep-Alive functionality. + +@item @code{forward} (default: @code{#f}) +By default, @{darkhttpd} does not forward requests. +This option allows requests to the host to be redirected +to the corresponding url given as an argument. +@{forward} may be specified multiple times, in which case +the host is matched in order of appearance. + +@item @code{forward-all} (default: @code{#f}) +@{forward-all} is similar to @{forward} but all +requests are redirected to the url given as an argument. + +@item @code{no-server-id?} (default: @code{#f}) +Do not identify the server type in headers or +directory listings. + +@item @code{enable-ipv6?} (default: @code{#f}) +Listen on IPv6 address. + +@item @code{user} (default: @code{"darkhttpd"}) +Owner of the @code{darkhttpd} process. + +@item @code{group} (default: @code{"darkhttpd"}) +Owner's group of the @code{darkhttpd} process. + +@end table +@end deftp @node Certificate Services @subsection Certificate Services diff --git a/gnu/services/web.scm b/gnu/services/web.scm index bb42eacf83..68afba3cad 100644 --- a/gnu/services/web.scm +++ b/gnu/services/web.scm @@ -281,8 +281,35 @@ agate-configuration-group agate-configuration-log-file - agate-service-type)) - + agate-service-type + + darkhttpd-configuration + darkhttpd-configuration? + darkhttpd-configuration-package + darkhttpd-configuration-content + darkhttpd-configuration-port + darkhttpd-configuration-address + darkhttpd-configuration-maximum-connections + darkhttpd-configuration-log-file + darkhttpd-configuration-chroot + darkhttpd-configuration-daemonize + darkhttpd-configuration-index-file + darkhttpd-configuration-do-not-serve-listing + darkhttpd-configuration-mimetypes + darkhttpd-configuration-default-mimetype + darkhttpd-configuration-drop-user-privileges + darkhttpd-configuration-drop-group-privileges + darkhttpd-configuration-write-pid-file + darkhttpd-configuration-disable-keep-alive + darkhttpd-configuration-forward + darkhttpd-configuration-forward-all + darkhttpd-configuration-no-server-id + darkhttpd-configuration-enable-ipv6 + darkhttpd-configuration-user + darkhttpd-configuration-group + + darkhttpd-service-type)) + ;;; Commentary: ;;; ;;; Web services. @@ -1993,3 +2020,156 @@ root=/srv/gemini (service-extension shepherd-root-service-type agate-shepherd-service))) (default-value (agate-configuration)))) + +(define-record-type* + darkhttpd-configuration make-darkhttpd-configuration + darkhttpd-configuration? + (package darkhttpd-configuration-package + (default darkhttpd)) + (content darkhttpd-configuration-content + (default "/var/www/localhost/htdocs")) + (port darkhttpd-configuration-port + (default "80")) + (address darkhttpd-configuration-address + (default "all")) + (maximum-connections darkhttpd-configuration-maximum-connections + (default #f)) + (log-file darkhttpd-configuration-log-file + (default "access.log")) + (chroot? darkhttpd-configuration-chroot + (default #t)) + (daemonize? darkhttpd-configuration-daemonize + (default #t)) + (index-file darkhttpd-configuration-index-file + (default "index.html")) + (do-not-serve-listing? darkhttpd-configuration-do-not-serve-listing + (default #f)) + (mimetypes darkhttpd-configuration-mimetypes + (default #f)) + (default-mimetype darkhttpd-configuration-default-mimetype + (default "application/octet-stream")) + (drop-user-privileges? darkhttpd-configuration-drop-user-privileges + (default #t)) + (drop-group-privileges? darkhttpd-configuration-drop-group-privileges + (default #t)) + (write-pid-file darkhttpd-configuration-write-pid-file + (default #f)) + (disable-keep-alive? darkhttpd-configuration-disable-keep-alive + (default #f)) + (forward darkhttpd-configuration-forward + (default #f)) + (forward-all darkhttpd-configuration-forward-all + (default #f)) + (no-server-id? darkhttpd-configuration-no-server-id + (default #f)) + (enable-ipv6? darkhttpd-configuration-enable-ipv6 + (default #f)) + (user darkhttpd-configuration-user + (default "darkhttpd")) + (group darkhttpd-configuration-group + (default "www-data"))) + +(define darkhttpd-shepherd-service + (match-lambda + (($ package content port address + maximum-connections log-file chroot? + daemonize? index-file do-not-serve-listing? + mimetypes default-mimetype + drop-user-priviledges drop-group-priviledges + write-pid-file disable-keep-alive? + forward forward-all + no-server-id? enable-ipv6? + user group) + (list (shepherd-service + (provision '(darkhttpd)) + (requirement '(networking)) + (documentation "Run the darkhttpd web server.") + (start (let ((darkhttpd (file-append package "/bin/darkhttpd"))) + #~(make-forkexec-constructor + (list #$darkhttpd + #$content + #$@(if port + (list "--port" (number->string port)) + '()) + #$@(if address + (list "--addr" address) + '()) + #$@(if maximum-connections + (list "--maxconn" maximum-connections) + '()) + #$@(if log-file + (list "--log" + (string-append "/var/log/darkhttpd/" + log-file) + '())) + #$@(if chroot? '("--chroot") '()) + #$@(if daemonize? '("--daemon") '()) + #$@(if index-file + (list "--index" index-file) + '()) + #$@(if do-not-serve-listing? + (list "--no-listing" + do-not-serve-listing?) + '()) + #$@(if mimetypes '("--mimetypes" mimetypes) '()) + #$@(if default-mimetype + (list "--default-mimetype" + default-mimetype) + '()) + #$@(if drop-user-privileges? + '("--uid" user) '()) + #$@(if drop-group-privileges? + '("--gid" group) '()) + ;; if using --chroot, then the pidfile must be + ;; relative to, and inside the wwwroot. + #$@(if write-pid-file + "--pidfile" + (if (and chroot? write-pid-file) + '(string-append content + "/" + write-pid-file) + write-pid-file) + '()) + #$@(if disable-keep-alive? + (list "--no-keepalive" + disable-keep-alive?) + '()) + #$@(if forward '("--forward" forward) '()) + #$@(if forward-all + (list "--forward-all" forward-all) + '()) + #$@(if no-server-id? '("--no-server-id") '()) + #$@(if enable-ipv6? '("--ipv6") '()) + #:user #$user #:group #$group)))) + (stop #~(make-kill-destructor))))))) + +(define darkhttpd-accounts + (match-lambda + (($ _ _ _ _ _ _ _ _ + _ _ _ _ _ _ _ _ + _ _ user group) + `(,@(if (equal? group "darkhttpd") + '() + (list (user-group (name "darkhttpd") (system? #t)))) + ,(user-group + (name group) + (system? #t)) + ,(user-account + (name user) + (group group) + (supplementary-groups '("darkhttpd")) + (system? #t) + (comment "darkhttpd server user") + (home-directory "/var/empty") + (shell (file-append shadow "/sbin/nologin"))))))) + +(define darkhttpd-service-type + (service-type + (name 'guix) + (extensions + (list (service-extension account-service-type + darkhttpd-accounts) + (service-extension shepherd-root-service-type + darkhttpd-shepherd-service))) + (default-value (darkhttpd-configuration)))) +