Incoming long post, please consider reading at least the following TL;DR before commenting.
TL;DR: Interested in finding the means to manage my dotfiles in a declarative, ‘immutable’/read-only way and with automatic sync across two devices (and a fleet of container environments). The method shouldn’t require the management of my packages.
First of all, I’m still relatively new to managing dotfiles. So far, git
has been doing fine, but time has come to upgrade.
Goals: As I’ve moved from a non-declarative way of administrating my system to one in which some elements are declarative, it just feels appropriate to apply a touch of ‘declarative-ness’ to managing dotfiles as well.
Furthermore, as I’ve been using image-based (‘immutable’) distros for some time already, I want to explore the possibilities of managing dotfiles within that ‘immutable’ paradigm.
Specifics of my usage: The primary desire is to have it working on two systems simultaneously. If possible, changes to one should ‘automatically’ apply to the other and vice versa. Furthermore, the exact content of the managed dotfiles is not the same on both, so differentiation is a requirement. My container workloads can be handled by the likes of chezmoi
and or yadm
. Nonetheless, being able to manage their dotfiles as well is definitely a plus.
Options that I’ve explored and associated (potential) challenges:
-
Nix’ Home Manager. From what I’ve gathered, this offers by default most of what I desire. However, I’m interested to know what the limitations are of managing dotfiles only as I’m not interested in installing any Nix packages. So it would have to manage the dotfiles of packages/software/whatever that weren’t installed with Nix.
Furthermore, to my knowledge, Nix doesn’t play nice with container environments; while this is not a hard requirement, I hope to be wrong on this.EDIT: Could not find sources to back this up. -
Guix with
guix home
. Unless I’m wrong, this is Guix’ Home Manager. So it’s met with similar challenges like those found in the previous paragraph. Furthermore, I’m interested to know if either of the two fares better than the other for my use case. -
While
chezmoi
,yadm
and other known dotfiles managers technically offer a solution, their respective solutions aren’t declarative or ‘immutable’ by default. While I’m sure someone might be able to hack one of them to better fit my needs, I’m not sure if I’m personally willing to commit to that. EDIT: Apparentlychezmoi
is declarative. I currently wonder which other dotfiles managers I might have mistakenly dismissed for disregarding the possibility that they might be declarative. Furthermore,chezmoi
seems to allow declarative control on the read-write permissions of files, which might allow restricting files to just read-only. -
Old, trusty
git
. Probably furthest removed from what I desire by default, but perhaps someone knows how to make it fit regardless.
Please feel free to inform me if I’ve missed anything! Thanks in regards 🙂 !
EDIT: So far chezmoi
has surprised me pleasantly with the possibilities it offers. But before committing, I would like to have some input from our residents that swear by Nix/Guix.
Update: It has been over 24 hours since the last time a comment was posted under this post. While I do hope to receive replies from at least two commenters eventually, I’m less optimistic on getting any replies from those that have significant experience with guix home
. Though I’d love to be wrong on that.
For posterity’s sake; first of all, this has been a great conversation and so I’d like to thank everyone that has contributed! Secondly, I’ve tried to spend a good portion of the last 24 hours to read up on the subjects that were touched upon and evaluate them accordingly. This has led to the following discoveries that might be worth sharing:
- Ansible is a legitimately good piece of software that can be used for this purpose, even if
chezmoi
’s author implies not to be a fan of this. - While Ansible applies configs ‘convergent’ (when done right), Nix’ Home Manager is able to do so ‘congruent’ and does so effortlessly in the sense that -with the advent of flakes- one ‘simply’ does it the ‘correct’ way regardless (though checks and whatnot help elevate everyone to that level relatively easily). I’m not confident on how
chezmoi
fares compared to the other two. Refer to this article for more info on what ‘convergent’ and ‘congruent’ mean in this context. (TL;DR: “ansible will make changes to get it closer to a target state, whereas nix will reach the target state by constructing the target state again”) - Due to the point raised in the previous bullet, (when mastered) Nix’ Home Manager simply seems a far superior option compared to Ansible. Thus Ansible is dismissed in favor of Nix’ Home Manager.
- I’ve also come to appreciate how powerful of a tool
chezmoi
is. Nonetheless, I couldn’t stop noticing how many people that have usedchezmoi
at some point in time eventually switched to Nix’ Home Manager for salvation. With those that didn’t stick to Nix’ Home Manager being open that it was often related to not being able to get it to work *gulp*… - At this point it seems that Nix’ Home Manager is the clear victor, but Guix’
guix home
hasn’t been represented (yet). So that’s what I intend to figure out before committing fully to either Nix’ Home Manager or (perhaps) Guix’guix home
. - As a final note, using any of the tools mentioned doesn’t exclude the use of the other tools. Sometimes one tool just fares better in one particular task compared to the other. Thus, one should not be afraid to mix and match these to best fit their needs. As such; a setup in which Ansible,
chezmoi
and Nix’ Home Manager are used together to manage the dotfiles is perfectly fine.
Final update: (for the foreseeable future)
- The question how Nix’ Home Manager fares against Guix’
guix home
didn’t matter in the end 😅, but this is related to how my system works. In case it wasn’t clear yet, I daily drive Fedora Silverblue. And as it stands, I’m unaware of any method that enables one to install Guix on Fedora Silverblue without putting SELinux from enforcing to permissive. I don’t want to forego SELinux’ enforcing mode for Guix, especially when Nix can be installed without being forced to do that. As such, I’ll start my (perhaps long overdue) journey into the wonderful world of Nix. I would like to once again thank everyone that has contributed! And also thank you for reading this :P !
I’m a fan of managing dotfiles with plain git. I think it could be orchestrated a bit to make it more declarative.
When you say immutable what do you mean? Surely dotfiles are meant to change over time? Where would you like to edit them?
Surely dotfiles are meant to change over time?
Indeed. But any and all changes should await my ‘permission’ of sorts before being committed declaratively (or related) if at all. This might indeed make it hard(er) for software to create and change dotfiles as they will, which is somewhat the intended purpose.
I’m currently learning home-manager. There are some configuration options that let you define common program configurations in nix (the language). But those options are limited and might even require package installation.
So for complex (or existing) configs withou package management, you can just tell home-manager explicitly to take dot file at path A (in a git repo, for instance) and link it to path B. This will check for overwrites too, so if path B already exists it will yell at you and no write over existing files, so no sweat.
You can also define different profiles per machine, so if you need something different per machine home-manager can let you do that too. And since its nix, you can break out configuration files as you would in any other language to organize you dotfiles however you like.
There might be something clever in home manager for mapping a file path in your dotfiles repo to the same directory relative to your $HOME, but it’s likely you’ll just explicitely write something like
xdg.configFile.nvim = { source = ./neovim/init.lua; }
, mapping precisely each file in your git repo to the appropriate config location.Let me know if you have other questions. I’m all aboard on the nixos train so I could be bias.
Thanks a lot for your input; much appreciated!
Let me know if you have other questions.
-
Is it possible to use Nix’ Home Manager to manage dotfiles within a container in such a way that changes applied to said dotfiles within the container would be ‘synced’ with all the other configs for existing (and future) containers?
-
Is it possible to continue to have said functionality if the host doesn’t have Nix’ Home Manager setup/installed? (So, like, can Nix and its Home Manager be installed within a (rootless) container?)
-
Are you by any chance knowledgeable on how Guix’
guix home
relates to Nix` Home Manager and how either of the two might be more suitable in this situation and why?
-
Chezmoi has templates and an ignore if you want it to be different on different machines. You can also specify the data you want templated so its kind of dynamic on your other machines. The automatic bit won’t really be automatic but you could run a cron job or systemd service that runs in the background to automatically pull, update and overwrite your dotfiles on a machine but it might be better to just do that manually whenever you log on to the other machine so you know what will get overwritten
I’ve already mentioned
chezmoi
in my original post. In which I further alluded that it doesn’t quite satisfy my needs unless it (somehow) allows the dotfiles to be managed declaratively and ‘immutable’/read-only. Do you happen to know if one is able to achieve that and (more importantly) how?With chezmoi it will kind of be read only/immutable with templates no? You could use templates in your dotfiles then on local you can specify the data you want to be templated. So your templates would be read only but the actual content in them could be different per machine. And you could have some dotfiles not be templated at all if you don’t use certain configs on different machines.
Reference documentation: https://www.chezmoi.io/user-guide/templating/#using-chezmoitemplates
This seems interesting. I didn’t make the link to ‘immutable’/read-only with templates. But I’ll read up on it and explore the possibilities. Thank you!
I would use nix home manager for this. Home manager has basically three separate layers. The ability to install nix packages for a user, the ability to generate config files, and special modules that combine these things things as an easy way to manage popular programs (like vim or tmux or something). You could probably just stick to the config file generation (see the
xdg.configFile
module).A big downside is that you will have to install the basic nix package manager to get home manager working. You don’t have to use it to install all of your software, but it will still need a
/nix
and a system daemon for home manager as far as I know.nix doesn’t play well with container environments
I’m not sure what this means. What specific things are you trying to do with containers and nix?
If you don’t want to install a bug, complicated piece of software just to manage dotfiles, maybe you could consider Ansible? I know some sysadmin types who keep their local machine configs in Ansible. It has some nice bonus features, like deployment over ssh (nix can do this too btw).
A big downside is that you will have to install the basic nix package manager to get home manager working. You don’t have to use it to install all of your software, but it will still need a /nix and a system daemon for home manager as far as I know.
It’s part of the package-deal I’m willing to commit to as long as the solution suffices 🙂 .
nix doesn’t play well with container environments
I’m not sure what this means.
Perhaps I should have been more precise, but I (seemed to) recall that Nix and/or Nix’ Home Manager were not installable on rootless containers. Though, I failed at finding sources on this. So it might be outdated or just blatantly false (and thus a brain fart). Thus, I’ll edit the OP to reflect this. Thank you for bringing this to my attention!
What specific things are you trying to do with containers and nix?
The final solution should also be applicable in containers. Thus I thought that Nix and Nix’ Home Manager therefore required to be installed/setup within the container environments as well. I might be wrong to assume this, though*.
If you don’t want to install a
bugbig (I suppose), complicated piece of software just to manage dotfiles, maybe you could consider Ansible? I know some sysadmin types who keep their local machine configs in Ansible. It has some nice bonus features, like deployment over ssh (nix can do this too btw).Did I understand you correctly in that you posit that Ansible is more compact, less intrusive and less complicated than Nix’ Home Manager? I’m not comfortable talking about Ansible, but it seemed to me like a grand tool for complete system management (at least for on new installation). Which, honestly, is pretty cool, but seemed to be overkill for what I tried to achieve here. Though, I’d love to be wrong on this. Furthermore, is Ansible container-friendly ?
rootless containers
Are you managing dotfiles in rootless containers? IMO you shouldn’t install nix in a container. If you want to customize your container, run nix outside of the container and tell home manager to apply itself to the container’s file system (
home-manager build
will put the result into aresult
directory, which you can copy). Or, you could just mount your host ~/.config on the container maybe.Ansible
Ansible is a big project, but at the end of the day it’s just a Python package. If you already have Python installed, it’s not really adding that much.
Also obligatory advice for anyone new to Nix: use flakes. Flakes are good and right. It sucks that Nix is in a confusing transition process to flakes, but if you just adopt them completely from the start it makes everything easier. Your home manager config can live in a single flake somewhere that you find convenient, and you can apply it from there.
Are you managing dotfiles in rootless containers?
There’s not a lot to it, but I like to have my stuff related to .zshrc and .vimrc around regardless of what environment I’m in.
IMO you shouldn’t install nix in a container. If you want to customize your container, run nix outside of the container and tell home manager to apply itself to the container’s file system (home-manager build will put the result into a result directory, which you can copy). Or, you could just mount your host ~/.config on the container maybe.
Very informative! Much appreciated!
Ansible is a big project, but at the end of the day it’s just a Python package. If you already have Python installed, it’s not really adding that much.
Perhaps I should look more into this. Thanks for enlightening me on this matter!
Also obligatory advice for anyone new to Nix: use flakes. Flakes are good and right. It sucks that Nix is in a confusing transition process to flakes, but if you just adopt them completely from the start it makes everything easier. Your home manager config can live in a single flake somewhere that you find convenient, and you can apply it from there.
Noted.
This has definitely opened up both Home Manager and Ansible as potential solutions. Perhaps somewhat random, but have you by any chance engaged with Guix’
guix home
?About Ansible, it’s not declarative in the same way Nix is. The way it actually works is it executes little Python programs based on your config. But if you stick to the high level modules, it has a declarative feel. Also, the Python aspect is useful because you can include bits of Python to manage things like generating complicated config files.
I haven’t checked out
guix home
, but it looks interesting. I have been doing some Lisp recently, so maybe the time is coming.About Ansible, it’s not declarative in the same way Nix is. The way it actually works is it executes little Python programs based on your config. But if you stick to the high level modules, it has a declarative feel.
Would it be correct to compare this to how declarative post-installation scripts written in bash feel like? Or is it really declarative, but just not to the level of Nix?
Btw, I just want to thank you for the heads-up 🙂 !
You could try ansible
While great as a last resort, to me this seems overkill. Though, I would love to be wrong on this. Is it even container-friendly?
That depends on what you mean by container. I use it to orchestrate Docker containers for my infrastructure and then some.
I use it to orchestrate Docker containers for my infrastructure and then some.
Very interesting. I will definitely look into this! Much appreciated!
I don’t know, I don’t have any experience with it
Aight. Thanks, regardless 🙂 !