Initial Guix Home setup

Table of Contents

In my previous post, Setting up GNU Guix, I installed Guix in a VM. The next step is setting up a user profile and a graphical environment. Guix Home originated in the rde project, and didn’t exist when I first set up Guix, and I used guix mostly as a regular package manager. I have been installing software in an ad-hoc fashion using guix install some-packaged-software, but Guix is so much more powerful than a regular package manager.

Guix home allows us to get the same features as with Guix System, just for a home folder/user. This means my Emacs configuration, bash scripts, and all other configuration files, can be atomically updated and rolled back as with guix system.

Home Configuration (guix documentation)

Transfer (private) keys to the new device

Usually when I set up a new system, I copy my gpg and ssh keys to a USB stick to transfer them to the new system. I really wanted to avoid the USB stick, so I created a script to transfer files over internet in, what I believe is, a secure enough way.

It encrypts the ssh private keys with my usual gpg key. It encrypts the gpg private key with a new password. It adds all keys to an archive, and then encrypts it with yet another password.

To make it available to a new device, I upload the archive to https://pwpush.com with yet another password. The upload is configured to expire after one fetch or one day, whichever comes first.

In order to get to my private keys, you must have:

  • the pwpush token created for the upload
  • the pwpush password I created
  • the archive password I created
  • the gpg private key password I created
  • and finally the password for the private key
  • .. fetch it before I fetch do, and within a day

Even if pwpush were a malicious host, it cannot make use of my keys without cracking randomly generated passwords, and it cannot serve me corrupted files that the script is able to extract.

The script will output the invocation needed on the other device to import.

See

Clone my dotfiles repository

Guix adds an example guix home configuration in the home folder when we set up the home folder: ~/guix-home-config.scm.

I have already created a repository and began configuring a system, so we want to continue from there.

We haven’t installed OpenSSH yet, but with guix shell we can use it without installing it.

mkdir -p ~/code
guix shell --pure ssh openssh -- \
    git clone git@codeberg.org:simendsjo/dotfiles ~/code/dotfiles

Reconfigure and log in again

Our user is not set up with a home configuration yet. It is possible to do this is the system configuration, but then we have to use a system reconfigure for the settings to be persisted across logins. E.g. when we log out, the home environment specified in the system configuration will be used when logging in again.

Our initial environment is empty, and we initialize using this environment.

guix home reconfigure \
    -L ~/code/dotfiles \
    ~/code/dotfiles/sijo/home/demo/home-environment

There are probably some invocations which might be run to avoid logging out after setting up guix home, but at least logging in again will get us into the home profile.

Just tab-complete the sessionid, or use this way too complex script to avoid pressing tab:

loginctl terminate-session $(loginctl -o json | sed 's/.\+\"session":"\([^"]\+\)".\+/\1/p')

A couple of things before getting a window manager

I’m an old vim user, and migrated to Emacs after using vim for around 16 years. Using only Emacs keybindings makes me extremely unproductive as I don’t know more than the basic movement and editing facilities taught by the tutorial.

So we install a vim emulation, and a package which shows the keys and commands I’m executing to make it easier to follow along when presenting. We’ll also add emacs-next-pgtk to get the development version of Emacs built without X11 support (as we’re using Wayland). At the time of writing, this is a quite stable version of emacs-30, so I’m just a bit on the bleeding edge.

Evil is an extensible vi layer for Emacs. It emulates the main features of Vim, and provides facilities for writing custom extensions.

https://github.com/emacs-evil/evil

Show current command and its binding – https://github.com/tarsius/keycast

;; for emacs-next-pgtk
#:use-module (gnu packages emacs)
;; for emacs packages
#:use-module (gnu packages emacs-xyz)

;; and the packages
(packages (list emacs-next-pgtk
                emacs-keycast
                emacs-evil
                emacs-lispy
                emacs-lispyville))

These packages will be added to the Emacs load path, but we need a restart of Emacs before these shows up.

Get the Sway window manager up and running

Sway is a tiling Wayland compositor and a drop-in replacement for the i3 window manager for X11. It works with your existing i3 configuration and supports most of i3’s features, plus a few extras.

https://swaywm.org/

I have been using a tiling window manager written in and configured in Common Lisp called StumpWM for a few years. Unfortunately, there isn’t a Wayland port, so we have to find another WM.

Before StumpWM, I used i3 and was happy with that. The biggest issue going back is loosing the lisp configuration of StumpWM. Luckily a new project has been created which allows controlling sway using Guile using the IPC protocol: Guile Swayer. I will probably move to this once my system is more stable.

The author of Guile Swayer mirrors my thoughts quite well, and I even thought about creating a similar project before I luckily found this existing effort.

I am an Emacs user and previously used StumpWM, an X11 window manager written in Common Lisp. I believe window managers should be scriptable because the level of workflow customization required by users often exceeds what can be achieved with simple configuration parameters (..).

I had to migrate to Wayland at some point. (..)

The bare minimum would be to add the sway and foot package, reconfigure, and run sway. But this would not give me the resolution, and more importantly, my keybindings.

A fast, lightweight and minimalistic Wayland terminal emulator

https://codeberg.org/dnkl/foot

The default sway configuration can be located by calling which sway, so we can copy it directly with

cp $(dirname $(realpath $(which sway)))/../etc/sway/config \
    ~/code/dotfiles/sijo/home/demo/dotfiles/sway/config

We next add the keyboard binding and output

input type:keyboard {
    xkb_layout us,no
    xkb_variant dvp,
    xkb_options compose:ralt,caps:ctrl_modifier
}

output Virtual-1 {
   mode 1920x1080@60.000Hz
}

And finally, we add this file to our configuration folder.

(simple-service 'sway-configuration
                home-xdg-configuration-files-service-type
                `(("sway/config" ,(local-file "dotfiles/sway/config"))))

At this point, we can run sway and it up and running.

Use fuzzel as an application launcher

Application launcher for wlroots based Wayland compositors, similar to rofi’s drun mode.

https://codeberg.org/dnkl/fuzzel

Although our system works fine, it’s useful to have a launcher. Add fuzzel to the package list and change the sway configuration to set $menu fuzzel.

set $menu fuzzel
bindsym $mod+slash exec $menu

I haven’t digged into launchers for Wayland yet, but I see both wofi and rofi-wayland is potential candidates.

Install IceCat, a free Firefox fork

There are several free browsers available in the main channel, and more non-free available in the nonguix channel. We start by using the free fork of Firefox as Firefox often requires a recompilation.

Some more Wayland tweaking

I have not used Wayland before, but I found these settings which will probably save me some headache later on.

Ref rde/features/wm.scm.

(simple-service 'sijo-profile-environment-variables
                          home-environment-variables-service-type
                          '(("XDG_CURRENT_DESKTOP" . "sway")
                            ("XDG_SESSION_TYPE" . "wayland")
                            ("RTC_USE_PIPEWIRE" . "true")
                            ("SDL_VIDEODRIVER" . "wayland")
                            ("MOZ_ENABLE_WAYLAND" . "1")
                            ("CLUTTER_BACKEND" . "wayland")
                            ("ELM_ENGINE" . "wayland_egl")
                            ("ECORE_EVAS_ENGINE" . "wayland-egl")
                            ("QT_QPA_PLATFORM" . "wayland-egl")
                            ;; https://github.com/swaywm/sway/issues/595
                            ("_JAVA_AWT_WM_NONREPARENTING" . "1")))

The GNU Privacy Guard (GnuPG) setup

PGP is important to my system. I use it to encrypt passwords and other secrets, sign commits etc. Unfortunately, I couldn’t get everything working nicely out of the box, so I created wrappers for pinentry and gpg to work from Emacs without breaking terminal use.

sijo-pinentry

The sijo-pinentry script launches a suitable pinentry program based on the execution context.

sijo-gpg

For some reason, I cannot get pinentry-emacs working as expected. It might be related to some tty setting I’m using incorrectly. sijo-gpg is a hack to use the loopback pinentry when we’re in Emacs. Hopefully I can find the correct way to launch pinentry-emacs to avoid this hack.

service

(service home-gpg-agent-service-type
         (home-gpg-agent-configuration
          (pinentry-program
            (file-append sijo-pinentry "/bin/sijo-pinentry"))
          (extra-content "allow-loopback-pinentry")))

OpenSSH

It is possible to make gpg work as an ssh provider, but for now, I still use ssh-agent.

(service home-ssh-agent-service-type)
(service home-openssh-service-type
         (home-openssh-configuration
          (add-keys-to-agent "yes")))

bash

Finally I add the default bash settings as files to my home configuration so I’m ready to make changes.

(service home-bash-service-type
         (home-bash-configuration
          (bashrc (list (local-file "dotfiles/bash/.bashrc" "bashrc")))
          (bash-profile (list (local-file "dotfiles/bash/.bash_profile" "bash_profile")))))

Done

Most work went into the scripts to transfer the gpg and ssh keys over to the new device, and that is not related to Guix. Getting gpg to play nicely with Emacs also required some experimentation, and this is not the end result as I’d rather have pinentry-emacs working rather than relying on the loopback pinentry.

Guix Home leaves a very good first impression. We’ll see how easy it is to hack on it in practice with the immutability, but running the configuration in a container before a reconfigure seems to work quite well.

Date: 2024-07-13 Sat 00:00

Author: Simen Endsjø

Created: 2024-08-27 Tue 22:24