Hello all,
I currently have a flakes configuration, it has more than 9 hosts
They fall under 2 categories:
- Desktops (with a DE & stuff)
- Servers (headless)
- Virtualisation (could be one of above or a completely separate use case)
This is what the tree looks like: link
Explanation:
./flake.nix
> ./configuration.nix
(imports ./hosts/hostname/ + all the host agnostic stuff like ./sys.nix, everything in ./ some things in ./programs/
) > ./hosts/hostname/configuration.nix
(imports hardware-configuration.nix
& ./hosts/category/configuration.nix
(which imports pkgs, programs, other files))
./programs/
is just a bunch of home manager stuff, dont worry about it
These are the important files:
flake.nix
vars.nix
(ive redacted a bunch of stuff for privacy and brevity), I would not like to change my filetree drastically, I have a bunch more important variables in my vars.nix which is why I find having per category & per host variables beneficial
So far, i’ve split-up my configs with:
This is my desired vars.nix structure:
In order of precedence: (1 has most precedence)
1. variables set per hostname
2 category set variables
3. general/ globally set variables
I would like to use these variables (in my actual configuration) as so:
e.g: users.users."${attributename.usrname}" = { isnormalUser = true; }
**however, I am not opposed to other implementations as long as they aren't very complex**
Any suggestions on how to do this would be greatly appreciated
I asked an LLM (one good at programming) for a solution, it gave me these snippets:
to my vars.nix:
getVarsForHost = hostname:
let
category = hostCategories.${hostname} or "desktop";
categoryVars = categories.${category};
hostVars = hostOverrides.${hostname} or {};
in
categoryVars // hostVars; # Host overrides have final precedence
in
{
# Export the function
inherit getVarsForHost;`
to my flake.nix:
let
getVarsForHost = import ./vars.nix;
in
{
# Desktop's
## desktop1
nixosConfigurations.desktop1 = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
specialArgs = {
inherit inputs;
hostVars = getVarsForHost "desktop1";
};
what it would look like in-practice
{ config, lib, pkgs, hostVars, hostname, ... }:
{
# Use your variables directly
users.users.${hostVars.usrname} = {
isNormalUser = true;
home = "/home/${hostVars.usrname}";
};
this is a good solution, but I couldn’t get it to work, I kept encountering recursive errors for hours
I found a solution, it works exactly as I intended
vars.nix (variables file)
defaults = {
# put ur global/ default settings here
mymainusername = "default";
}
categories = { # host's categories go here
desktops = { # example category named desktop
mymainusername = "admin";
}
}
hosts = { # put your host specific overrides here
hostname1 = { # example host
mymainusername = "usr1";
category = "desktops"; # you must declare what category the host belongs to so it can inherit its variables
}
}
# Explaination: the host hostname1 will have the variable mymainusername == usr1
# a host which also belongs to the desktops category, the variable mymainusername == admin
# another random host thats not in the desktops category would have the variable mymainusername == default
# Logic
getHostVars = hostname:
let
hostConfig = hosts.${hostname} or {};
categoryName = hostConfig.category or null;
categoryConfig = if categoryName != null then categories.${categoryName} or {} else {};
mergedConfig = defaults // categoryConfig // hostConfig;
in
mergedConfig // {
home = "/home/${mergedConfig.usr}";
homeDir = if mergedConfig ? homeDir then mergedConfig.homeDir else "/home/${mergedConfig.usr}";
};
getHostsInCategory = categoryName:
builtins.filter (hostName:
let hostConfig = hosts.${hostName};
in hostConfig ? category && hostConfig.category == categoryName
) (builtins.attrNames hosts);
getHostCategory = hostname:
let hostConfig = hosts.${hostname} or {};
in hostConfig.category or null;
}
put this in your flake.nix file after “outputs”
let
varsConfig = import ./path/to/vars.nix;
in
{
## hostname1
nixosConfigurations.hostname1 = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
specialArgs = {
inherit inputs;
vars = varsConfig.getHostVars "hostname1"; # function arg
};
modules = [
./path/to/configuration.nix
];
};
then to use these variables globally in your config:
{ vars, ...}: # Add the function arg "vars" like so
{
networking.hostName = vars.mymainusername; # this would equal "usr1" for the host, "hostname1"
}
Please feel free to message me if would would like help
1 Like