Merge remote-tracking branch 'origin/master' into core-updates-frozen
[jackhill/guix/guix.git] / doc / guix-cookbook.texi
index 8a9d075..88d3b98 100644 (file)
@@ -16,6 +16,8 @@ Copyright @copyright{} 2020 Matthew Brooks@*
 Copyright @copyright{} 2020 Marcin Karpezo@*
 Copyright @copyright{} 2020 Brice Waegeneire@*
 Copyright @copyright{} 2020 André Batista@*
+Copyright @copyright{} 2020 Christine Lemmer-Webber@*
+Copyright @copyright{} 2021 Joshua Branson@*
 
 Permission is granted to copy, distribute and/or modify this document
 under the terms of the GNU Free Documentation License, Version 1.3 or
@@ -55,9 +57,12 @@ its API, and related concepts.
 @c TRANSLATORS: You can replace the following paragraph with information on
 @c how to join your own translation team and how to report issues with the
 @c translation.
-If you would like to translate this document in your native language, consider
-joining the @uref{https://translationproject.org/domain/guix-cookbook.html,
-Translation Project}.
+This manual is also available in French (@pxref{Top,,, guix-cookbook.fr,
+Livre de recettes de GNU Guix}) and German (@pxref{Top,,,
+guix-cookbook.de, GNU-Guix-Kochbuch}).  If you would like to translate
+this document in your native language, consider joining
+@uref{https://translate.fedoraproject.org/projects/guix/documentation-cookbook,
+Weblate} (@pxref{Translating Guix,,, guix, GNU Guix reference manual}).
 
 @menu
 * Scheme tutorials::            Meet your new favorite language!
@@ -83,8 +88,8 @@ Packaging
 
 System Configuration
 
-* Customizing the Kernel::      Creating and using a custom Linux kernel
-
+* Auto-Login to a Specific TTY:: Automatically Login a User to a Specific TTY
+* Customizing the Kernel::       Creating and using a custom Linux kernel on Guix System.
 
 @end detailmenu
 @end menu
@@ -127,8 +132,9 @@ REPL.
 @item
 Scheme syntax boils down to a tree of expressions (or @emph{s-expression} in
 Lisp lingo).  An expression can be a literal such as numbers and strings, or a
-compound which is a parenthesized list of compounds and literals.  @code{#t}
-and @code{#f} stand for the Booleans ``true'' and ``false'', respectively.
+compound which is a parenthesized list of compounds and literals.  @code{#true}
+and @code{#false} (abbreviated @code{#t} and @code{#f}) stand for the
+Booleans ``true'' and ``false'', respectively.
 
 Examples of valid expressions:
 
@@ -248,8 +254,10 @@ definitions.
 @end lisp
 
 @item
-The keyword syntax is @code{#:}; it is used to create unique identifiers.
-@pxref{Keywords,,, guile, GNU Guile Reference Manual}.
+@dfn{Keywords} are typically used to identify the named parameters of a
+procedure.  They are prefixed by @code{#:} (hash, colon) followed by
+alphanumeric characters: @code{#:like-this}.
+@xref{Keywords,,, guile, GNU Guile Reference Manual}.
 
 @item
 The percentage @code{%} is typically used for read-only global variables in
@@ -585,7 +593,7 @@ packages.
 Guix makes it possible to streamline the process by adding as many ``package
 declaration directories'' as you want.
 
-Create a directory, say @file{~./guix-packages} and add it to the @samp{GUIX_PACKAGE_PATH}
+Create a directory, say @file{~/guix-packages} and add it to the @samp{GUIX_PACKAGE_PATH}
 environment variable:
 
 @example
@@ -787,14 +795,12 @@ another, more sophisticated package (slightly modified from the source):
                   "17pjvprmdrx4h6bb1hhc98w9qi6ki7yl57f090n9kbhswxqfs7s3"))
                 (patches (search-patches "libgit2-mtime-0.patch"))
                 (modules '((guix build utils)))
-                (snippet '(begin
-                            ;; Remove bundled software.
-                            (delete-file-recursively "deps")
-                            #t))))
+                ;; Remove bundled software.
+                (snippet '(delete-file-recursively "deps"))))
       (build-system cmake-build-system)
       (outputs '("out" "debug"))
       (arguments
-       `(#:tests? #t                            ; Run the test suite (this is the default)
+       `(#:tests? #true                         ; Run the test suite (this is the default)
          #:configure-flags '("-DUSE_SHA1DC=ON") ; SHA-1 collision detection
          #:phases
          (modify-phases %standard-phases
@@ -804,23 +810,19 @@ another, more sophisticated package (slightly modified from the source):
                  (("#!/bin/sh") (string-append "#!" (which "sh"))))
                (substitute* "tests/clar/fs.h"
                  (("/bin/cp") (which "cp"))
-                 (("/bin/rm") (which "rm")))
-               #t))
+                 (("/bin/rm") (which "rm")))))
            ;; Run checks more verbosely.
            (replace 'check
              (lambda _ (invoke "./libgit2_clar" "-v" "-Q")))
            (add-after 'unpack 'make-files-writable-for-tests
-               (lambda _ (for-each make-file-writable (find-files "." ".*")))))))
+             (lambda _ (for-each make-file-writable (find-files "." ".*")))))))
       (inputs
-       `(("libssh2" ,libssh2)
-         ("http-parser" ,http-parser)
-         ("python" ,python-wrapper)))
+       (list libssh2 http-parser python-wrapper))
       (native-inputs
-       `(("pkg-config" ,pkg-config)))
+       (list pkg-config))
       (propagated-inputs
        ;; These two libraries are in 'Requires.private' in libgit2.pc.
-       `(("openssl" ,openssl)
-         ("zlib" ,zlib)))
+       (list openssl zlib))
       (home-page "https://libgit2.github.com/")
       (synopsis "Library providing Git core methods")
       (description
@@ -884,22 +886,6 @@ Snippets might need additional Guile modules which can be imported from the
 
 @subsubsection Inputs
 
-First, a syntactic comment: See the quasi-quote / comma syntax?
-
-@lisp
-    (native-inputs
-     `(("pkg-config" ,pkg-config)))
-@end lisp
-
-is equivalent to
-
-@lisp
-    (native-inputs
-     (list (list "pkg-config" pkg-config)))
-@end lisp
-
-You'll mostly see the former because it's shorter.
-
 There are 3 different input types.  In short:
 
 @table @asis
@@ -933,6 +919,24 @@ It also matters when a substitute is available, in which case only the @emph{inp
 and @emph{propagated inputs} will be fetched: the @emph{native inputs} are not required to
 install a package from a substitute.
 
+@quotation Note
+You may see here and there snippets where package inputs are written
+quite differently, like so:
+
+@lisp
+;; The "old style" for inputs.
+(inputs
+ `(("libssh2" ,libssh2)
+   ("http-parser" ,http-parser)
+   ("python" ,python-wrapper)))
+@end lisp
+
+This is the ``old style'', where each input in the list is explicitly
+given a label (a string).  It is still supported but we recommend using
+the style above instead.  @xref{package Reference,,, guix, GNU Guix
+Reference Manual}, for more info.
+@end quotation
+
 @subsubsection Outputs
 
 Just like how a package can have multiple inputs, it can also produce multiple
@@ -1028,7 +1032,7 @@ If you want to know more about what happens during those phases, consult the
 associated procedures.
 
 For instance, as of this writing the definition of @code{unpack} for the GNU build
-system is
+system is:
 
 @lisp
 (define* (unpack #:key source #:allow-other-keys)
@@ -1043,13 +1047,13 @@ working directory."
         ;; Preserve timestamps (set to the Epoch) on the copied tree so that
         ;; things work deterministically.
         (copy-recursively source "."
-                          #:keep-mtime? #t))
+                          #:keep-mtime? #true))
       (begin
         (if (string-suffix? ".zip" source)
             (invoke "unzip" source)
             (invoke "tar" "xvf" source))
         (chdir (first-subdirectory "."))))
-  #t)
+  #true)
 @end lisp
 
 Note the @code{chdir} call: it changes the working directory to where the source was
@@ -1065,16 +1069,16 @@ the following forms:
 
 @itemize
 @item
-@code{(add-before PHASE NEW-PHASE PROCEDURE)}: Run @code{PROCEDURE} named @code{NEW-PHASE} before @code{PHASE}.
+@code{(add-before @var{phase} @var{new-phase} @var{procedure})}: Run @var{procedure} named @var{new-phase} before @var{phase}.
 @item
-@code{(add-after PHASE NEW-PHASE PROCEDURE)}: Same, but afterwards.
+@code{(add-after @var{phase} @var{new-phase} @var{procedure})}: Same, but afterwards.
 @item
-@code{(replace PHASE PROCEDURE)}.
+@code{(replace @var{phase} @var{procedure})}.
 @item
-@code{(delete PHASE)}.
+@code{(delete @var{phase})}.
 @end itemize
 
-The @code{PROCEDURE} supports the keyword arguments @code{inputs} and @code{outputs}.  Each
+The @var{procedure} supports the keyword arguments @code{inputs} and @code{outputs}.  Each
 input (whether @emph{native}, @emph{propagated} or not) and output directory is referenced
 by their name in those variables.  Thus @code{(assoc-ref outputs "out")} is the store
 directory of the main output of the package.  A phase procedure may look like
@@ -1082,16 +1086,16 @@ this:
 
 @lisp
 (lambda* (#:key inputs outputs #:allow-other-keys)
-  (let (((bash-directory (assoc-ref inputs "bash"))
-         (output-directory (assoc-ref outputs "out"))
-         (doc-directory (assoc-ref outputs "doc"))
-  ; ...
-  #t)
+  (let ((bash-directory (assoc-ref inputs "bash"))
+        (output-directory (assoc-ref outputs "out"))
+        (doc-directory (assoc-ref outputs "doc")))
+    ;; ...
+    #true))
 @end lisp
 
-The procedure must return @code{#t} on success.  It's brittle to rely on the return
+The procedure must return @code{#true} on success.  It's brittle to rely on the return
 value of the last expression used to tweak the phase because there is no
-guarantee it would be a @code{#t}.  Hence the trailing @code{#t} to ensure the right value
+guarantee it would be a @code{#true}.  Hence the trailing @code{#true} to ensure the right value
 is returned on success.
 
 @subsubsection Code staging
@@ -1117,7 +1121,7 @@ Some of those functions can be found in
 @samp{$GUIX_CHECKOUT/guix/guix/build/utils.scm}.  Most of them mirror the behaviour
 of the traditional Unix system commands:
 
-@table @asis
+@table @code
 @item which
 Like the @samp{which} system command.
 @item find-files
@@ -1141,6 +1145,9 @@ then restore the previous working directory.
 A ``@command{sed}-like'' function.
 @end table
 
+@xref{Build Utilities,,, guix, GNU Guix Reference Manual}, for more
+information on these utilities.
+
 @subsubsection Module prefix
 
 The license in our last example needs a prefix: this is because of how the
@@ -1345,13 +1352,62 @@ chapter is to demonstrate some advanced configuration concepts.
 reference.
 
 @menu
+* Auto-Login to a Specific TTY:: Automatically Login a User to a Specific TTY
 * Customizing the Kernel::       Creating and using a custom Linux kernel on Guix System.
+* Guix System Image API::        Customizing images to target specific platforms.
 * Connecting to Wireguard VPN::  Connecting to a Wireguard VPN.
 * Customizing a Window Manager:: Handle customization of a Window manager on Guix System.
+* Running Guix on a Linode Server:: Running Guix on a Linode Server
 * Setting up a bind mount:: Setting up a bind mount in the file-systems definition.
 * Getting substitutes from Tor:: Configuring Guix daemon to get substitutes through Tor.
+* Setting up NGINX with Lua:: Configuring NGINX web-server to load Lua modules.
 @end menu
 
+@node Auto-Login to a Specific TTY
+@section Auto-Login to a Specific TTY
+
+While the Guix manual explains auto-login one user to @emph{all} TTYs (
+@pxref{auto-login to TTY,,, guix, GNU Guix Reference Manual}), some
+might prefer a situation, in which one user is logged into one TTY with
+the other TTYs either configured to login different users or no one at
+all.  Note that one can auto-login one user to any TTY, but it is
+usually advisable to avoid @code{tty1}, which, by default, is used to
+log warnings and errors.
+
+Here is how one might set up auto login for one user to one tty:
+
+@lisp
+(define (auto-login-to-tty config tty user)
+  (if (string=? tty (mingetty-configuration-tty config))
+        (mingetty-configuration
+         (inherit config)
+         (auto-login user))
+        config))
+
+(define %my-services
+  (modify-services %base-services
+    ;; @dots{}
+    (mingetty-service-type config =>
+                           (auto-login-to-tty
+                            config "tty3" "alice"))))
+
+(operating-system
+  ;; @dots{}
+  (services %my-services))
+@end lisp
+
+One could also @code{compose} (@pxref{Higher-Order Functions,,, guile,
+The Guile Reference Manual}) @code{auto-login-to-tty} to login multiple
+users to multiple ttys.
+
+Finally, here is a note of caution.  Setting up auto login to a TTY,
+means that anyone can turn on your computer and run commands as your
+regular user.
+However, if you have an encrypted root partition, and thus already need
+to enter a passphrase when the system boots, auto-login might be a
+convenient option.
+
+
 @node Customizing the Kernel
 @section Customizing the Kernel
 
@@ -1382,8 +1438,8 @@ creates a package.
                            #:key
                            ;; A function that takes an arch and a variant.
                            ;; See kernel-config for an example.
-                           (extra-version #f)
-                           (configuration-file #f)
+                           (extra-version #false)
+                           (configuration-file #false)
                            (defconfig "defconfig")
                            (extra-options %default-extra-linux-options)
                            (patches (list %boot-logo-patch)))
@@ -1426,7 +1482,7 @@ the @code{make-linux-libre} package definition:
       (begin
         (copy-file config ".config")
         (chmod ".config" #o666))
-      (invoke "make" ,defconfig))
+      (invoke "make" ,defconfig)))
 @end lisp
 
 Below is a sample kernel package.  The @code{linux-libre} package is nothing
@@ -1457,7 +1513,7 @@ it:
 @lisp
 (define %default-extra-linux-options
   `(;; https://lists.gnu.org/archive/html/guix-devel/2014-04/msg00039.html
-   ("CONFIG_DEVPTS_MULTIPLE_INSTANCES" . #t)
+   ("CONFIG_DEVPTS_MULTIPLE_INSTANCES" . #true)
    ;; Modules required for initrd:
    ("CONFIG_NET_9P" . m)
    ("CONFIG_NET_9P_VIRTIO" . m)
@@ -1474,9 +1530,9 @@ it:
   (string-join (map (match-lambda
                       ((option . 'm)
                        (string-append option "=m"))
-                      ((option . #t)
+                      ((option . #true)
                        (string-append option "=y"))
-                      ((option . #f)
+                      ((option . #false)
                        (string-append option "=n")))
                     options)
                "\n"))
@@ -1492,7 +1548,7 @@ And in the custom configure script from the `make-linux-libre` package:
   (display extra-configuration port)
   (close-port port))
 
-(invoke "make" "oldconfig"))))
+(invoke "make" "oldconfig")
 @end lisp
 
 So by not providing a configuration-file the @file{.config} starts blank, and
@@ -1592,6 +1648,217 @@ likely that you'll need to modify the initrd on a machine using a custom
 kernel, since certain modules which are expected to be built may not be
 available for inclusion into the initrd.
 
+@node Guix System Image API
+@section Guix System Image API
+
+Historically, Guix System is centered around an @code{operating-system}
+structure.  This structure contains various fields ranging from the
+bootloader and kernel declaration to the services to install.
+
+Depending on the target machine, that can go from a standard
+@code{x86_64} machine to a small ARM single board computer such as the
+Pine64, the image constraints can vary a lot.  The hardware
+manufacturers will impose different image formats with various partition
+sizes and offsets.
+
+To create images suitable for all those machines, a new abstraction is
+necessary: that's the goal of the @code{image} record.  This record
+contains all the required information to be transformed into a
+standalone image, that can be directly booted on any target machine.
+
+@lisp
+(define-record-type* <image>
+  image make-image
+  image?
+  (name               image-name ;symbol
+                      (default #f))
+  (format             image-format) ;symbol
+  (target             image-target
+                      (default #f))
+  (size               image-size  ;size in bytes as integer
+                      (default 'guess))
+  (operating-system   image-operating-system  ;<operating-system>
+                      (default #f))
+  (partitions         image-partitions ;list of <partition>
+                      (default '()))
+  (compression?       image-compression? ;boolean
+                      (default #t))
+  (volatile-root?     image-volatile-root? ;boolean
+                      (default #t))
+  (substitutable?     image-substitutable? ;boolean
+                      (default #t)))
+@end lisp
+
+This record contains the operating-system to instantiate. The
+@code{format} field defines the image type and can be @code{efi-raw},
+@code{qcow2} or @code{iso9660} for instance. In the future, it could be
+extended to @code{docker} or other image types.
+
+A new directory in the Guix sources is dedicated to images definition. For now
+there are four files:
+
+@itemize @bullet
+@item @file{gnu/system/images/hurd.scm}
+@item @file{gnu/system/images/pine64.scm}
+@item @file{gnu/system/images/novena.scm}
+@item @file{gnu/system/images/pinebook-pro.scm}
+@end itemize
+
+Let's have a look to @file{pine64.scm}. It contains the
+@code{pine64-barebones-os} variable which is a minimal definition of an
+operating-system dedicated to the @b{Pine A64 LTS} board.
+
+@lisp
+(define pine64-barebones-os
+  (operating-system
+   (host-name "vignemale")
+   (timezone "Europe/Paris")
+   (locale "en_US.utf8")
+   (bootloader (bootloader-configuration
+                (bootloader u-boot-pine64-lts-bootloader)
+                (targets '("/dev/vda"))))
+   (initrd-modules '())
+   (kernel linux-libre-arm64-generic)
+   (file-systems (cons (file-system
+                        (device (file-system-label "my-root"))
+                        (mount-point "/")
+                        (type "ext4"))
+                       %base-file-systems))
+   (services (cons (service agetty-service-type
+                            (agetty-configuration
+                             (extra-options '("-L")) ; no carrier detect
+                             (baud-rate "115200")
+                             (term "vt100")
+                             (tty "ttyS0")))
+                   %base-services))))
+@end lisp
+
+The @code{kernel} and @code{bootloader} fields are pointing to packages
+dedicated to this board.
+
+Right below, the @code{pine64-image-type} variable is also defined.
+
+@lisp
+(define pine64-image-type
+  (image-type
+   (name 'pine64-raw)
+   (constructor (cut image-with-os arm64-disk-image <>))))
+@end lisp
+
+It's using a record we haven't talked about yet, the @code{image-type} record,
+defined this way:
+
+@lisp
+(define-record-type* <image-type>
+  image-type make-image-type
+  image-type?
+  (name           image-type-name) ;symbol
+  (constructor    image-type-constructor)) ;<operating-system> -> <image>
+@end lisp
+
+The main purpose of this record is to associate a name to a procedure
+transforming an @code{operating-system} to an image.  To understand why
+it is necessary, let's have a look to the command producing an image
+from an @code{operating-system} configuration file:
+
+@example
+guix system image my-os.scm
+@end example
+
+This command expects an @code{operating-system} configuration but how
+should we indicate that we want an image targeting a Pine64 board?  We
+need to provide an extra information, the @code{image-type}, by passing
+the @code{--image-type} or @code{-t} flag, this way:
+
+@example
+guix system image --image-type=pine64-raw my-os.scm
+@end example
+
+This @code{image-type} parameter points to the @code{pine64-image-type}
+defined above. Hence, the @code{operating-system} declared in
+@code{my-os.scm} will be applied the @code{(cut image-with-os
+arm64-disk-image <>)} procedure to turn it into an image.
+
+The resulting image looks like:
+
+@lisp
+(image
+ (format 'disk-image)
+ (target "aarch64-linux-gnu")
+ (operating-system my-os)
+ (partitions
+  (list (partition
+         (inherit root-partition)
+         (offset root-offset)))))
+@end lisp
+
+which is the aggregation of the @code{operating-system} defined in
+ @code{my-os.scm} to the @code{arm64-disk-image} record.
+
+But enough Scheme madness. What does this image API bring to the Guix user?
+
+One can run:
+
+@example
+mathieu@@cervin:~$ guix system --list-image-types
+The available image types are:
+
+   - pinebook-pro-raw
+   - pine64-raw
+   - novena-raw
+   - hurd-raw
+   - hurd-qcow2
+   - qcow2
+   - uncompressed-iso9660
+   - efi-raw
+   - arm64-raw
+   - arm32-raw
+   - iso9660
+@end example
+
+and by writing an @code{operating-system} file based on
+@code{pine64-barebones-os}, you can customize your image to your
+preferences in a file (@file{my-pine-os.scm}) like this:
+
+@lisp
+(use-modules (gnu services linux)
+             (gnu system images pine64))
+
+(let ((base-os pine64-barebones-os))
+  (operating-system
+    (inherit base-os)
+    (timezone "America/Indiana/Indianapolis")
+    (services
+     (cons
+      (service earlyoom-service-type
+               (earlyoom-configuration
+                (prefer-regexp "icecat|chromium")))
+      (operating-system-user-services base-os)))))
+@end lisp
+
+run:
+
+@example
+guix system image --image-type=pine64-raw my-pine-os.scm
+@end example
+
+or,
+
+@example
+guix system image --image-type=hurd-raw my-hurd-os.scm
+@end example
+
+to get an image that can be written directly to a hard drive and booted
+from.
+
+Without changing anything to @code{my-hurd-os.scm}, calling:
+
+@example
+guix system image --image-type=hurd-qcow2 my-hurd-os.scm
+@end example
+
+will instead produce a Hurd QEMU image.
+
 @node Connecting to Wireguard VPN
 @section Connecting to Wireguard VPN
 
@@ -1760,6 +2027,249 @@ your screen but not suspend it, it's a good idea to notify xss-lock about this s
 confusion occurs. This can be done by executing @code{xset s activate} immediately
 before you execute slock.
 
+@node Running Guix on a Linode Server
+@section Running Guix on a Linode Server
+@cindex linode, Linode
+
+To run Guix on a server hosted by @uref{https://www.linode.com, Linode},
+start with a recommended Debian server.  We recommend using the default
+distro as a way to bootstrap Guix. Create your SSH keys.
+
+@example
+ssh-keygen
+@end example
+
+Be sure to add your SSH key for easy login to the remote server.
+This is trivially done via Linode's graphical interface for adding
+SSH keys.  Go to your profile and click add SSH Key.
+Copy into it the output of:
+
+@example
+cat ~/.ssh/<username>_rsa.pub
+@end example
+
+Power the Linode down.
+
+In the Linode's Storage tab, resize the Debian disk to be smaller.
+30 GB free space is recommended.  Then click "Add a disk", and fill
+out the form with the following:
+
+@itemize @bullet
+@item
+Label: "Guix"
+
+@item
+Filesystem: ext4
+
+@item
+Set it to the remaining size
+@end itemize
+
+In the Configurations tab, press "Edit" on the default Debian profile.
+Under "Block Device Assignment" click "Add a Device". It should be
+@file{/dev/sdc} and you can select the "Guix" disk. Save Changes.
+
+Now "Add a Configuration", with the following:
+@itemize @bullet
+@item
+Label: Guix
+
+@item
+Kernel:GRUB 2 (it's at the bottom!  This step is @b{IMPORTANT!})
+
+@item
+Block device assignment:
+
+@item
+@file{/dev/sda}: Guix
+
+@item
+@file{/dev/sdb}: swap
+
+@item
+Root device: @file{/dev/sda}
+
+@item
+Turn off all the filesystem/boot helpers
+@end itemize
+
+Now power it back up, booting with the Debian configuration.  Once it's
+running, ssh to your server via @code{ssh
+root@@@var{<your-server-IP-here>}}. (You can find your server IP address in
+your Linode Summary section.) Now you can run the "install guix from
+@pxref{Binary Installation,,, guix, GNU Guix}" steps:
+
+@example
+sudo apt-get install gpg
+wget https://sv.gnu.org/people/viewgpg.php?user_id=15145 -qO - | gpg --import -
+wget https://git.savannah.gnu.org/cgit/guix.git/plain/etc/guix-install.sh
+chmod +x guix-install.sh
+./guix-install.sh
+guix pull
+@end example
+
+Now it's time to write out a config for the server.  The key information
+is below. Save the resulting file as @file{guix-config.scm}.
+
+@lisp
+(use-modules (gnu)
+             (guix modules))
+(use-service-modules networking
+                     ssh)
+(use-package-modules admin
+                     certs
+                     package-management
+                     ssh
+                     tls)
+
+(operating-system
+  (host-name "my-server")
+  (timezone "America/New_York")
+  (locale "en_US.UTF-8")
+  ;; This goofy code will generate the grub.cfg
+  ;; without installing the grub bootloader on disk.
+  (bootloader (bootloader-configuration
+               (bootloader
+                (bootloader
+                 (inherit grub-bootloader)
+                 (installer #~(const #true))))))
+  (file-systems (cons (file-system
+                        (device "/dev/sda")
+                        (mount-point "/")
+                        (type "ext4"))
+                      %base-file-systems))
+
+
+  (swap-devices (list "/dev/sdb"))
+
+
+  (initrd-modules (cons "virtio_scsi"    ; Needed to find the disk
+                        %base-initrd-modules))
+
+  (users (cons (user-account
+                (name "janedoe")
+                (group "users")
+                ;; Adding the account to the "wheel" group
+                ;; makes it a sudoer.
+                (supplementary-groups '("wheel"))
+                (home-directory "/home/janedoe"))
+               %base-user-accounts))
+
+  (packages (cons* nss-certs            ;for HTTPS access
+                   openssh-sans-x
+                   %base-packages))
+
+  (services (cons*
+             (service dhcp-client-service-type)
+             (service openssh-service-type
+                      (openssh-configuration
+                       (openssh openssh-sans-x)
+                       (password-authentication? #false)
+                       (authorized-keys
+                        `(("janedoe" ,(local-file "janedoe_rsa.pub"))
+                          ("root" ,(local-file "janedoe_rsa.pub"))))))
+             %base-services)))
+@end lisp
+
+Replace the following fields in the above configuration:
+@lisp
+(host-name "my-server")       ; replace with your server name
+; if you chose a linode server outside the U.S., then
+; use tzselect to find a correct timezone string
+(timezone "America/New_York") ; if needed replace timezone
+(name "janedoe")              ; replace with your username
+("janedoe" ,(local-file "janedoe_rsa.pub")) ; replace with your ssh key
+("root" ,(local-file "janedoe_rsa.pub")) ; replace with your ssh key
+@end lisp
+
+The last line in the above example lets you log into the server as root
+and set the initial root password (see the note at the end of this
+recipe about root login).  After you have done this, you may
+delete that line from your configuration and reconfigure to prevent root
+login.
+
+Copy your ssh public key (eg: @file{~/.ssh/id_rsa.pub}) as
+@file{@var{<your-username-here>}_rsa.pub} and put
+@file{guix-config.scm} in the same directory.  In a new terminal run
+these commands.
+
+@example
+sftp root@@<remote server ip address>
+put /path/to/files/<username>_rsa.pub .
+put /path/to/files/guix-config.scm .
+@end example
+
+In your first terminal, mount the guix drive:
+
+@example
+mkdir /mnt/guix
+mount /dev/sdc /mnt/guix
+@end example
+
+Due to the way we set up the bootloader section of the guix-config.scm,
+only the grub configuration file will be installed.  So, we need to copy
+over some of the other GRUB stuff already installed on the Debian system:
+
+@example
+mkdir -p /mnt/guix/boot/grub
+cp -r /boot/grub/* /mnt/guix/boot/grub/
+@end example
+
+Now initialize the Guix installation:
+
+@example
+guix system init guix-config.scm /mnt/guix
+@end example
+
+Ok, power it down!
+Now from the Linode console, select boot and select "Guix".
+
+Once it boots, you should be able to log in via SSH!  (The server config
+will have changed though.)  You may encounter an error like:
+
+@example
+$ ssh root@@<server ip address>
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
+Someone could be eavesdropping on you right now (man-in-the-middle attack)!
+It is also possible that a host key has just been changed.
+The fingerprint for the ECDSA key sent by the remote host is
+SHA256:0B+wp33w57AnKQuHCvQP0+ZdKaqYrI/kyU7CfVbS7R4.
+Please contact your system administrator.
+Add correct host key in /home/joshua/.ssh/known_hosts to get rid of this message.
+Offending ECDSA key in /home/joshua/.ssh/known_hosts:3
+ECDSA host key for 198.58.98.76 has changed and you have requested strict checking.
+Host key verification failed.
+@end example
+
+Either delete @file{~/.ssh/known_hosts} file, or delete the offending line
+starting with your server IP address.
+
+Be sure to set your password and root's password.
+
+@example
+ssh root@@<remote ip address>
+passwd  ; for the root password
+passwd <username> ; for the user password
+@end example
+
+You may not be able to run the above commands at this point.  If you
+have issues remotely logging into your linode box via SSH, then you may
+still need to set your root and user password initially by clicking on
+the ``Launch Console'' option in your linode.  Choose the ``Glish''
+instead of ``Weblish''.  Now you should be able to ssh into the machine.
+
+Hooray!  At this point you can shut down the server, delete the
+Debian disk, and resize the Guix to the rest of the size.
+Congratulations!
+
+By the way, if you save it as a disk image right at this point, you'll
+have an easy time spinning up new Guix images!  You may need to
+down-size the Guix image to 6144MB, to save it as an image.  Then you
+can resize it again to the max size.
+
 @node Setting up a bind mount
 @section Setting up a bind mount
 
@@ -1871,6 +2381,63 @@ sudo herd set-http-proxy guix-daemon http://localhost:9250
 guix build --substitute-urls=https://bp7o7ckwlewr4slm.onion …
 @end example
 
+@node Setting up NGINX with Lua
+@section Setting up NGINX with Lua
+@cindex nginx, lua, openresty, resty
+
+NGINX could be extended with Lua scripts.
+
+Guix provides NGINX service with ability to load Lua module and specific
+Lua packages, and reply to requests by evaluating Lua scripts.
+
+The following example demonstrates system definition with configuration
+to evaluate @file{index.lua} Lua script on HTTP request to
+@uref{http://localhost/hello} endpoint:
+
+@example
+local shell = require "resty.shell"
+
+local stdin = ""
+local timeout = 1000  -- ms
+local max_size = 4096  -- byte
+
+local ok, stdout, stderr, reason, status =
+   shell.run([[/run/current-system/profile/bin/ls /tmp]], stdin, timeout, max_size)
+
+ngx.say(stdout)
+@end example
+
+@lisp
+(use-modules (gnu))
+(use-service-modules #;… web)
+(use-package-modules #;… lua)
+(operating-system
+  ;; …
+  (services
+   ;; …
+   (service nginx-service-type
+            (nginx-configuration
+             (modules
+              (list
+               (file-append nginx-lua-module "/etc/nginx/modules/ngx_http_lua_module.so")))
+             (lua-package-path (list lua-resty-core
+                                     lua-resty-lrucache
+                                     lua-resty-signal
+                                     lua-tablepool
+                                     lua-resty-shell))
+             (lua-package-cpath (list lua-resty-signal))
+             (server-blocks
+              (list (nginx-server-configuration
+                     (server-name '("localhost"))
+                     (listen '("80"))
+                     (root "/etc")
+                     (locations (list
+                                 (nginx-location-configuration
+                                  (uri "/hello")
+                                  (body (list #~(format #f "content_by_lua_file ~s;"
+                                                        #$(local-file "index.lua"))))))))))))))
+@end lisp
+
 @c *********************************************************************
 @node Advanced package management
 @chapter Advanced package management
@@ -1939,7 +2506,7 @@ section on @ref{Reproducible profiles}.
 
 @item
 Easier upgrades and maintenance: Multiple profiles make it easy to keep
-package listings at hand and make upgrades completely friction-less.
+package listings at hand and make upgrades completely frictionless.
 @end itemize
 
 Concretely, here follows some typical profiles: