Atomized

Bootstrapping Nonguix

Background

Guix takes a hardline stance on Free Software, and only refuses to include non-free software, but also rejects software which either requires non-free tools to build; or which must be built by tools which themselves cannot be built from source. This is why the entire Guix System can be bootstrapped from pure source.

These prohibitions presents some practical difficulties, as many modern hardware devices don’t function without closed-source binary firmware. GPUs and wireless networking hardware are the two most common offenders. Effectively all currently available WiFi hardware requires firmware blobs to work1. Since the Guix installer requires networking, this is a significant obstacle, and new users often struggle with it.

The Nonguix project contains the full Linux kernel and binary firmware; it also has a customized installer image, which allows the software needed for the new system to be downloaded. System Crafters has a similar Guix image.

Unfortunately, both these images suffer from the same problem: while the installer can use WiFi, the system they install cannot. So the installer works, but you reboot into a system with no networking, and no clear path to fix that -- you’re stuck in a Catch-22, where you need network access to get the software you need for networking to work. The solutions to this involve various forms of manual hackery within the installation environment, which can be difficult and error-prone for new users.

Installing Guix

These customized installers are a frequent first stop for new Guix users, but I recommend a different approach entirely. If the vanilla Guix installer can get on the network, the installed system can get on the network. And in that state, nonguix can be added, which enables the normal WiFi hardware.

While the Linux-Libre kernel Guix (thus, the Guix installer) uses lacks support for firmware blobs, it supports a wide variety of networking hardware, both wired and wireless. When you look at the intersection of what’s supported vs. what a user is likely to have, one option jumps out immediately: an Android phone2. When wired tethering is enabled, the phone appears as a USB Ethernet device to the computer it’s plugged into. This is my preferred option for installing Guix.

Step By Step Guide

NOTE: I’m assuming typical x86-64 hardware. While this approach should work with any platform, getting the installer to boot in the first place is left as an exercise for the reader.

NOTE: These instructions are valid for Android 16. Other versions should be similar, until they’re not.

Install Guix

  1. Download the official Guix System installer. Copy it to whatever media you want to boot from (Ventoy works great for this), plug it into the computer you want to install Guix on, and boot it. You should land on a screen asking if you want a graphical3 or manual installation. Don’t select anything yet.
  2. Get your phone ready. Enable airplane mode, then turn WiFi back on. Open Settings, then enter "USB" in the search area and select "USB Controled By." This will bring up a page of settings, most of which are disabled. At the top of the page are two options, "Connected device" and "This device." If it’s not already selected, choose "This device," then plug the phone into your target system. This should enable the rest of the options; select "USB tethering."
  3. Proceed with the installation. When you get to networking, it should notice the interface and automatically configure it.

    Choosing a graphical desktop environment is not advised at this time. Since Guix is a rolling distribution, most of the software downloaded when you install will be updated immediately after, and installing a heavy DE means wasted time and bandwidth.

    Select Network Manager for managing network devices.

  4. Finally, boot the new system. You’ll need to reenable USB tethering on the Android phone afterwards. Log in, and try ping 1.1.1.1 to see if you have networking. If not, run nmtui and activate the wired connection.

Bootstrapping Nonguix

This is a three-stage process.

  1. Tell Guix about the nonguix channel. Run:

    guix shell curl -- curl -O https://atomized.org/nonguix-channels.scm
    guix pull -C nonguix-channels.scm
    

    Grab a beverage of your choice, this part takes a while.

    The nonguix-channels.scm file is reproduced below, for the curious:

    (list
     (channel
       (name 'guix)
       (url "https://git.guix.gnu.org/guix.git")
       (branch "master")
       (introduction
        (make-channel-introduction
         "9edb3f66fd807b096b48283debdcddccfea34bad"
         (openpgp-fingerprint
          "BBB0 2DDF 2CEA F6A8 0D1D  E643 A2A0 6DF2 A33A 54FA"))))
     (channel
       (name 'nonguix)
       (url "https://gitlab.com/nonguix/nonguix")
       (branch "master")
       (introduction
        (make-channel-introduction
         "897c1a470da759236cc11798f4e0a5f7d4d59fbc"
         (openpgp-fingerprint
          "2A39 3FFF 68F4 EF7A 3D29  12AF 6F51 20A0 22FB B2D5")))))
    
  2. Verify your channels. Run:

    hash -r
    guix describe
    

    This will print a list of channels, and which commits were built. You should see nonguix in the output; if not, something has gone wrong. Stop and recheck your work.

  3. Configure your system to use the Guix channel and substitutes. In Guix, a single file controls the entire system configuration. You can put the file anywhere (under version control is strongly recommended), but on a fresh install, it’s in /etc/config.scm. Guix makes heavy use of Scheme, and this file contains Scheme source code.

    Open /etc/config.scm in your text editor of choice. You can use guix shell to run most any editor in Guix. You’ll need to run the editor as the root user, with sudo.

    The configuration will look something like this:

    ;; This is an operating system configuration generated
    ;; by the graphical installer.
    ;;
    ;; Once installation is complete, you can learn and modify
    ;; this file to tweak the system configuration, and pass it
    ;; to the 'guix system reconfigure' command to effect your
    ;; changes.
    
    
    ;; Indicate which modules to import to access the variables
    ;; used in this configuration.
    (use-modules (gnu))
    (use-service-modules cups desktop networking ssh xorg)
    
    (operating-system
      (locale "en_US.utf8")
      (timezone "America/Los_Angeles")
      (keyboard-layout (keyboard-layout "us"))
      (host-name "vroom")
    
      ;; The list of user accounts ('root' is implicit).
      (users (cons* (user-account
    		  (name "user")
    		  (comment "New User")
    		  (group "users")
    		  (home-directory "/home/user")
    		  (supplementary-groups '("wheel" "netdev" "audio" "video")))
    		%base-user-accounts))
    
      ;; Below is the list of system services.  To search for available
      ;; services, run 'guix system search KEYWORD' in a terminal.
      (services
       (append (list (service network-manager-service-type)
    		 (service wpa-supplicant-service-type)
    		 (service ntp-service-type))
    
    	   ;; This is the default list of services we
    	   ;; are appending to.
    	   %base-services))
      (bootloader (bootloader-configuration
    		(bootloader grub-bootloader)
    		(targets (list "/dev/sda"))
    		(keyboard-layout keyboard-layout)))
      (swap-devices (list (swap-space
    			(target (uuid
    				 "20343827-0f4c-4277-8dbf-304b9b8b072a")))))
    
      ;; The list of file systems that get "mounted".  The unique
      ;; file system identifiers there ("UUIDs") can be obtained
      ;; by running 'blkid' in a terminal.
      (file-systems (cons* (file-system
    			 (mount-point "/")
    			 (device (uuid
    				  "888542b6-844d-47e3-af92-e3dea1b1289c"
    				  'ext4))
    			 (type "ext4")) %base-file-systems)))
    
    

    Look near the top of the file for use-service-modules, and add this line underneath it:

    (use-modules (nonguix transformations))
    

    Locate the operating-system definition, and assign it to a variable, by wrapping it in a define form:

    (define %os
      (operating-system
        ;; include the full contents of the operating-system form here.
        ))
    

    Make sure to add a closing parenthesis after the operating-system form, to balance the one one opened by (define. This assigns your operating-system to the %os variable4.

    Move the the end of the file and insert a a blank line or two, then add:

    (define xf
      (compose
       (nonguix-transformation-guix)))
    
    (xf %os)
    

    This creates a function named xf, which is an abbreviation of "transform." The function accepts an operating-system, and returns an operating-system with some modifications applied. With the current definitions, the returned operating-system will be updated to know about the nonguix channel and substitute server.

    The file should now look like this:

    ;; This is an operating system configuration generated
    ;; by the graphical installer.
    ;;
    ;; Once installation is complete, you can learn and modify
    ;; this file to tweak the system configuration, and pass it
    ;; to the 'guix system reconfigure' command to effect your
    ;; changes.
    
    
    ;; Indicate which modules to import to access the variables
    ;; used in this configuration.
    (use-modules (gnu))
    (use-service-modules cups desktop networking ssh xorg)
    (use-modules (nonguix transformations))
    
    (define %os
      (operating-system
        (locale "en_US.utf8")
        (timezone "America/Los_Angeles")
        (keyboard-layout (keyboard-layout "us"))
        (host-name "vroom")
    
        ;; The list of user accounts ('root' is implicit).
        (users (cons* (user-account
    		    (name "user")
    		    (comment "New User")
    		    (group "users")
    		    (home-directory "/home/user")
    		    (supplementary-groups '("wheel" "netdev" "audio" "video")))
    		  %base-user-accounts))
    
        ;; Below is the list of system services.  To search for available
        ;; services, run 'guix system search KEYWORD' in a terminal.
        (services
         (append (list (service network-manager-service-type)
    		   (service wpa-supplicant-service-type)
    		   (service ntp-service-type))
    
    	     ;; This is the default list of services we
    	     ;; are appending to.
    	     %base-services))
        (bootloader (bootloader-configuration
    		  (bootloader grub-bootloader)
    		  (targets (list "/dev/sda"))
    		  (keyboard-layout keyboard-layout)))
        (swap-devices (list (swap-space
    			  (target (uuid
    				   "20343827-0f4c-4277-8dbf-304b9b8b072a")))))
    
        ;; The list of file systems that get "mounted".  The unique
        ;; file system identifiers there ("UUIDs") can be obtained
        ;; by running 'blkid' in a terminal.
        (file-systems (cons* (file-system
    			   (mount-point "/")
    			   (device (uuid
    				    "888542b6-844d-47e3-af92-e3dea1b1289c"
    				    'ext4))
    			   (type "ext4")) %base-file-systems))))
    
    (define xf
      (compose
       (nonguix-transformation-guix)))
    
    (xf %os)
    

    Save the file and reconfigure your system:

    sudo guix system reconfigure /etc/config.scm
    

    If this doesn’t work, prints errors, etc: stop and recheck your work. The most common errors are caused by unbalanced parenthesis or incorrectly nested forms. If you want to start over, no problem! Guix has a saved, immutable copy of the configuration. Run guix system describe, the path after "configuration file:" is the configuration for the running system; copy it over top of /etc/config.scm and go back to the top of this step.

    Assuming that worked, restart the Guix daemon:

    sudo herd restart guix-daemon
    

    The nonguix channel and substitutes are now permanently enabled.

  4. Switch to the full Linux kernel.

    Open /etc/config.scm again. Change the definition of xf to:

    (define xf
      (compose
       (nonguix-transformation-linux)
       (nonguix-transformation-guix)))
    

    If you want to add a desktop environment, or any other software, this is a good time to add those to the configuration.

    Reconfigure your system again. Unplug your phone. Reboot, and you should have working WiFi and Bluetooth.

Footnotes:

1

The most recent wireless chipset which offers blob-free operation is Atheros ath9k, which is very outdated, as well as difficult and expensive to buy in the m.2 formfactor most modern laptops need. Also, many modern laptops solder their WiFi, making replacement impossible for all but the most motivated users.

2

I have a Pixel 8 running GrapheneOS. I don’t recommend using any stock Android firmware, which tend to be packed full of spyware and junk apps you can’t remove.

3

This is really text-graphical, and is superficially similar in appearance to the Debian installer.

4

In Guile Scheme, the % prefix on a variable is a convention denoting a constant value.