diff mbox series

[bug#50882] services: Add darkhttpd service.

Message ID 20210929004633.17158-1-jgart@dismail.de
State Accepted
Headers show
Series [bug#50882] services: Add darkhttpd service. | expand

Checks

Context Check Description
cbaines/comparison success View comparision
cbaines/git branch success View Git branch
cbaines/applying patch success View Laminar job
cbaines/issue success View issue
cbaines/comparison success View comparision
cbaines/git branch success View Git branch
cbaines/applying patch success View Laminar job
cbaines/issue success View issue
cbaines/comparison success View comparision
cbaines/git branch success View Git branch
cbaines/applying patch success View Laminar job
cbaines/issue success View issue
cbaines/comparison success View comparision
cbaines/git branch success View Git branch
cbaines/applying patch success View Laminar job
cbaines/issue success View issue
cbaines/comparison success View comparision
cbaines/git branch success View Git branch
cbaines/applying patch success View Laminar job
cbaines/issue success View issue

Commit Message

jgart Sept. 29, 2021, 12:46 a.m. UTC
* gnu/services/web.scm (<darkhttpd-configuration>): 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(-)

Comments

Ludovic Courtès Oct. 25, 2021, 12:32 p.m. UTC | #1
Hi,

jgart <jgart@dismail.de> skribis:

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

Overall LGTM!  Some comments and suggestions below.

> +@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 

I’d replace the bullet list with a simple sentence like: “Among other
things, it can change root directories, drop privileges, it times out on
idle connections and can drop overly long requests.”

> +@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

Please don’t use tabs.

> +@end table
> +@end deftp
>  @node Certificate Services

Missing newline before @node.  :-)

> +  (mimetypes               darkhttpd-configuration-mimetypes
> +                           (default #f))
> +  (default-mimetype        darkhttpd-configuration-default-mimetype

Rather ‘mime-type’ (two words).

> +(define darkhttpd-shepherd-service
> +  (match-lambda
> +    (($ <darkhttpd-configuration> 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)

Rather use ‘match-record’ here, to make sure we’re getting the right
fields.

> +(define darkhttpd-accounts
> +  (match-lambda
> +    (($ <darkhttpd-configuration> _ _ _ _ _ _ _ _ 
> +                                  _ _ _ _ _ _ _ _ 
> +                                  _ _ user group)

In such a case, simply call ‘darkhttpd-configuration-user’ and
‘darkhttpd-configuration-group’; it’s much less error-prone!

> +(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))))

Please add a ‘description’ field.

Could you also add a system test, under (gnu tests web)?  You can start
by copying the nginx test; it should take around ~20 lines.

TIA!

Ludo’.
Maxim Cournoyer July 7, 2022, 6:02 p.m. UTC | #2
tag 50882 moreinfo
thanks

Hello jgart,

Ludovic Courtès <ludo@gnu.org> writes:

> Hi,
>
> jgart <jgart@dismail.de> skribis:
>
>> * gnu/services/web.scm (<darkhttpd-configuration>): New record type.
>> (darkhttpd-accounts, darkhttpd-shepherd-service): New procedures.
>> (darkhttpd-service-type): New variable.
>> * doc/guix.texi (Web Services): Adds documentation for darkhttpd.
>
> Overall LGTM!  Some comments and suggestions below.
>
>> +@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 
>
> I’d replace the bullet list with a simple sentence like: “Among other
> things, it can change root directories, drop privileges, it times out on
> idle connections and can drop overly long requests.”
>
>> +@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
>
> Please don’t use tabs.
>
>> +@end table
>> +@end deftp
>>  @node Certificate Services
>
> Missing newline before @node.  :-)
>
>> +  (mimetypes               darkhttpd-configuration-mimetypes
>> +                           (default #f))
>> +  (default-mimetype        darkhttpd-configuration-default-mimetype
>
> Rather ‘mime-type’ (two words).
>
>> +(define darkhttpd-shepherd-service
>> +  (match-lambda
>> +    (($ <darkhttpd-configuration> 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)
>
> Rather use ‘match-record’ here, to make sure we’re getting the right
> fields.
>
>> +(define darkhttpd-accounts
>> +  (match-lambda
>> +    (($ <darkhttpd-configuration> _ _ _ _ _ _ _ _ 
>> +                                  _ _ _ _ _ _ _ _ 
>> +                                  _ _ user group)
>
> In such a case, simply call ‘darkhttpd-configuration-user’ and
> ‘darkhttpd-configuration-group’; it’s much less error-prone!
>
>> +(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))))
>
> Please add a ‘description’ field.
>
> Could you also add a system test, under (gnu tests web)?  You can start
> by copying the nginx test; it should take around ~20 lines.

Friendly ping about the above requests from Ludovic :-).

Thanks,

Maxim
jgart July 8, 2022, 12:20 a.m. UTC | #3
On Thu, 07 Jul 2022 14:02:36 -0400 Maxim Cournoyer <maxim.cournoyer@gmail.com> wrote:
> tag 50882 moreinfo
> thanks
> 
> Hello jgart,
> 
> Ludovic Courtès <ludo@gnu.org> writes:
> 
> > Hi,
> >
> > jgart <jgart@dismail.de> skribis:
> >
> >> * gnu/services/web.scm (<darkhttpd-configuration>): New record type.
> >> (darkhttpd-accounts, darkhttpd-shepherd-service): New procedures.
> >> (darkhttpd-service-type): New variable.
> >> * doc/guix.texi (Web Services): Adds documentation for darkhttpd.
> >
> > Overall LGTM!  Some comments and suggestions below.
> >
> >> +@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 
> >
> > I’d replace the bullet list with a simple sentence like: “Among other
> > things, it can change root directories, drop privileges, it times out on
> > idle connections and can drop overly long requests.”
> >
> >> +@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
> >
> > Please don’t use tabs.
> >
> >> +@end table
> >> +@end deftp
> >>  @node Certificate Services
> >
> > Missing newline before @node.  :-)
> >
> >> +  (mimetypes               darkhttpd-configuration-mimetypes
> >> +                           (default #f))
> >> +  (default-mimetype        darkhttpd-configuration-default-mimetype
> >
> > Rather ‘mime-type’ (two words).
> >
> >> +(define darkhttpd-shepherd-service
> >> +  (match-lambda
> >> +    (($ <darkhttpd-configuration> 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)
> >
> > Rather use ‘match-record’ here, to make sure we’re getting the right
> > fields.
> >
> >> +(define darkhttpd-accounts
> >> +  (match-lambda
> >> +    (($ <darkhttpd-configuration> _ _ _ _ _ _ _ _ 
> >> +                                  _ _ _ _ _ _ _ _ 
> >> +                                  _ _ user group)
> >
> > In such a case, simply call ‘darkhttpd-configuration-user’ and
> > ‘darkhttpd-configuration-group’; it’s much less error-prone!
> >
> >> +(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))))
> >
> > Please add a ‘description’ field.
> >
> > Could you also add a system test, under (gnu tests web)?  You can start
> > by copying the nginx test; it should take around ~20 lines.
> 
> Friendly ping about the above requests from Ludovic :-).

Arun Isaac convinced me to not write a service for this one since it's
common usage is for quick serving by simply running `darkhttpd ...` from
the command line. I think that guile bindings for every CLI feature of
darkhttpd doesn't add to that aim. I might change my mind later on this.
Feel free to close this one for now.

It was a fun exercise though. 

Ludo, thanks for the review. It was much appreciated!

all best,

jgart

https://whereis.みんな/
Maxim Cournoyer July 9, 2022, 1:41 a.m. UTC | #4
Hello,

[...]

>> Friendly ping about the above requests from Ludovic :-).
>
> Arun Isaac convinced me to not write a service for this one since it's
> common usage is for quick serving by simply running `darkhttpd ...` from
> the command line. I think that guile bindings for every CLI feature of
> darkhttpd doesn't add to that aim. I might change my mind later on this.
> Feel free to close this one for now.
>
> It was a fun exercise though. 
>
> Ludo, thanks for the review. It was much appreciated!

OK, if you do reopen a ticket for it, please incorporate Ludovic's and
others comments in this issue in the to be submitted code, to avoid
duplicating efforts.

Closing; thanks!

Maxim
diff mbox series

Patch

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>
+  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
+    (($ <darkhttpd-configuration> 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
+    (($ <darkhttpd-configuration> _ _ _ _ _ _ _ _ 
+                                  _ _ _ _ _ _ _ _ 
+                                  _ _ 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))))
+