Linux Maxxing dot com

Install and Muse about GNU Guix

N.B.: Throughout this post I refer to Guix System Distribution simply as Guix and NixOS as Nix. Understand that Guix and Nix ackshully refer to the respective package managers which can be run on any distro. Additionally I adopt tony_btw’s phrase of “legacy” distros to refer to GNU/Linux distros which are not Guix System or NixOS.



Guix has been on my radar for a number of years now. I always viewed it as an elite distro for a number of key reasons:

  1. It is a GNU project and an FSF-approved distro which means it meets the Free System Distribution guidelines, meaning the distro will work perfectly on a couple dual-core thinkpads and YMMV on all other hardware. Harder and more limiting systems are always better.
  2. It is source-based.
  3. It is (was) rarely used in the wild. “Neofetch flex potential” as it has been called. 1

The main selling point of both Guix System and NixOS for the average user would be the source-controlled configuration file which results in an easily “reproducible” system. I put reproducible in quotes because I don’t care so much as whether the system is technically reproducible - meaning exact binary copy down to a hash - but more a system that has all the same packages and configuration.

But I’ve been able to make any distro “reproducible” by using shell scripts and more recently ansible. My ansible roles work extremely well for me on any arch or debian derivative distro, or at least any derivative distro I would consider running. Install a couple packages, run a quick playbook, add the device to my tailnet, and then run another playbook that completely recreates my workstation setup after 15 minutes or so. There are other simpler roles I use on servers to also include alpine.

I bring up ansible only to say that at this point I don’t have a “need” for Guix System or NixOS insofar as they are fantastic tools for reproducibility, roll-backs, snapshots, etc. I get get all those features from “legacy” distros with btrfs snapshots and ansible.

But that doesn’t mean I’m going to not try Guix and NixOS (well, maybe not NixOS). And more importantly it would be a mistake to believe Guix and Nix are primarily systems for easily recreating your rice. That is just a nice touch. The shells, containers, and deployment capabilities are the real selling points of Guix and Nix IMHO, which for me are not that important as I have zero issues using lxc and docker/podman for containers.

I say all of this as background to explain my perspective as a user who is perfectly happy using normie GNU/linux tools. Inertia is a thing, so even if the process of learning FHS linux, ansible, docker, etc took significantly longer than learning Guix/Nix equivalents would, I’m already at the end-point. Anything different is probably going to seem “harder” or “complicated,” and I don’t think any Guix or Nix enjoyer would describe those systems as simple or easy. So if I come across as a Guix denier at any point in this post or other related ones in the future, it’s coming from a perspective that the other solutions Just Werk™ for me at this time.


Definitions

Like Nix, Guix has its own terminology for various things. Here are a few important ones:

  1. Channel:

Guix and its package collection can be extended through channels. A channel is a Git repository, public or not, containing .scm files that provide packages or services.

  1. Substitutes

Build farms that build packages from Guix continuously for some architectures, and make them available as substitutes (binaries).

  1. Nonguix

Nonguix is a software repository for the GNU Guix package manager, which packages some software which cannot be included in the official distribution for ethical or policy-related reasons.

  1. Generation

Known Challenges

Like all FSF-approved distros the Achilles' heel of Guix is the inability to run proprietary software. It comes with the linux-libre kernel which removes the proprietary firmware blobs found in the mainline linux kernel. There’s a lot of misleading tribal knowledge about this on the internet, I figured my computers likely would not even boot as a result. Whilst this may be true for some machines, particularly new ones, this simply is not true for the overwhelming majority of computers. Your computer will boot fine and your graphics will function for at least rendering screens unless it is a new card. The one thing won’t have is wifi. Honestly, not the end of the world.

Don’t Talk about Nonguix

That being said I fully intended to get wifi working using the freedom-hating nonguix channel which provides both the mainline linux kernel and proprietary firmware which are likely needed for your wifi. Adding a channel in Guix is akin to adding a 3rd party repo in legacy distros.

Nonguix is like Fight Club: everybody knows about it and partakes, but nobody talks about it in official Guix fora. A bit silly, but I understand why and have become more and more FSF-aligned over time despite its flaws and characters.


Installation Prep

Before ever installing Guix System, I used the Guix package manager on a so-called foreign distro, in my case it was Devuan GNU/Linux. So I came in with some guix knowledge already. And consoomed System Crafter’s Guix vidyos which are good and still relevant.

I first installed Guix in VM, but after 20 minutes or so I decided to just live dangerously and install it on bare metal. I gained nothing of importance from installing in a VM other than knowing that Guix does not set up btrfs subvolumes by default. More on that later.

Bare Metal Weapon of Choice

In my stack of old corporate thinkpads I had an unallocated W541 and an X230 running Artix GNU/Linux. The W541 has a 4th-gen i7 processor (4-core, 8-thread) and a whopping 4 RAM slots which I filled with a number of DDR3 sticks I had laying around to get a total of 20GB. Plenty enough for compiling for this cpu.

Despite having an NVIDIA Quadro K1100M discrete graphics card, I chose the W541 over the X230 because of the beefier processor since Guix is a source-based distro by default. This computer also has an integrated graphics card, and from my research the discrete GPU is old enough that it works fine with nouveau drivers which are included in the linux-libre kernel. So for the sake of getting a bootable and functioning system that can also compile a kernel, the W541 works.

The wifi chip is also easily accessible and there likely is a linux-libre compatible chip which I can use in the future.

Installation Media & Nonguix

If you’re absolutely set on having wifi working during installation, you will need to use a nonguix ISO. The latest official nonguix ISO is from 2022, though from vidyos it seems like there were more recent images from 2024 which are no-longer on the gitlab. Whilst this is a very minimal base system and the installer itself probably has not changed, 0/10 WOULD NOT RECOMMEND using a 4-year-old ISO.

For starters it is using Guix 1.4, a version behind the current 1.5 which brought major changes to the package manager. It probably also still references the old, slow GNU Savannah channel which Guix used to be hosted on. Guix is now on codeberg which is a significantly faster channel. Aside from that you probably don’t need me to explain why using an iso that old is probably a bad idea.

System Crafters used to publish their own nonguix iso on their github. The community has since moved to codeberg and no longer publishes custom Guix ISOs. My guess is due to codeberg limitations.

You can also generate your own nonguix iso image on any system with the Guix package manager installed. Instructions are provided on the nonguix gitlab. Keep in mind this compiles an iso, so expect around an hour. I have not verified how well this works or if there are any gotchas with this method, though an unnamed friend may or may not have had issues with this until finally conquering.

I chose to use the official GNU Guix ISO over ethernet and add the nonguix channel later. If your system boots the linux-libre kernel - which you should know based on the ISO booting or not - it is a simple enough process to just add the nonguix channel after installation. You can even add the nonguix channel during installation via ssh, see Thanos Apollo’s Guix Installation video for how that can be done.

Official ISO Issues

There are two flavors of the official Guix iso: standard and latest. At the time of this post the standard ISO is from January, 2026, so I knew going it that I would basically be pulling the entire system with this ISO.

There is additionally a latest ISO which should be a weekly build.

Both are direct downloads, I could not find any torrent links.

There are issues with both of these though. The latest official ISO only includes a gpg signature file. No sha256 or sha512 hash. The latest ISO includes neither a gpg signature nor hash. This is unacceptable.

Since I still like to live a bit dangerously, I was fine with signature verification of the standard ISO, but I would not recommend using the latest ISO unless you like to curl | sh your entire operating system.


Guix Installation

There are several videos running through a Guix installation, tony_btw’s shows a cli install per the Guix Reference Manual. This is honestly one of the more straightforward cli installs out there.

I opted to go the graphical/tui route as I value ease and reproducibility of installation. I was more curious how sane the defaults were, and when I choose a distro for long-term use I will not choose one that requires a bunch of cli nursing and a handbook to install. It’s just not worth my time, I want something I can mindlessly install to get back up and running as quickly as possible.

Let me tell you that the Guix tui installer is fantastic, up there with the MX Linux gui installer as my favorites.

Encryption

Guix by default uses true Full-Disk encryption save the EFI system partition with GPT partition tables. From what I understand this is only possible (or more consistent) with the older LUKS1 encryption vs the newer LUKS2 which generally requires an un-encrypted /boot. LUKS2 with un-encrypted /boot is the default on Debian where an encrypted /boot installation will fail from within the tui installer. I generally prefer an encrypted boot if possible and convenient. Of course it’s always possible from the cli.

Btrfs Snapshots, /boot, & Encryption

This is not an issues on Guix, but on legacy distros using btrfs snapshots for roll-backs, an un-encrypted boot partition can bite you if your initramfs gets corrupted or significantly differs from the installed kernel. For instance if you’re on arch where there are only two officially supported kernels and want to restore an old btrfs snapshot, it probably will not boot as the kernels on the snapshot could be completely different kernels. You would need to chroot from an iso or boot into the snapshot from grub, regenerate initramfs, and modify the btrfs root subvolume name to point to the actual root subvolume and not the btrfs snapshot you’re booted in. It potentially becomes messy and could render your /boot unrecoverable without a usb chroot.

So on legacy systems with encryption and btrfs, encrypted /boot is always preferred as the /boot partition is included in the btrfs root snapshot.

File Systems

On the VM I installed btrfs which included zero btrfs subvolumes. My initial strategy was to use btrfs snapshots to have restorable backups even if I garbage-collect (prune) my Guix system. Not having subvolumes makes this impossible without the cli installer.

As I thought about it though, btrfs snapshots offer you absolutely nothing on a Guix system. Btrfs snapshots are incremental, so on a legacy distro each snapshot references the previous snapshot and adds/removes packages as appropriate. This works because the packages/files are installed in the same place just with different timestamps and/or versions.

On Guix and Nix, upgraded packages are stored in a completely different locations and are just symlinked to the appropriate place is the system or user path. As far as I know btrfs would have no way of identifying these as the same package since they are in completely different folders, which means you probably gain zero incremental benefits. So whether you are using btrfs snapshots or Guix generations, it probably makes no difference, the same amount of space exists on disk. This is probably why grub-btrfs is not included in otherwise massive nix package repo.

Further, to roll-back using btrfs you must restore and reboot the system, while Guix can roll back in real-time using guix system roll-back without reboot.

So as far as I can tell there is zero upside to using btrfs snapshots and only downside considering installation complexity. Additionally if you have both btrfs snapshots and generations, you are effectively saving the same packages multiple times, taking up more disk space which I imagine can be precious on Guix and Nix.

So why choose btrfs? Compression, copy-on-write, and data integrity features.

For this install I chose the default ext4 on a 500gb drive, and depending on how much space I have after transferring my /home folder over and keeping a couple months of generations, I may re-evaluated switching to btrfs for the compression benefits which are not insignificant.

Substitutes

You’ll want to enable substitutes during installation. It’s a long process regardless, but substitutes will insure installation takes under an hour. Speed is a weakness of Guix unfortunately, but keep in mind it was a source-based distro for a number of years. Substitutes are secondary. If a substitute server does not have the binary, it will be built from source. That being said I would say around 80% of the packages installed were from binary substitutes, and most of the compiled programs were small anyway. I haven’t looked in detail but I imagine Guix is selective as to which packages even make it to substitute.

Desktops

Guix includes a few desktop environments and window managers, I opted for XFCE as that is my go-to on all systems as a fallback.


Post-Install

Moving /etc/config.scm

I kept the default /etc/config.scm file generated by the installer. Whilst I could have modified it at this point, I really wanted to experience default Guix before I go-a-ricing. Additionally my plan was to copy the system config.scm for modifications, leaving the original one intact at /etc/config.scm.

Tony directly edits /etc/config.scm to install packages and services in his guide. This works, but you miss out out version controlling your config file. Instead I would recommend leaving the default config.scm as is and copying it to a folder of your choosing where you can add it to git. It can be anywhere. I chose ~/.config/guix/config.scm.

Adding nonguix

The instructions for adding the nonguix channel are straightforward. One thing you’ll want to do is add the nonguix substitute server. The instructions are clear enough, but the code block included will conflict somewhat with the default (services ...) block in /etc/config.scm

Here is the default (services ...) block in /etc/config.scm after an XFCE installation.

(services
 (append (list (service xfce-desktop-service-type)
               (service openssh-service-type)
               (set-xorg-configuration
                (xorg-configuration (keyboard-layout keyboard-layout))))
         ;; This is the default list of services we are appending to.
         %desktop-services))

And here is what nonguix provides:

(services (modify-services %desktop-services
           (guix-service-type config => (guix-configuration
             (inherit config)
             (substitute-urls
              (append (list "https://substitutes.nonguix.org")
                %default-substitute-urls))
             (authorized-keys
              (append (list (local-file "./signing-key.pub"))
                %default-authorized-guix-keys))))))

Crystal clear, right? Not going to get into the weeds of scheme here, but defining services beginning with append and then later modify-services is not the cleanest approach.

Instead I borrowed what is done on a default base Guix installation (no desktop) and use cons* to add elements to a list rather than use append which concatenates lists.

This:

(services
 (append (list (service xfce-desktop-service-type)
               (service openssh-service-type)
         %desktop-services))

Is functionally equivalent to

(services
 (cons* (service xfce-desktop-service-type)
        (service openssh-service-type)
        %desktop-services))

In both cases we are adding two services to desktop-services which exists by default on the system.

The difference is we can directly pass (modify-services ...) in the (cons* ...) block, wheres it would have to be a list in order to include it in the (append ...) block.

Here’s what I ended up with:

 (services (cons* (service xfce-desktop-service-type)
                  (service gnome-keyring-service-type)
                  (service nix-service-type)
                  tailscale-service

                  (modify-services
                   %desktop-services
                   (guix-service-type config =>
                                      (guix-configuration
                                       (inherit config)
                                       (substitute-urls
                                        (append
                                         (list "https://substitutes.nonguix.org")
                                         %default-substitute-urls))
                                       (authorized-keys
                                        (append
                                         (list
                                          (local-file
                                           "./signing-key.pub"))
                                         %default-authorized-guix-keys)))))))

Then just change the location of signing-key.pub to a file location of your choosing. I chose ~/.config/guix/nonguix.pub. You can find the contents for this key file here.

Per nonguix instructions:

Guix System will only use the substitution server after it has been reconfigured. The substitution server will therefore by default not be used the first time you run guix system reconfigure after adding the substitution server. It is therefore recommended to explicitly specify the use of the substitution server the first time you reconfigure your system:

sudo guix archive --authorize < signing-key.pub
sudo guix system reconfigure ~/.config/home/config.scm \
--substitute-urls='https://ci.guix.gnu.org \
https://bordeaux.guix.gnu.org https://substitutes.nonguix.org'

Just be sure to put the proper location of config.scm for your system.

Adding the non-libre Linux Kernel and Firmware

Add the following to config.scm:

(use-modules
    ...
    (nongnu packages linux)
    (nongnu system linux-initrd)
    ...
    )
...

(operating-system
  ...
 (kernel linux-lts)
 (initrd microcode-initrd)
 (firmware (list linux-firmware))
 ...
 )

Then run:

sudo guix system reconfigure ~/.config/guix/config.scm

And you will begin pulling the binary linux-lts kernel (assuming the latest build exists, if not it will be source) and linux firmware. After rebooting you should have working wifi.

Notice I have also added a nix service and tailscale service. The nix service is provided by Guix.

The tailscale service is a module I created with tailscale installed from nix. You can additionally find guix channels to install tailscale.


Profiles

System Profile

Now is a good time to mention profiles. By default you have a system profile and a user profile. When you add software to config.scm and run:

sudo guix system reconfigure ~/.config/guix/config.scm

(substituting your file location), you are revising your system profile. Any packages installed will be installed to the system profile. The default path for executable files installed to your system profile is:

/run/current-system/profile/bin

Running guix install <package> as root (or with sudo) installs that <package> to your system profile.

There are certain packages you might want in your system profile, for instance desktop environments and system services, but most software should not be installed in your system profile, whether that is installed via sudo guix install or defined in config.scm.

User Profile

Software installed via guix install <package> will be installed to your user profile located at:

~/.guix-profile/bin

In general, do not install software this way. Not that it is bad or wrong, it just doesn’t get you anything beneficial.

Instead, use Guix Home.

Home Profile / Guix Home

Guix Home is akin to NixOS home-manager except it is also a profile and parallels your system configuration. A default home configuration file is located at ~/guix-home-config.scm. Once again I recommend making a copy of this file and placing it in a convenient place, and keeping the original saved. I chose ~/.config/guix/home/home-config.scm. Add packages to this file in a similar manner to config.scm, and update your home profile by running:

guix home reconfigure ~/.config/guix/home/home-config.scm

What is the advantage of this? You have all the same generational features of your Guix system, just with your home profile. Removing a package is done by simple removing it from home-config.scm. Your configuration can also become modular which is what I intend to do. In this way your home-config.scm and related modules are your source of truth as to what is installed on your system, not whatever happens to be in ~/.guix-profile/bin which you installed by guix install <package>.

There’s a ton more to say about Guix Home but for now I’m pretty much just using it to install packages.


Installing software

There is very little included at first, frustratingly so at times. For instance the clear command is not included and needs to be installed using the ncurses package.

At a minimum you will need to add the appropriate package module and package name to the respective sections of your home config file. There are multiple ways of doing this depending on if you are using a modularized configuration or not. The default guix-home-config.scm file is modular which you may or may not want to immediately use. I would recommend starting from scratch at first, so keep a copy of the default file and then make your own in a more simple format.

Here’s an example for installing emacs, emacs-guix, and ncurses packages:

(use-modules
  (gnu home)
  (gnu home services)
  (gnu packages)
  (gnu packages emacs)
  (gnu packages emacs-xyz)
  (gnu packages ncurses))

(home-environment
  (packages
    (list
     emacs
     emacs-guix
     ncurses)))

emacs-guix is a fantastic way to manage your Guix system. It is extremely useful for searching for packages, much quicker than guix search <package>.

You’ll need the location item from guix search <package>, for example:

guix search emacs-guix

name: emacs-guix
version: 0.6.1
...
location: gnu/packages/emacs-xyz.scm:8355:2
...

This location is simply the folder structure of the Guix git repo, and emacs-xyz is the guile scheme module which includes emacs-guix. Add emacs-xyz to (use-modules ...) and you’ll now have that module loaded. Add emacs-guix to your package list and guix home will install emacs-guix from the emacs-xyz scheme module.

Pretty much everything in Guix follows this format. If we look the config.scm section above which installed the kernel and firmware from nonguix, notice how the modules were in the nongnu folder (channel), not the default gnu channel.

For more information on a modularized configuration, see the Guix Reference Manual and System Crafters video


To be Continued

At this point I have a Guix system running the mainline linux-lts kernel, functioning wifi, the XFCE desktop, with some packages installed in my home profile, and quite a bit more that I’ll save for another post. For me this is the minimum viable product, I would be perfectly happy living in XFCE. In my next post I’ll go through what I’ve done to modify my desktop setup, install suckless software, copy over (and subsequently modify) my dotfiles, and the successes and failures I’ve had in the process.

Things don’t always Just Werk™ on Guix, for instance after writing this post and installing hugo from nonguix, hugo is not rendering the page at all. So add that to the list of things to troubleshoot. But, once the troubleshooting is done, everything is documented in a file and I’m sure Guix will at least be just as usable as any other distro. I’m just doing my best to enjoy the journey of getting there.