Before we get to the actual setup, I’ll first share some background on how I arrived at the solution I’m currently using. If you want to go to the actual steps jump to provisioning.
Git
One of the many chores in my day to day digital life is keeping the configurations between my home and work machines synced and tidy. I tried chezmoi1 at some point but it didn’t stick (I don’t recall why as it was many years ago). After some trial and error I have settled on using simple git repository in my home folder which I used for many years. The setup would be like:
cd $HOME
git init
echo "*" > .gitignore
And for every new file I wanted to keep track I’d add it by git add -f <FILE>
and once I’m on a new computer I’d git clone the repository on home folder to
get configuration in their correct place.
That repository contains all my essential configuration; shell files (.profile, fish configuration), applications (waybar, git, niri), my email configuration (aerc, maildir, notmuch), and yes, some of those have secrets stored in plain text (in a private repository, of course 😅).
However that approach has some shortcomings when the configuration between
computers differ. For example I can’t simply commit my mail connection
configuration (aerc/accounts.conf) since I have one for work with corporate
email and one on my home machine with my private email as they would conflict.
Nix to rescue
Now it comes Nix to the rescue! Or more specifically home-manger2.
It all started at work where we had expanded our nix usage as a way to share resource between repositories (e.g.: linter configuration, required binaries to run tests). This daily exposure helped me to better understand its capabilities and it gradually started to grow with me.
So naturally I have gravitated toward home-manger as way to have a global configuration for nix without having to use nixos, and the more I learned the more I saw the potential to use as my local configuration. After a couple of months gradually migrating my setup, I’ve now moved everything over to home-manager.
Besides just dotfiles managing home-mamager allows me to supplement my setup with binaries that are not available on latest alpine. So lets share some details how I’m setting up home manger. Here3 is my full configuration repository for reference which runs on flake mode4. I won’t go into every details of all those files. You’re better off following a dedicated guide on nix for that, but I’ll share some key points.
Looking at flake.nix we have two hostnames/profiles; home and work.
"gabrielgio@workstation.lan" = home-manager.lib.homeManagerConfiguration {
inherit pkgs;
extraSpecialArgs = {
inherit inputs;
git = {
name = "Gabriel A. Giovanini";
email = "g.arakakigiovanini@gridx.de";
};
};
modules = [
./home.nix
./secrets/gridx/gridx.nix
];
};
"gabrielgio@homestation.lan" = home-manager.lib.homeManagerConfiguration {
inherit pkgs;
extraSpecialArgs = {
inherit inputs;
git = {
name = "Gabriel A. Giovanini";
email = "mail@gabrielgio.me";
};
};
modules = [
./home.nix
];
};
Both inherit the base packages and share the same core configuration on
home.nix, which contains shared dotfiles and packages. While you won’t be able
to see the contents for obvious reasons, this file includes work related tools,
terraform linter, awscli2, internal tooling and much more.
Now that extra git configuration is used to configure the proper git configuration for each profiles. That later5 is used to set the jj config files with the correct values.
{
pkgs,
inputs,
git,
...
}: let
tomlFormat = pkgs.formats.toml {};
in {
xdg.configFile."jj/config.toml".source = tomlFormat.generate "config.toml" {
user = {
name = git.name;
email = git.email;
};
...
}
Git crypt
I use git-crypt6 to be able so share secrets between machines and still be able to publicly share most of my configuration.
Why not nix-os?
Pretty much because I like alpine. It is a simple, small and because of that, the entire distro fits on my head7. APK is straightforward to understand and build yourself8. OpenRC follows a simple model that’s easy to make sense of and dead simple to configure. I run it as my home and work computer as well as my server (even running on diskless mode). It gets out of my way, and I haven’t seen any major issues even on major upgrades.
Also there’s something about having 12 version of glibc installed that just does not sit well with me. (some could argue I have felt for the sunk cost fallacy but I will deny it!)
Provisioning
I have recently formatted my home computer and as always I forgot to take notes
so as punishiment exercise, I’ll setup a VM from scratch to validate all
the steps are correct. In the end it should be a couple steps only.
Similar to my other post9 we will be using qemu. First create the disk:
qemu-img create -f qcow2 var.cow2 30G
Later go to alpine and download the latest image for virtual10.
Now we can start VM with:
qemu-system-x86_64 \
-machine accel=kvm \
-display gtk \
-smp $(nproc) \
-m 2048 \
-cdrom alpine-virt-3.22.2-x86_64.iso \
-drive file=var.cow2,if=virtio
Now run the classic setup-alpine then reboot and run setup-desktop sway and
setup-devd udev.
Niri for 3.22 and bonus building APKBUILD
Now there is niri. On alpine it is already on community folder but it is not available on 3.22. This means I need to setup APK building to build that package. This approach is actually easier than build from source code directly, since APKBUILD takes care of all development dependencies.
# make sure you have community repository enabled on /etc/apk/repositories
doas apk add git alpine-sdk
addgroup <USER> abuild # might need to re-login or run: su <USER>
abuild-keygen -a -i
git clone --depth 1 https://gitlab.alpinelinux.org/alpine/aports.git
cd aports/community/niri
abuild -r
Depending on your system configuration it will take some time to build but at
the end there will be a new folder $HOME/packages which contains the result of
the build. Add it to your /etc/apk/repositories.
echo "/home/<USER>/packages/community" >> /etc/apk/repositories
apk add -U niri
To continue, here are the basic packages I typically install. I maintain a shared list of common packages that can all be installed with a single command:
curl https://artifacts.gabrielgio.me/world | xargs -I{} apk add {}
Getting home-manager off the ground
Before we do anything with nix make sure you have nix-daemon running and your
user added to /etc/nix/nix.conf
allowed-users = @nix <USERNAME>
build-users-group = nixbld
max-jobs = <CPU_COUNT>
extra-nix-path = nixpkgs=flake:nixpkgs
experimental-features = nix-command flakes
Then:
rc-service nix-daemon restart
Clone home-manager repository:
cd .config
git clone https://git.gabrielgio.me/home-manager
Now run the shell with nh utility inside of the cloned folder:
nix shell nixpkgs#nh
# inside of the shell run:
nh home switch .
Now on the home folder we should see .profile linked ls -lha $HOME. Once here
exit tty1 and log in again and you should see niri. After that I have to add ssh
and pgp keys and I’m set.