Building a Custom Guix Distribution


  • Big changes coming to Crafted Emacs soon, check out Jeff Bowman’s blog post:

Building a Custom Guix Distribution

Today we’re going to experiment with how one might build a custom Guix distribution that comes pre-configured with a specific desktop environment and software configuration (i.e. heavily Emacs-driven).

To do that, we’re going to build a VM image where one can boot directly into the default environment provided by the distribution to try it out and then later install it to their own machine!

We might also take a peek at the RDE source code to get some ideas!


(We definitely won’t achieve all of these today)

  • Including the full Linux kernel including proprietary blobs
  • Having an EXWM-based desktop environment
  • Improving the look of the bootup process (splash screen on boot, improved Grub theme, better console font?)
  • Certain services pre-configured (bluetooth, thermald/power for laptops, etc)
  • Develop it in a way where it’s easy to pull in the preconfigured bits, but you can also discard them
  • Automatically set up user’s guix home configuration at system install time

The final config

Unfortunately the stream crashed and we didn’t get to finish this!

Thanks a lot to Andrew Tropin for pointing me to the guix-home-service-type from RDE!

;; -*- mode: scheme; -*-
;; This is an operating system configuration for a VM image.
;; Modify it as you see fit and instantiate the changes by running:
;;   guix system reconfigure /etc/config.scm
(use-modules (gnu services)
             (gnu services shepherd)
             (guix gexp)
             (guix packages)
             (guix records))

(define (guix-home-shepherd-service config)
   (lambda (x)
     (let ((user (car x))
           (he (cdr x)))
        (documentation "Activate Guix Home.")
        (requirement '(user-homes))
        (provision (list (symbol-append 'guix-home- (string->symbol user))))
        (one-shot? #t)
        (auto-start? #t)
        (start #~(make-forkexec-constructor
                  '(#$(file-append he "/activate"))
                  #:user #$user
                  (list (string-append "HOME=" (passwd:dir (getpw #$user))))
                  #:group (group:name (getgrgid (passwd:gid (getpw #$user))))))
        (stop #~(make-kill-destructor)))))

(define (guix-home-gc-roots config)
  (map cdr config))

(define guix-home-service-type
   (name 'guix-home)
   (description "Setups home-environments specified in the value.")
   (extensions (list (service-extension
   ;; (compose append)
   ;; (extend append)
   (default-value '())))

(use-modules (gnu)
             (gnu packages)
             (gnu home)
             (gnu home services)
             (srfi srfi-1))

(define user-home-config
   (packages (map specification->package
                  (list "emacs-doom-themes"
   (services (list (simple-service 'put-me-some-files-brah
                                   (list `(".config/emacs/init.el" ,(local-file "init.el"))))))))

(use-service-modules desktop mcron networking spice ssh xorg sddm)
(use-package-modules bootloaders certs fonts nvi
                     package-management wget xorg)

(define vm-image-motd (plain-file "motd" "
\x1b[1;37mThis is the GNU system.  Welcome!\x1b[0m

This instance of Guix is a template for virtualized environments.
You can reconfigure the whole system by adjusting /etc/config.scm
and running:

  guix system reconfigure /etc/config.scm

Run '\x1b[1;37minfo guix\x1b[0m' to browse documentation.

\x1b[1;33mConsider setting a password for the 'root' and 'guest' \

;;; XXX: Xfce does not implement what is needed for the SPICE dynamic
;;; resolution to work (see:
;;;  Workaround it
;;; by manually invoking xrandr every second.
(define auto-update-resolution-crutch
  #~(job '(next-second)
         (lambda ()
           (setenv "DISPLAY" ":0.0")
           (setenv "XAUTHORITY" "/home/guest/.Xauthority")
           (execl (string-append #$xrandr "/bin/xrandr") "xrandr" "-s" "0"))
         #:user "guest"))

  (host-name "gnu")
  (timezone "Etc/UTC")
  (locale "en_US.utf8")
  (keyboard-layout (keyboard-layout "us" "altgr-intl"))

  ;; Label for the GRUB boot menu.
  (label (string-append "GNU Guix "
                        (or (getenv "GUIX_DISPLAYED_VERSION")
                            (package-version guix))))

  (firmware '())

  ;; Below we assume /dev/vda is the VM's hard disk.
  ;; Adjust as needed.
  (bootloader (bootloader-configuration
               (bootloader grub-bootloader)
               (targets '("/dev/vda"))
               (theme (grub-theme
                         (resolution '(1920 . 1080))
                         (image (local-file "grub-bg.jpg"))))))
  (file-systems (cons (file-system
                        (mount-point "/")
                        (device "/dev/vda1")
                        (type "ext4"))

  (users (cons (user-account
                (name "guest")
                (comment "GNU Guix Live")
                (password "")                     ;no password
                (group "users")
                (supplementary-groups '("wheel" "netdev"
                                        "audio" "video")))

  ;; Our /etc/sudoers file.  Since 'guest' initially has an empty password,
  ;; allow for password-less sudo.
  (sudoers-file (plain-file "sudoers" "\
root ALL=(ALL) ALL
%wheel ALL=NOPASSWD: ALL\n"))

  (packages (append (list font-bitstream-vera nss-certs nvi wget)
                    (list (specification->package "emacs")
                          (specification->package "emacs-exwm")
                          (specification->package "emacs-desktop-environment"))

   (append (list ;; (service xfce-desktop-service-type)

            ;; Choose SLiM, which is lighter than the default GDM.
            (service slim-service-type
                      (auto-login? #t)
                      (default-user "guest")
                        ;; The QXL virtual GPU driver is added to provide
                        ;; a better SPICE experience.
                        (modules (cons xf86-video-qxl
                        (keyboard-layout keyboard-layout)))))

            ;; Uncomment the line below to add an SSH server.
            ;;(service openssh-service-type)

            ;; Add support for the SPICE protocol, which enables dynamic
            ;; resizing of the guest screen resolution, clipboard
            ;; integration with the host, etc.
            (service spice-vdagent-service-type)

            (simple-service 'cron-jobs mcron-service-type
                            (list auto-update-resolution-crutch))

            (service guix-home-service-type
                     `(("guest" . ,user-home-config)))

            ;; Use the DHCP client service rather than NetworkManager.
            (service dhcp-client-service-type))

           ;; Remove some services that don't make sense in a VM.
           (remove (lambda (service)
                     (let ((type (service-kind service)))
                       (or (memq type
                                 (list gdm-service-type
                           (eq? 'network-manager-applet
                                (service-type-name type)))))
                   (modify-services %desktop-services
                     (login-service-type config =>
                                          (inherit config)
                                          (motd vm-image-motd)))

                     ;; Install and run the current Guix rather than an older
                     ;; snapshot.
                     (guix-service-type config =>
                                         (inherit config)
                                         (guix (current-guix))))))))

  ;; Allow resolution of '.local' host names with mDNS.
  (name-service-switch %mdns-host-lookup-nss))
Subscribe to the System Crafters Newsletter!
Stay up to date with the latest System Crafters news and updates! Read the Newsletter page for more information.
Name (optional)
Email Address