doc: Refer to the pt_BR translation.
[jackhill/guix/guix.git] / doc / guix-cookbook.texi
index 31c4cd4..f371364 100644 (file)
@@ -7,14 +7,20 @@
 @settitle GNU Guix Cookbook
 @c %**end of header
 
+@c Onion service for ci.guix.gnu.org.
+@set SUBSTITUTE-TOR-URL https://4zwzi66wwdaalbhgnix55ea3ab4pvvw66ll2ow53kjub6se4q2bclcyd.onion
+
 @copying
-Copyright @copyright{} 2019 Ricardo Wurmus@*
+Copyright @copyright{} 2019, 2022 Ricardo Wurmus@*
 Copyright @copyright{} 2019 Efraim Flashner@*
 Copyright @copyright{} 2019 Pierre Neidhardt@*
 Copyright @copyright{} 2020 Oleg Pykhalov@*
 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
@@ -54,15 +60,20 @@ 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!
 * Packaging::                   Packaging tutorials
 * System Configuration::        Customizing the GNU System
+* Containers::                  Isolated environments and nested systems
 * Advanced package management:: Power to the users!
+* Environment management::      Control environment
 
 * Acknowledgments::             Thanks!
 * GNU Free Documentation License::  The license of this document.
@@ -81,8 +92,16 @@ 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.
+* 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.  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.
+* Music Server with Bluetooth Audio:: Headless music player with Bluetooth output.
 
 @end detailmenu
 @end menu
@@ -109,24 +128,25 @@ Let's get started!
 
 Guix uses the Guile implementation of Scheme.  To start playing with the
 language, install it with @code{guix install guile} and start a
-@uref{https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop,
-REPL} by running @code{guile} from the command line.
+@dfn{REPL}---short for @uref{https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop,
+@dfn{read-eval-print loop}}---by running @code{guile} from the command line.
 
-Alternatively you can also run @code{guix environment --ad-hoc guile -- guile}
+Alternatively you can also run @code{guix shell guile -- guile}
 if you'd rather not have Guile installed in your user profile.
 
 In the following examples, lines show what you would type at the REPL;
 lines starting with ``@result{}'' show evaluation results, while lines
 starting with ``@print{}'' show things that get printed.  @xref{Using Guile
-Interactively,,, guile, GNU Guile Reference Manual}), for more details on the
+Interactively,,, guile, GNU Guile Reference Manual}, for more details on the
 REPL.
 
 @itemize
 @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:
 
@@ -246,8 +266,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
@@ -271,24 +293,41 @@ depends on the @code{(guix store)} module and it exports two variables,
 @code{ruby-build} and @code{ruby-build-system}.
 @end itemize
 
-For a more detailed introduction, check out
-@uref{http://www.troubleshooters.com/codecorn/scheme_guile/hello.htm, Scheme
-at a Glance}, by Steve Litt.
-
-One of the reference Scheme books is the seminal ``Structure and
-Interpretation of Computer Programs'', by Harold Abelson and Gerald Jay
-Sussman, with Julie Sussman.  You'll find a
-@uref{https://mitpress.mit.edu/sites/default/files/sicp/index.html, free copy
-online}, together with
-@uref{https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-001-structure-and-interpretation-of-computer-programs-spring-2005/video-lectures/,
-videos of the lectures by the authors}.  The book is available in Texinfo
-format as the @code{sicp} Guix package.  Go ahead, run @code{guix install
-sicp} and start reading with @code{info sicp} (@pxref{,,, sicp, Structure and Interpretation of Computer Programs}).
-An @uref{https://sarabander.github.io/sicp/, unofficial ebook is also
-available}.
+@quotation Going further
+Scheme is a language that has been widely used to teach programming and
+you'll find plenty of material using it as a vehicle.  Here's a
+selection of documents to learn more about Scheme:
+
+@itemize
+@item
+@uref{https://spritely.institute/static/papers/scheme-primer.html, @i{A
+Scheme Primer}}, by Christine Lemmer-Webber and the Spritely Institute.
+
+@item
+@uref{http://www.troubleshooters.com/codecorn/scheme_guile/hello.htm,
+@i{Scheme at a Glance}}, by Steve Litt.
+
+@item
+@uref{https://mitpress.mit.edu/sites/default/files/sicp/index.html,
+@i{Structure and Interpretation of Computer Programs}}, by Harold
+Abelson and Gerald Jay Sussman, with Julie Sussman.  Colloquially known
+as ``SICP'', this book is a reference.
+
+You can also install it and read it from your computer:
+
+@example
+guix install sicp info-reader
+info sicp
+@end example
+
+An @uref{https://sarabander.github.io/sicp/, unofficial ebook} is also
+available.
+
+@end itemize
 
 You'll find more books, tutorials and other resources at
 @url{https://schemers.org/}.
+@end quotation
 
 
 @c *********************************************************************
@@ -583,7 +622,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
@@ -785,14 +824,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
@@ -802,23 +839,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
@@ -847,11 +880,29 @@ To ensure that the source code from the Git repository is stored in a
 directory with a descriptive name, we use @code{(file-name (git-file-name name
 version))}.
 
-The @code{git-version} procedure that can be used to derive the
+The @code{git-version} procedure can be used to derive the
 version when packaging programs for a specific commit, following the
 Guix contributor guidelines (@pxref{Version Numbers,,, guix, GNU Guix
 Reference Manual}).
 
+How does one obtain the @code{sha256} hash that's in there, you ask?  By
+invoking @command{guix hash} on a checkout of the desired commit, along
+these lines:
+
+@example
+git clone https://github.com/libgit2/libgit2/
+cd libgit2
+git checkout v0.26.6
+guix hash -rx .
+@end example
+
+@command{guix hash -rx} computes a SHA256 hash over the whole directory,
+excluding the @file{.git} sub-directory (@pxref{Invoking guix hash,,,
+guix, GNU Guix Reference Manual}).
+
+In the future, @command{guix download} will hopefully be able to do
+these steps for you, just like it does for regular downloads.
+
 @subsubsection Snippets
 
 Snippets are quoted (i.e. non-evaluated) Scheme code that are a means of patching
@@ -864,22 +915,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
@@ -894,7 +929,7 @@ Installed in the store and in the profile, as well as
 being present at build time.
 @end table
 
-@xref{Package Reference,,, guix, GNU Guix Reference Manual} for more details.
+@xref{package Reference,,, guix, GNU Guix Reference Manual} for more details.
 
 The distinction between the various inputs is important: if a dependency can be
 handled as an @emph{input} instead of a @emph{propagated input}, it should be done so, or
@@ -913,6 +948,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
@@ -1008,7 +1061,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)
@@ -1023,13 +1076,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
@@ -1045,16 +1098,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
@@ -1062,16 +1115,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
@@ -1097,7 +1150,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
@@ -1121,6 +1174,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
@@ -1195,10 +1251,7 @@ $ guix import cran --recursive walrus
             "1nk2glcvy4hyksl5ipq2mz8jy4fss90hx6cq98m3w96kzjni6jjj"))))
     (build-system r-build-system)
     (propagated-inputs
-      `(("r-ggplot2" ,r-ggplot2)
-        ("r-jmvcore" ,r-jmvcore)
-        ("r-r6" ,r-r6)
-        ("r-wrs2" ,r-wrs2)))
+      (list r-ggplot2 r-jmvcore r-r6 r-wrs2))
     (home-page "https://github.com/jamovi/walrus")
     (synopsis "Robust Statistical Methods")
     (description
@@ -1257,8 +1310,7 @@ noticed that a significant number of them have a @code{inherit} field:
               (sha256
                (base32
                 "17fpahgh5dyckgz7rwqvzgnhx53cx9kr2xw0szprc6bnqy977fi8"))))
-    (native-inputs
-     `(("gtk-encode-symbolic-svg" ,gtk+ "bin")))))
+    (native-inputs (list `(,gtk+ "bin")))))
 @end lisp
 
 All unspecified fields are inherited from the parent package.  This is very
@@ -1269,7 +1321,7 @@ version or compilation options.
 @subsection Getting help
 
 Sadly, some applications can be tough to package.  Sometimes they need a patch to
-work with the non-standard filesystem hierarchy enforced by the store.
+work with the non-standard file system hierarchy enforced by the store.
 Sometimes the tests won't run properly.  (They can be skipped but this is not
 recommended.)  Other times the resulting package won't be reproducible.
 
@@ -1325,13 +1377,63 @@ 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.
+* Music Server with Bluetooth Audio:: Headless music player with Bluetooth output.
 @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
 
@@ -1358,37 +1460,34 @@ The @code{linux-libre} kernel package definition is actually a procedure which
 creates a package.
 
 @lisp
-(define* (make-linux-libre version hash supported-systems
-                           #:key
-                           ;; A function that takes an arch and a variant.
-                           ;; See kernel-config for an example.
-                           (extra-version #f)
-                           (configuration-file #f)
-                           (defconfig "defconfig")
-                           (extra-options %default-extra-linux-options)
-                           (patches (list %boot-logo-patch)))
+(define* (make-linux-libre* version gnu-revision source supported-systems
+                            #:key
+                            (extra-version #f)
+                            ;; A function that takes an arch and a variant.
+                            ;; See kernel-config for an example.
+                            (configuration-file #f)
+                            (defconfig "defconfig")
+                            (extra-options %default-extra-linux-options))
   ...)
 @end lisp
 
-The current @code{linux-libre} package is for the 5.1.x series, and is
+The current @code{linux-libre} package is for the 5.15.x series, and is
 declared like this:
 
 @lisp
-(define-public linux-libre
-  (make-linux-libre %linux-libre-version
-                    %linux-libre-hash
-                    '("x86_64-linux" "i686-linux" "armhf-linux" "aarch64-linux")
-                    #:patches %linux-libre-5.1-patches
-                    #:configuration-file kernel-config))
+(define-public linux-libre-5.15
+  (make-linux-libre* linux-libre-5.15-version
+                     linux-libre-5.15-gnu-revision
+                     linux-libre-5.15-source
+                     '("x86_64-linux" "i686-linux" "armhf-linux" "aarch64-linux" "riscv64-linux")
+                     #:configuration-file kernel-config))
 @end lisp
 
 Any keys which are not assigned values inherit their default value from the
 @code{make-linux-libre} definition.  When comparing the two snippets above,
-you may notice that the code comment in the first doesn't actually refer to
-the @code{#:extra-version} keyword; it is actually for
-@code{#:configuration-file}.  Because of this, it is not actually easy to
-include a custom kernel configuration from the definition, but don't worry,
-there are other ways to work with what we do have.
+notice the code comment that refers to @code{#:configuration-file}.  Because of
+this, it is not actually easy to include a custom kernel configuration from the
+definition, but don't worry, there are other ways to work with what we do have.
 
 There are two ways to create a kernel with a custom kernel configuration.  The
 first is to provide a standard @file{.config} file during the build process by
@@ -1406,7 +1505,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
@@ -1437,7 +1536,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)
@@ -1454,9 +1553,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"))
@@ -1472,7 +1571,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
@@ -1482,24 +1581,25 @@ custom kernel:
 @lisp
 (define %macbook41-full-config
   (append %macbook41-config-options
-          %filesystems
+          %file-systems
           %efi-support
           %emulation
           (@@@@ (gnu packages linux) %default-extra-linux-options)))
 
 (define-public linux-libre-macbook41
-  ;; XXX: Access the internal 'make-linux-libre' procedure, which is
+  ;; XXX: Access the internal 'make-linux-libre*' procedure, which is
   ;; private and unexported, and is liable to change in the future.
-  ((@@@@ (gnu packages linux) make-linux-libre) (@@@@ (gnu packages linux) %linux-libre-version)
-                      (@@@@ (gnu packages linux) %linux-libre-hash)
-                      '("x86_64-linux")
-                      #:extra-version "macbook41"
-                      #:patches (@@@@ (gnu packages linux) %linux-libre-5.1-patches)
-                      #:extra-options %macbook41-config-options))
+  ((@@@@ (gnu packages linux) make-linux-libre*)
+   (@@@@ (gnu packages linux) linux-libre-version)
+   (@@@@ (gnu packages linux) linux-libre-gnu-revision)
+   (@@@@ (gnu packages linux) linux-libre-source)
+   '("x86_64-linux")
+   #:extra-version "macbook41"
+   #:extra-options %macbook41-config-options))
 @end lisp
 
-In the above example @code{%filesystems} is a collection of flags enabling
-different filesystem support, @code{%efi-support} enables EFI support and
+In the above example @code{%file-systems} is a collection of flags enabling
+different file system support, @code{%efi-support} enables EFI support and
 @code{%emulation} enables a x86_64-linux machine to act in 32-bit mode also.
 @code{%default-extra-linux-options} are the ones quoted above, which had to be
 added in since they were replaced in the @code{extra-options} keyword.
@@ -1527,7 +1627,7 @@ letting you know what you're missing.  If the file is blank then you're
 missing everything.  The next step is to run:
 
 @example shell
-guix environment linux-libre -- make localmodconfig
+guix shell -D linux-libre -- make localmodconfig
 @end example
 
 and note the output.  Do note that the @file{.config} file is still empty.
@@ -1563,7 +1663,7 @@ The second way to setup the kernel configuration makes more use of Guix's
 features and allows you to share configuration segments between different
 kernels.  For example, all machines using EFI to boot have a number of EFI
 configuration flags that they need.  It is likely that all the kernels will
-share a list of filesystems to support.  By using variables it is easier to
+share a list of file systems to support.  By using variables it is easier to
 see at a glance what features are enabled and to make sure you don't have
 features in one kernel but missing in another.
 
@@ -1572,6 +1672,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
 
@@ -1740,6 +2051,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
 
@@ -1801,10 +2355,16 @@ HTTP/HTTPS will get proxied; FTP, Git protocol, SSH, etc connections
 will still go through the clearnet.  Again, this configuration isn't
 foolproof some of your traffic won't get routed by Tor at all.  Use it
 at your own risk.
+
+Also note that the procedure described here applies only to package
+substitution. When you update your guix distribution with
+@command{guix pull}, you still need to use @command{torsocks} if
+you want to route the connection to guix's git repository servers
+through Tor.
 @end quotation
 
 Guix's substitute server is available as a Onion service, if you want
-to use it to get your substitutes from Tor configure your system as
+to use it to get your substitutes through Tor configure your system as
 follow:
 
 @lisp
@@ -1824,7 +2384,8 @@ follow:
           config => (guix-configuration
                       (inherit config)
                       ;; ci.guix.gnu.org's Onion service
-                      (substitute-urls "https://bp7o7ckwlewr4slm.onion")
+                      (substitute-urls
+                       "@value{SUBSTITUTE-TOR-URL}")
                       (http-proxy "http://localhost:9250")))))))
 @end lisp
 
@@ -1842,9 +2403,655 @@ want to get a substitute from the Tor tunnel run:
 
 @example
 sudo herd set-http-proxy guix-daemon http://localhost:9250
-guix build --substitute-urls=https://bp7o7ckwlewr4slm.onion …
+guix build \
+  --substitute-urls=@value{SUBSTITUTE-TOR-URL} @dots{}
 @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
+
+@node Music Server with Bluetooth Audio
+@section Music Server with Bluetooth Audio
+@cindex mpd
+@cindex music server, headless
+@cindex bluetooth, ALSA configuration
+
+MPD, the Music Player Daemon, is a flexible server-side application for
+playing music.  Client programs on different machines on the network ---
+a mobile phone, a laptop, a desktop workstation --- can connect to it to
+control the playback of audio files from your local music collection.
+MPD decodes the audio files and plays them back on one or many outputs.
+
+By default MPD will play to the default audio device.  In the example
+below we make things a little more interesting by setting up a headless
+music server.  There will be no graphical user interface, no Pulseaudio
+daemon, and no local audio output.  Instead we will configure MPD with
+two outputs: a bluetooth speaker and a web server to serve audio streams
+to any streaming media player.
+
+Bluetooth is often rather frustrating to set up.  You will have to pair
+your Bluetooth device and make sure that the device is automatically
+connected as soon as it powers on.  The Bluetooth system service
+returned by the @code{bluetooth-service} procedure provides the
+infrastructure needed to set this up.
+
+Reconfigure your system with at least the following services and
+packages:
+
+@lisp
+(operating-system
+  ;; …
+  (packages (cons* bluez bluez-alsa
+                   %base-packages))
+  (services
+   ;; …
+   (dbus-service #:services (list bluez-alsa))
+   (bluetooth-service #:auto-enable? #t)))
+@end lisp
+
+Start the @code{bluetooth} service and then use @command{bluetoothctl}
+to scan for Bluetooth devices.  Try to identify your Bluetooth speaker
+and pick out its device ID from the resulting list of devices that is
+indubitably dominated by a baffling smorgasbord of your neighbors' home
+automation gizmos.  This only needs to be done once:
+
+@example
+$ bluetoothctl 
+[NEW] Controller 00:11:22:33:95:7F BlueZ 5.40 [default]
+
+[bluetooth]# power on
+[bluetooth]# Changing power on succeeded
+
+[bluetooth]# agent on
+[bluetooth]# Agent registered
+
+[bluetooth]# default-agent
+[bluetooth]# Default agent request successful
+
+[bluetooth]# scan on
+[bluetooth]# Discovery started
+[CHG] Controller 00:11:22:33:95:7F Discovering: yes
+[NEW] Device AA:BB:CC:A4:AA:CD My Bluetooth Speaker
+[NEW] Device 44:44:FF:2A:20:DC My Neighbor's TV
+@dots{}
+
+[bluetooth]# pair AA:BB:CC:A4:AA:CD
+Attempting to pair with AA:BB:CC:A4:AA:CD
+[CHG] Device AA:BB:CC:A4:AA:CD Connected: yes
+
+[My Bluetooth Speaker]# [CHG] Device AA:BB:CC:A4:AA:CD UUIDs: 0000110b-0000-1000-8000-00xxxxxxxxxx
+[CHG] Device AA:BB:CC:A4:AA:CD UUIDs: 0000110c-0000-1000-8000-00xxxxxxxxxx
+[CHG] Device AA:BB:CC:A4:AA:CD UUIDs: 0000110e-0000-1000-8000-00xxxxxxxxxx
+[CHG] Device AA:BB:CC:A4:AA:CD Paired: yes
+Pairing successful
+
+[CHG] Device AA:BB:CC:A4:AA:CD Connected: no
+
+[bluetooth]# 
+[bluetooth]# trust AA:BB:CC:A4:AA:CD
+[bluetooth]# [CHG] Device AA:BB:CC:A4:AA:CD Trusted: yes
+Changing AA:BB:CC:A4:AA:CD trust succeeded
+
+[bluetooth]# 
+[bluetooth]# connect AA:BB:CC:A4:AA:CD
+Attempting to connect to AA:BB:CC:A4:AA:CD
+[bluetooth]# [CHG] Device AA:BB:CC:A4:AA:CD RSSI: -63
+[CHG] Device AA:BB:CC:A4:AA:CD Connected: yes
+Connection successful
+
+[My Bluetooth Speaker]# scan off
+[CHG] Device AA:BB:CC:A4:AA:CD RSSI is nil
+Discovery stopped
+[CHG] Controller 00:11:22:33:95:7F Discovering: no
+@end example
+
+Congratulations, you can now automatically connect to your Bluetooth
+speaker!
+
+It is now time to configure ALSA to use the @emph{bluealsa} Bluetooth
+module, so that you can define an ALSA pcm device corresponding to your
+Bluetooth speaker.  For a headless server using @emph{bluealsa} with a
+fixed Bluetooth device is likely simpler than configuring Pulseaudio and
+its stream switching behavior.  We configure ALSA by crafting a custom
+@code{alsa-configuration} for the @code{alsa-service-type}.  The
+configuration will declare a @code{pcm} type @code{bluealsa} from the
+@code{bluealsa} module provided by the @code{bluez-alsa} package, and
+then define a @code{pcm} device of that type for your Bluetooth speaker.
+
+All that is left then is to make MPD send audio data to this ALSA
+device.  We also add a secondary MPD output that makes the currently
+played audio files available as a stream through a web server on port
+8080.  When enabled a device on the network could listen to the audio
+stream by connecting any capable media player to the HTTP server on port
+8080, independent of the status of the Bluetooth speaker.
+
+What follows is the outline of an @code{operating-system} declaration
+that should accomplish the above-mentioned tasks:
+
+@lisp
+(use-modules (gnu))
+(use-service-modules audio dbus sound #;… etc)
+(use-package-modules audio linux #;… etc)
+(operating-system
+  ;; …
+  (packages (cons* bluez bluez-alsa
+                   %base-packages))
+  (services
+   ;; …
+   (service mpd-service-type
+            (mpd-configuration
+             (user "your-username")
+             (music-dir "/path/to/your/music")
+             (address "192.168.178.20")
+             (outputs (list (mpd-output
+                             (type "alsa")
+                             (name "MPD")
+                             (extra-options
+                              ;; Use the same name as in the ALSA
+                              ;; configuration below.
+                              '((device . "pcm.btspeaker"))))
+                            (mpd-output
+                             (type "httpd")
+                             (name "streaming")
+                             (enabled? #false)
+                             (always-on? #true)
+                             (tags? #true)
+                             (mixer-type 'null)
+                             (extra-options
+                              '((encoder . "vorbis")
+                                (port    . "8080")
+                                (bind-to-address . "192.168.178.20")
+                                (max-clients . "0") ;no limit
+                                (quality . "5.0")
+                                (format  . "44100:16:1"))))))))
+   (dbus-service #:services (list bluez-alsa))
+   (bluetooth-service #:auto-enable? #t)
+   (service alsa-service-type
+            (alsa-configuration
+             (pulseaudio? #false) ;we don't need it
+             (extra-options
+              #~(string-append "\
+# Declare Bluetooth audio device type \"bluealsa\" from bluealsa module
+pcm_type.bluealsa @{
+    lib \"" #$(file-append bluez-alsa "/lib/alsa-lib/libasound_module_pcm_bluealsa.so") "\"
+@}
+
+# Declare control device type \"bluealsa\" from the same module
+ctl_type.bluealsa @{
+    lib \"" #$(file-append bluez-alsa "/lib/alsa-lib/libasound_module_ctl_bluealsa.so") "\"
+@}
+
+# Define the actual Bluetooth audio device.
+pcm.btspeaker @{
+    type bluealsa
+    device \"AA:BB:CC:A4:AA:CD\" # unique device identifier
+    profile \"a2dp\"
+@}
+
+# Define an associated controller.
+ctl.btspeaker @{
+    type bluealsa
+@}
+"))))))
+@end lisp
+
+Enjoy the music with the MPD client of your choice or a media player
+capable of streaming via HTTP!
+
+
+@c *********************************************************************
+@node Containers
+@chapter Containers
+
+The kernel Linux provides a number of shared facilities that are
+available to processes in the system.  These facilities include a shared
+view on the file system, other processes, network devices, user and
+group identities, and a few others.  Since Linux 3.19 a user can choose
+to @emph{unshare} some of these shared facilities for selected
+processes, providing them (and their child processes) with a different
+view on the system.
+
+A process with an unshared @code{mount} namespace, for example, has its
+own view on the file system --- it will only be able to see directories
+that have been explicitly bound in its mount namespace.  A process with
+its own @code{proc} namespace will consider itself to be the only
+process running on the system, running as PID 1.
+
+Guix uses these kernel features to provide fully isolated environments
+and even complete Guix System containers, lightweight virtual machines
+that share the host system's kernel.  This feature comes in especially
+handy when using Guix on a foreign distribution to prevent interference
+from foreign libraries or configuration files that are available
+system-wide.
+
+@menu
+* Guix Containers::            Perfectly isolated environments
+* Guix System Containers::     A system inside your system
+@end menu
+
+@node Guix Containers
+@section Guix Containers
+
+The easiest way to get started is to use @command{guix shell} with the
+@option{--container} option.  @xref{Invoking guix shell,,, guix, GNU
+Guix Reference Manual} for a reference of valid options.
+
+The following snippet spawns a minimal shell process with most
+namespaces unshared from the system.  The current working directory is
+visible to the process, but anything else on the file system is
+unavailable.  This extreme isolation can be very useful when you want to
+rule out any sort of interference from environment variables, globally
+installed libraries, or configuration files.
+
+@example
+guix shell --container
+@end example
+
+It is a bleak environment, barren, desolate.  You will find that not
+even the GNU coreutils are available here, so to explore this deserted
+wasteland you need to use built-in shell commands.  Even the usually
+gigantic @file{/gnu/store} directory is reduced to a faint shadow of
+itself.
+
+@example sh
+$ echo /gnu/store/*
+/gnu/store/@dots{}-gcc-10.3.0-lib
+/gnu/store/@dots{}-glibc-2.33
+/gnu/store/@dots{}-bash-static-5.1.8
+/gnu/store/@dots{}-ncurses-6.2.20210619
+/gnu/store/@dots{}-bash-5.1.8
+/gnu/store/@dots{}-profile
+/gnu/store/@dots{}-readline-8.1.1
+@end example
+
+@cindex exiting a container
+There isn't much you can do in an environment like this other than
+exiting it.  You can use @key{^D} or @command{exit} to terminate this
+limited shell environment.
+
+@cindex exposing directories, container
+@cindex sharing directories, container
+@cindex mapping locations, container
+You can make other directories available inside of the container
+environment; use @option{--expose=DIRECTORY} to bind-mount the given
+directory as a read-only location inside the container, or use
+@option{--share=DIRECTORY} to make the location writable.  With an
+additional mapping argument after the directory name you can control the
+name of the directory inside the container.  In the following example we
+map @file{/etc} on the host system to @file{/the/host/etc} inside a
+container in which the GNU coreutils are installed.
+
+@example sh
+$ guix shell --container --share=/etc=/the/host/etc coreutils
+$ ls /the/host/etc
+@end example
+
+Similarly, you can prevent the current working directory from being
+mapped into the container with the @option{--no-cwd} option.  Another
+good idea is to create a dedicated directory that will serve as the
+container's home directory, and spawn the container shell from that
+directory.
+
+@cindex hide system libraries, container
+@cindex avoid ABI mismatch, container
+On a foreign system a container environment can be used to compile
+software that cannot possibly be linked with system libraries or with
+the system's compiler toolchain.  A common use-case in a research
+context is to install packages from within an R session.  Outside of a
+container environment there is a good chance that the foreign compiler
+toolchain and incompatible system libraries are found first, resulting
+in incompatible binaries that cannot be used by R.  In a container shell
+this problem disappears, as system libraries and executables simply
+aren't available due to the unshared @code{mount} namespace.
+
+Let's take a comprehensive manifest providing a comfortable development
+environment for use with R:
+
+@lisp
+(specifications->manifest
+  (list "r-minimal"
+
+        ;; base packages
+        "bash-minimal"
+        "glibc-locales"
+        "nss-certs"
+
+        ;; Common command line tools lest the container is too empty.
+        "coreutils"
+        "grep"
+        "which"
+        "wget"
+        "sed"
+
+        ;; R markdown tools
+        "pandoc"
+
+        ;; Toolchain and common libraries for "install.packages"
+        "gcc-toolchain@@10"
+        "gfortran-toolchain"
+        "gawk"
+        "tar"
+        "gzip"
+        "unzip"
+        "make"
+        "cmake"
+        "pkg-config"
+        "cairo"
+        "libxt"
+        "openssl"
+        "curl"
+        "zlib"))
+@end lisp
+
+Let's use this to run R inside a container environment.  For convenience
+we share the @code{net} namespace to use the host system's network
+interfaces.  Now we can build R packages from source the traditional way
+without having to worry about ABI mismatch or incompatibilities.
+
+@example sh
+$ guix shell --container --network --manifest=manifest.scm -- R
+
+R version 4.2.1 (2022-06-23) -- "Funny-Looking Kid"
+Copyright (C) 2022 The R Foundation for Statistical Computing
+@dots{}
+> e <- Sys.getenv("GUIX_ENVIRONMENT")
+> Sys.setenv(GIT_SSL_CAINFO=paste0(e, "/etc/ssl/certs/ca-certificates.crt"))
+> Sys.setenv(SSL_CERT_FILE=paste0(e, "/etc/ssl/certs/ca-certificates.crt"))
+> Sys.setenv(SSL_CERT_DIR=paste0(e, "/etc/ssl/certs"))
+> install.packages("Cairo", lib=paste0(getwd()))
+@dots{}
+* installing *source* package 'Cairo' ...
+@dots{}
+* DONE (Cairo)
+
+The downloaded source packages are in
+       '/tmp/RtmpCuwdwM/downloaded_packages'
+> library("Cairo", lib=getwd())
+> # success!
+@end example
+
+Using container shells is fun, but they can become a little cumbersome
+when you want to go beyond just a single interactive process.  Some
+tasks become a lot easier when they sit on the rock solid foundation of
+a proper Guix System and its rich set of system services.  The next
+section shows you how to launch a complete Guix System inside of a
+container.
+
+
+@node Guix System Containers
+@section Guix System Containers
+
+The Guix System provides a wide array of interconnected system services
+that are configured declaratively to form a dependable stateless GNU
+System foundation for whatever tasks you throw at it.  Even when using
+Guix on a foreign distribution you can benefit from the design of Guix
+System by running a system instance as a container.  Using the same
+kernel features of unshared namespaces mentioned in the previous
+section, the resulting Guix System instance is isolated from the host
+system and only shares file system locations that you explicitly
+declare.
+
+A Guix System container differs from the shell process created by
+@command{guix shell --container} in a number of important ways.  While
+in a container shell the containerized process is a Bash shell process,
+a Guix System container runs the Shepherd as PID 1.  In a system
+container all system services (@pxref{Services,,, guix, GNU Guix
+Reference Manual}) are set up just as they would be on a Guix System in
+a virtual machine or on bare metal---this includes daemons managed by
+the GNU@tie{}Shepherd (@pxref{Shepherd Services,,, guix, GNU Guix
+Reference Manual}) as well as other kinds of extensions to the operating
+system (@pxref{Service Composition,,, guix, GNU Guix Reference Manual}).
+
+The perceived increase in complexity of running a Guix System container
+is easily justified when dealing with more complex applications that
+have higher or just more rigid requirements on their execution
+contexts---configuration files, dedicated user accounts, directories for
+caches or log files, etc.  In Guix System the demands of this kind of
+software are satisfied through the deployment of system services.
+
+
+@node A Database Container
+@subsection A Database Container
+
+A good example might be a PostgreSQL database server.  Much of the
+complexity of setting up such a database server is encapsulated in this
+deceptively short service declaration:
+
+@lisp
+(service postgresql-service-type
+         (postgresql-configuration
+          (postgresql postgresql-14)))
+@end lisp
+
+A complete operating system declaration for use with a Guix System
+container would look something like this:
+
+@lisp
+(use-modules (gnu))
+(use-package-modules databases)
+(use-service-modules databases)
+
+(operating-system
+  (host-name "container")
+  (timezone "Europe/Berlin")
+  (file-systems (cons (file-system
+                        (device (file-system-label "does-not-matter"))
+                        (mount-point "/")
+                        (type "ext4"))
+                      %base-file-systems))
+  (bootloader (bootloader-configuration
+               (bootloader grub-bootloader)
+               (targets '("/dev/sdX"))))
+  (services
+   (cons* (service postgresql-service-type
+                   (postgresql-configuration
+                    (postgresql postgresql-14)
+                    (config-file
+                     (postgresql-config-file
+                      (log-destination "stderr")
+                      (hba-file
+                       (plain-file "pg_hba.conf"
+                                   "\
+local  all     all                     trust
+host   all     all     10.0.0.1/32     trust"))
+                      (extra-config
+                       '(("listen_addresses" "*")
+                         ("log_directory"    "/var/log/postgresql")))))))
+          (service postgresql-role-service-type
+                   (postgresql-role-configuration
+                    (roles
+                     (list (postgresql-role
+                            (name "test")
+                            (create-database? #t))))))
+          %base-services)))
+@end lisp
+
+With @code{postgresql-role-service-type} we define a role ``test'' and
+create a matching database, so that we can test right away without any
+further manual setup.  The @code{postgresql-config-file} settings allow
+a client from IP address 10.0.0.1 to connect without requiring
+authentication---a bad idea in production systems, but convenient for
+this example.
+
+Let's build a script that will launch an instance of this Guix System as
+a container.  Write the @code{operating-system} declaration above to a
+file @file{os.scm} and then use @command{guix system container} to build
+the launcher.  (@pxref{Invoking guix system,,, guix, GNU Guix Reference
+Manual}).
+
+@example
+$ guix system container os.scm
+The following derivations will be built:
+  /gnu/store/@dots{}-run-container.drv
+  @dots{}
+building /gnu/store/@dots{}-run-container.drv...
+/gnu/store/@dots{}-run-container
+@end example
+
+Now that we have a launcher script we can run it to spawn the new system
+with a running PostgreSQL service.  Note that due to some as yet
+unresolved limitations we need to run the launcher as the root user, for
+example with @command{sudo}.
+
+@example
+$ sudo /gnu/store/@dots{}-run-container
+system container is running as PID 5983
+@dots{}
+@end example
+
+Background the process with @key{Ctrl-z} followed by @command{bg}.  Note
+the process ID in the output; we will need it to connect to the
+container later.  You know what?  Let's try attaching to the container
+right now.  We will use @command{nsenter}, a tool provided by the
+@code{util-linux} package:
+
+@example
+$ guix shell util-linux
+$ sudo nsenter -a -t 5983
+root@@container /# pgrep -a postgres
+49 /gnu/store/@dots{}-postgresql-14.4/bin/postgres -D /var/lib/postgresql/data --config-file=/gnu/store/@dots{}-postgresql.conf -p 5432
+51 postgres: checkpointer
+52 postgres: background writer
+53 postgres: walwriter
+54 postgres: autovacuum launcher
+55 postgres: stats collector
+56 postgres: logical replication launcher
+root@@container /# exit
+@end example
+
+The PostgreSQL service is running in the container!
+
+
+@node Container Networking
+@subsection Container Networking
+@cindex container networking
+
+What good is a Guix System running a PostgreSQL database service as a
+container when we can only talk to it with processes originating in the
+container?  It would be much better if we could talk to the database
+over the network.
+
+The easiest way to do this is to create a pair of connected virtual
+Ethernet devices (known as @code{veth}).  We move one of the devices
+(@code{ceth-test}) into the @code{net} namespace of the container and
+leave the other end (@code{veth-test}) of the connection on the host
+system.
+
+@example
+pid=5983
+ns="guix-test"
+host="veth-test"
+client="ceth-test"
+
+# Attach the new net namespace "guix-test" to the container PID.
+sudo ip netns attach $ns $pid
+
+# Create the pair of devices
+sudo ip link add $host type veth peer name $client
+
+# Move the client device into the container's net namespace
+sudo ip link set $client netns $ns
+@end example
+
+Then we configure the host side:
+
+@example
+sudo ip link set $host up
+sudo ip addr add 10.0.0.1/24 dev $host
+@end example
+
+@dots{}and then we configure the client side:
+
+@example
+sudo ip netns exec $ns  ip link set lo up
+sudo ip netns exec $ns  ip link set $client up
+sudo ip netns exec $ns  ip addr add 10.0.0.2/24 dev $client
+@end example
+
+At this point the host can reach the container at IP address 10.0.0.2,
+and the container can reach the host at IP 10.0.0.1.  This is all we
+need to talk to the database server inside the container from the host
+system on the outside.
+
+@example
+$ psql -h 10.0.0.2 -U test
+psql (14.4)
+Type "help" for help.
+
+test=> CREATE TABLE hello (who TEXT NOT NULL);
+CREATE TABLE
+test=> INSERT INTO hello (who) VALUES ('world');
+INSERT 0 1
+test=> SELECT * FROM hello;
+  who
+-------
+ world
+(1 row)
+@end example
+
+Now that we're done with this little demonstration let's clean up:
+
+@example
+sudo kill $pid
+sudo ip netns del $ns
+sudo ip link del $host
+@end example
+
+
 @c *********************************************************************
 @node Advanced package management
 @chapter Advanced package management
@@ -1913,7 +3120,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:
@@ -1941,8 +3148,9 @@ Let's dive in the set up!
 @node Basic setup with manifests
 @subsection Basic setup with manifests
 
-A Guix profile can be set up @emph{via} a so-called @emph{manifest specification} that looks like
-this:
+A Guix profile can be set up @i{via} a @dfn{manifest}.  A manifest is a
+snippet of Scheme code that specifies the set of packages you want to
+have in your profile; it looks like this:
 
 @lisp
 (specifications->manifest
@@ -1955,8 +3163,8 @@ this:
     "package-N"))
 @end lisp
 
-@pxref{Invoking guix package,,, guix, GNU Guix Reference Manual}, for
-the syntax details.
+@xref{Writing Manifests,,, guix, GNU Guix Reference Manual}, for
+more information about the syntax.
 
 We can create a manifest specification per profile and install them this way:
 
@@ -2194,7 +3402,7 @@ Maybe a dependency from our manifest has been updated; or we may have run
 garbage-collected.
 
 @item
-Eventually, we set to work on that project again, so we run @code{guix environment
+Eventually, we set to work on that project again, so we run @code{guix shell
    -m manifest.scm}.  But now we have to wait for Guix to build and install
 stuff!
 @end enumerate
@@ -2243,6 +3451,130 @@ mkdir -p "$GUIX_EXTRA_PROFILES/my-project"
 It's safe to delete the Guix channel profile you've just installed with the
 channel specification, the project profile does not depend on it.
 
+@c *********************************************************************
+@node Environment management
+@chapter Environment management
+
+Guix provides multiple tools to manage environment.  This chapter
+demonstrate such utilities.
+
+@menu
+* Guix environment via direnv:: Setup Guix environment with direnv
+@end menu
+
+@node Guix environment via direnv
+@section Guix environment via direnv
+
+Guix provides a @samp{direnv} package, which could extend shell after
+directory change.  This tool could be used to prepare a pure Guix
+environment.
+
+The following example provides a shell function for @file{~/.direnvrc}
+file, which could be used from Guix Git repository in
+@file{~/src/guix/.envrc} file to setup a build environment similar to
+described in @pxref{Building from Git,,, guix, GNU Guix Reference
+Manual}.
+
+Create a @file{~/.direnvrc} with a Bash code:
+
+@example
+# Thanks <https://github.com/direnv/direnv/issues/73#issuecomment-152284914>
+export_function()
+@{
+  local name=$1
+  local alias_dir=$PWD/.direnv/aliases
+  mkdir -p "$alias_dir"
+  PATH_add "$alias_dir"
+  local target="$alias_dir/$name"
+  if declare -f "$name" >/dev/null; then
+    echo "#!$SHELL" > "$target"
+    declare -f "$name" >> "$target" 2>/dev/null
+    # Notice that we add shell variables to the function trigger.
+    echo "$name \$*" >> "$target"
+    chmod +x "$target"
+  fi
+@}
+
+use_guix()
+@{
+    # Set GitHub token.
+    export GUIX_GITHUB_TOKEN="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+
+    # Unset 'GUIX_PACKAGE_PATH'.
+    export GUIX_PACKAGE_PATH=""
+
+    # Recreate a garbage collector root.
+    gcroots="$HOME/.config/guix/gcroots"
+    mkdir -p "$gcroots"
+    gcroot="$gcroots/guix"
+    if [ -L "$gcroot" ]
+    then
+        rm -v "$gcroot"
+    fi
+
+    # Miscellaneous packages.
+    PACKAGES_MAINTENANCE=(
+        direnv
+        git
+        git:send-email
+        git-cal
+        gnupg
+        guile-colorized
+        guile-readline
+        less
+        ncurses
+        openssh
+        xdot
+    )
+
+    # Environment packages.
+    PACKAGES=(help2man guile-sqlite3 guile-gcrypt)
+
+    # Thanks <https://lists.gnu.org/archive/html/guix-devel/2016-09/msg00859.html>
+    eval "$(guix environment --search-paths --root="$gcroot" --pure guix --ad-hoc $@{PACKAGES[@@]@} $@{PACKAGES_MAINTENANCE[@@]@} "$@@")"
+
+    # Predefine configure flags.
+    configure()
+    @{
+        ./configure --localstatedir=/var --prefix=
+    @}
+    export_function configure
+
+    # Run make and optionally build something.
+    build()
+    @{
+        make -j 2
+        if [ $# -gt 0 ]
+        then
+            ./pre-inst-env guix build "$@@"
+        fi
+    @}
+    export_function build
+
+    # Predefine push Git command.
+    push()
+    @{
+        git push --set-upstream origin
+    @}
+    export_function push
+
+    clear                        # Clean up the screen.
+    git-cal --author='Your Name' # Show contributions calendar.
+
+    # Show commands help.
+    echo "
+build          build a package or just a project if no argument provided
+configure      run ./configure with predefined parameters
+push           push to upstream Git repository
+"
+@}
+@end example
+
+Every project containing @file{.envrc} with a string @code{use guix}
+will have predefined environment variables and procedures.
+
+Run @command{direnv allow} to setup the environment for the first time.
+
 @c *********************************************************************
 @node Acknowledgments
 @chapter Acknowledgments