#! emacs --script ;; -*- org -*- (find-file load-file-name) (org-mode) (org-babel-tangle) (kill-emacs) #+STARTUP: showeverything * Introduction This guide is a literate program to help you bootstrap a working guix home install onto your Librem 5 running PureOS. Guix System does not yet support the Librem 5, but you can still install the guix package manager on the Librem 5. I detail here everything I touched in PureOS, and leave the rest of the guix hacking to you. The Librem 5 has only ~30GiB of internal memory, so this process puts guix, as well as all of your personal files, on a μSD, which I assume from here on that you have already inserted. There is no garuntee that it will work, especially as systems change and get updated, and you should understand/test each line before running it. In theory, you should be able to open your new Librem 5 and obtain this program by running (in ~): #+begin_src shell :tangle no sudo bash -c "apt update && apt upgrade -y && apt install emacs -y" emacs --eval '(eww "zacchae.us/guix-usd.org")' -f org-mode #+end_src Convenience blocks for getting more screen realestate in gui (use C-c C-c). #+begin_src elisp :tangle no :results none (tool-bar-mode -1) (menu-bar-mode -1) (toggle-frame-fullscreen) #+end_src or tui (launching emacs with -nw) #+begin_src elisp :tangle no :results none (xterm-mouse-mode) (menu-bar-mode -1) #+end_src Make this buffer a local copy and enable edits #+begin_src elisp :tangle no :results none (write-file "~/guix-usd.org") (kill-buffer "guix-usd.org") (find-file "~/guix-usd.org") #+end_src and generate the script files #+begin_src elisp :tangle no :results none (org-babel-tangle) #+end_src In theory, you should be able to run the following to get a working guix home, but this is not recommended until a later, more stable version of guix-usd.org. For now, this file is more of a reference. #+begin_src shell :tangle no ./guix-usd.org ./guix-usd.bootstrap ./guix-usd.configure #+end_src This should leave you with a functional home.scm which you can start from. However, you may end up with a bricked device that must be re-flashed, which is [[*Re-flahsing from Guix][difficult to do from Guix]]. There will be no warnings printed from the code, and I unashamedly pass "force" flags to make dangerous operations go through. I do try to highlight dangers in the text here, so it is "slightly" safer if you read along and do things manually. Additionally, some operations are performed (like appending to /etc/crypttab) that may break your system if run twice without reverting files. If by some miracle, you follow this guide and end up with a working device, you will have a setup like the following: - At boot, when you decrypt your Librem 5's eMMC memory (i.e. /), it will attempt to decrypt your μSD using a key file located in /etc. - If the μSD decrypts successfully, then it will mount btrfs subvolumes from the decrypted μSD at /home, /gnu, and /var/guix. - This means your home, the guix store, and current state of guix are all stored on your μSD. - If the μSD fails to decrypt, then: - /gnu and /var/guix will fail to mount. - guix will be unusable - /home will be mounted from a file ** Final Warning This guide has you modify the following files: /etc/fstab /etc/crypttab Optionally modify the following: /lib/systemd/system/guix-daemon.service /etc/defaults/keyboard /etc/passwd Create the following files: /etc/luks-keys/* /gnu /var/guix And completely destroy any data on your μSD. This is your final warning to do a back up and pray. * Initial setup We will be setting up the entire μSD as a singular encrypted device with a btrfs filesystem and subvolumes to hold guix and your files #+begin_src shell :tangle guix-usd.bootstrap :shebang #!/bin/sh sudo bash -c "apt update && apt upgrade -y && apt install btrfs-progs guix" #+end_src The μSD encryption keys will be in /etc/luks-keys, and we will need mount points for guix folders /gnu and /var/guix #+begin_src shell :tangle guix-usd.bootstrap sudo mkdir /etc/luks-keys /gnu /var/guix sudo chmod o-rwx /etc/luks-keys #+end_src * Encrypting your μSD To my knowledge, there is no way to prompt the user for a second encryption passphrase for the μSD at boot, hence the only way to decrypt the μSD at boot is to have a key file stored in your file tree. This means that even if you remove your μSD, if you unlock your phone, then the keys to your μSD could be extracted from your phone. Additionally, the following will erase any data which was previously on the μSD. #+begin_src shell :tangle guix-usd.bootstrap sudo dd if=/dev/urandom of=/etc/luks-keys/disk_secret_key bs=512 count=8 echo Encrypting device. Enter passphrase below (a few times). echo This passphrase will be usable in addition to the key file at: echo /etc/luks-key/disk_secret_key sudo umount /dev/sda* sudo cryptsetup luksFormat /dev/sda --batch-mode sudo cryptsetup luksAddKey /dev/sda /etc/luks-keys/disk_secret_key #+end_src * Setting up your btr file system Open (map) the encrypted μSD, reformat the contents as btrfs, mount the mapped device, and create subvolumes for /home, /gnu, and /var/guix. Additionally, copy over all files from your home directory as a starting point for your new home directory. #+begin_src shell :tangle guix-usd.bootstrap sudo cryptsetup open /dev/sda crypt_sd --key-file=/etc/luks-keys/disk_secret_key sudo mkfs.btrfs --force /dev/mapper/crypt_sd -L btros sudo mount LABEL=btros /mnt sudo btrfs subvolume create /mnt/home sudo btrfs subvolume create /mnt/gnu sudo btrfs subvolume create /mnt/varguix sudo cp -a /home/purism /mnt/home/ sudo umount /mnt #+end_src * Decrypting/Mounting at boot The following describes the steps to decrypt and mount your now-set-up μSD at boot. ** Decrypting the μSD To decrypt at boot, append the necessary entry to /etc/crypttab #+begin_src shell :tangle guix-usd.bootstrap echo crypt_sd UUID=$(sudo cryptsetup luksUUID /dev/sda) \ /etc/luks-keys/disk_secret_key nofail,luks \ | sudo tee -a /etc/crypttab #+end_src This will use the luks UUID to identify the μSD, and the 'nofail' flag ensures the system will still boot if μSD is broken or missing. ** mounting #+begin_src text :tangle guix-usd.service [Unit] Description=mount decrypted home if μSD exists Before=user.slice guix-daemon.service gnu-store.mount guix-publish.service Requires=systemd-cryptsetup@crypt_sd.service After=systemd-cryptsetup@crypt_sd.service [Service] Type=oneshot ExecStart=/usr/bin/mount /dev/mapper/crypt_sd /home -o subvol=home ExecStart=/usr/bin/mount /dev/mapper/crypt_sd /gnu -o subvol=gnu ExecStart=/usr/bin/mount /dev/mapper/crypt_sd /var/guix -o subvol=varguix ExecStop=/usr/bin/umount /home RemainAfterExit=True [Install] WantedBy=local-fs-pre.target #+end_src #+begin_src shell :tangle guix-usd.configue cp guix-usd.service /etc/systemd/system/ systemctl daemon-reload systemctl enable guix-usd #+end_src * Setting up guix home This section assumes you have successfully done all the steps described above and rebooted. First, you should do a guix pull as your user, and additionally as root. #+begin_src shell :tangle guix-usd.configure :shebang #!/bin/sh su -c "guix pull" purism /home/purism/.config/guix/current/bin/guix pull guix archive --authorize < \ ~root/.config/guix/current/share/guix/bordeaux.guix.gnu.org.pub #+end_src Now that root's guix has been setup, you should modify the systemd unit file to use root's guix-daemon. #+begin_src shell :tangle guix-usd.configure sed -i 's/\/usr\/bin\/guix-daemon/\/var\/guix\/profiles\/per-user\/root\/current-guix\/bin\/guix-daemon/' /lib/systemd/system/guix-daemon.service systemctl daemon-reload systemctl restart guix-daemon #+end_src This isn't strictly necessary, but I like that I can update guix-daemon with sudo -i guix pull. This is also helpful because the current (as of this writing) version of guix installed by apt does not check bordeaux.guix.gnu.org for substitutes, something extremely necessary for tiny arm devices that have little RAM. You can, however, enable bordeaux.guix.gnu.org by adding "--substitute-urls='https://bordeaux.guix.gnu.org https://ci.guix.gnu.org'" to the "ExecStart" feild of /lib/systemd/system/guix-daemon.service instead. One other problem I came across is that guix home environment variable initialization fails to properly deal with empty variables. There are ways to fix this by modifying guix-home, but looking at https://issues.guix.gnu.org/61982, it seems that they have decided to make changes to how guix is installed on foreign distros. This means even if you guix pull after this is patched, guix home will probably not work properly until the next major release is adopted in your apt repo. Specifically, ~/.guix-home/setup-environment will assign to the empty XDG_CONFIG_DIRS variable without adding the default "/etc/xdg" value, so programs like phosh will not find /etc/xdg and fail to start. This means if you naively install guix home on your new Librem 5, you will get a black screen on boot... To address this, I add the following line to my shell environment to set XDG_CONFIG_DIRS to the default value in the case that it is empty. #+begin_src scheme :tangle no ("XDG_CONFIG_DIRS" . "$([ -z $XDG_CONFIG_DIRS ] 2> /dev/null && echo /etc/xdg || echo $XDG_CONFIG_DIRS)") #+end_src From here you should be able to use the following starter home.scm at ./home.scm (not tested with bash). #+begin_src scheme :tangle home.scm (use-modules (gnu packages) (gnu services) (gnu home services shells) (guix gexp)) (home-environment (packages (map specification->package (list "emacs" "screen" "glibc-locales" "syncthing" "guile"))) (services (list (service home-bash-service-type (home-bash-configuration (environment-variables '(("XDG_CONFIG_DIRS" . "$([ -z $XDG_CONFIG_DIRS ] 2> /dev/null && echo /etc/xdg || echo $XDG_CONFIG_DIRS)"))))) (service home-zsh-service-type (home-zsh-configuration (environment-variables '(("GUIX_LOCPATH" . "$HOME/.guix-home/profile/lib/locale"))) ;(zshrc (list (plain-file "zshrc" "source $HOME/.guix-home/setup-environment\n"))) (zlogin (list (plain-file "zlogin" "XDG_CONFIG_DIRS=\"$XDG_CONFIG_DIRS\":/etc/xdg\n")))))))) #+end_src And initialize your first home environment! #+begin_src shell :tangle guix-usd.configure su -c 'guix home reconfigure home.scm' purism #+end_src ** Another note on substitutes If trying to run guix home still results in many packages trying to build, it could be that there was a recent push to the guix repo which caused a lot of rebuilds that the build farm can't keep up with. The only solution I know of is to manually check https://ci.guix.gnu.org/jobset/master. Go there and find a commit COMMIT right before a commit which resulted in a large number of builds. Then run #+begin_src shell :tangle no guix pull --commit=COMMIT --allow-downgrades #+end_src This should revert your guix version to one with more substitutes available. * Finishing Touches ** Changing UI scaling I do a lot of things at a terminal or emacs. I want my phone screen to be like a real screen. For this, I change the UI scaling of the builtin screen from 2 to 1.75 like so: #+begin_src shell :tangle guix-usd.candy echo '[output:DSI-1] scale = 1.75' >> /usr/share/phosh/phoc.ini #+end_src See [[elisp:(run-async"gnome-control-center")][gnome-control-panel->Displays->select your monitor-> zoom dropdown]] for different zoom options ** Changing console keyboard layout I like to use the dvorak layout with caps-lock as another control key. For the gui, you need to change your layout in settings, download gnome-tweaks: #+begin_src shell :tangle no apt install gnome-tweaks #+end_src And enable "Caps Lock is also Ctrl" in gnome-tweaks>Keyboard & Mouse>additional Layout Options>Caps Lock behavior. To make the same layout available from a tty, I ran: #+begin_src shell :tangle guix-usd.candy sudo apt install console-data echo ' XKBMODEL="pc105" XKBLAYOUT="us" XKBVARIANT="dvorak" XKBOPTIONS="ctrl:nocaps" BACKSPACE="guess" ' | sudo tee /etc/default/keyboard #+end_src ** toggle fullscreen #+begin_src shell gsettings set org.gnome.desktop.wm.keybindings toggle-fullscreen "['F11']" #+end_src ** Using zsh I personally like zsh over bash for interactive prompts. To change to zsh, run: #+begin_src shell :tangle guix-usd.candy sudo apt install zsh echo Need user passwd to change shell to zsh chsh -s /bin/zsh #+end_src #+begin_src shell :tangle guix-usd.candy echo l5 > /etc/hostname #+end_src * Re-flahsing from Guix If you messed something up, and know what you did, you may want to try fixing your problem using Jumpdrive instead: https://github.com/dreemurrs-embedded/Jumpdrive This will allow you to mount your powered off Librem like a flash drive and make changes to fix your device. I don't have any automated solution for flashing a librem from guix, but I have figured out how to do it. To do so, I mostly followed the instructions at https://developer.puri.sm/Librem5/Development_Environment/Phone/Troubleshooting/Reflashing_the_Phone.html. First, I cloned the librem 5 flash image repository #+begin_src shell :tangle no git clone https://source.puri.sm/Librem5/librem5-flash-image #+end_src The main hiccup here is that the jenkins package required by the flashing script has not been packaged for guix. To make it work, I manually made changes to scripts/librem5-flash-image: comment lines 23-27, 461-484, and add `uboot_board = 'librem5'` to line 485 (line numbers may have changed since). Then, I manually tried to traverse https://arm01.puri.sm/ to find some images, and downloaded the necessary images #+begin_src shell :tangle no mkdir imdir wget https://arm01.puri.sm/job/Images/job/Image%20Build/14006/artifact/librem5r4.img.xz xz -d librem5r4.img.xz mv librem5r4.img imdir wget https://arm01.puri.sm/job/u-boot_builds/job/uboot_librem5_build/lastSuccessfulBuild/artifact/output/uboot-librem5/u-boot-librem5.imx mv u-boot-librem5.imx imdir/ #+end_src Then, from a *ROOT SHELL*, I activated a guix shell, and downloaded necessary packages from pip: #+begin_src shell :tangle no cd librem5-flash-image guix shel python gcc musl python-requests binutils usbutils uuu --pure python3 -m venv venv --upgrade-deps --system-site-packages source ./venv/bin/activate pip3 install tqdm pyyaml ./scripts/librem5-flash-image --skip-download --dir ./imdir #+end_src * connecting to the device Now spawn a syncthing daemon, and take note of the #+begin_src shell syncthing #+end_src ** setting up home #+begin_src shell git init git pull .stsync/git/home .config/config.org guix home reconfigure .config/guix/home.scm #+end_src ** secured devices *** obtaining encypted passwords #+begin_src shell git clone .stsync/git/store .password-store #+end_src *** obtainiing encryption keys Because your home directory is synced across all devices, even possibly compromized devices (which therefore don't have your encryption keys), it is unwise to sync such files via the same syncthing folder. An ideal way to accomplish this is with an auxhilary syncthing folder. In the future, I will add an automated way to utilize syncthing for such a task, but for now, you should transfer them over manually on, say, a USB drive, on a preferably luks encrypted partition. * planned future content - better syncthing automation - changing username - fewer apt dependencies - switch to guix installer from apt - auto screen change - change screen timout - exwm? - guix usd service extends syncthing service - controls pureos install - make syncthing useable as root. Make user passeable?