This module includes configuration that is automatically enabled for any NixOS or nix-darwin system I use.
Unlike most of my modules, there's no "mjm.foo" option to enable the behavior.
{ lib, ... }:
{
imports = [
<<submodules>>
];
options.mjm.minimal = {
enable = lib.mkEnableOption "minimal settings for microvms";
};
}The mjm.minimal.enable option defaults to false, but is set to true for all microVMs. This gives an easy way to disable things that would normally be enabled by default, in order to keep the microVMs small. There's probably a better way to structure this; I don't really like how this feels.
./shell.nix
{ config, ... }: {
programs.fish = {
enable = true;
generateCompletions = !config.mjm.minimal.enable;
};
}My preferred shell is fish, so I want it present and set up properly on all my machines. I avoid generating completions on microVMs because the build times can really start to add up.
./nix.nix
{
config,
inputs,
pkgs,
lib,
...
}:
let
inherit (lib) isStorePath mkIf mkMerge;
<<nix-let-bindings>>
in
{
config = mkMerge [
{
<<nix-config>>
}
(mkIf (!config.mjm.minimal.enable) {
<<nix-non-minimal-config>>
})
];
}Configuration for Nix is split up into two sections, to separate config that should not be set for microVMs. So first I'll go over the things that are set unconditionally.
nix.package = pkgs.lix;
I use Lix as my Nix implementation on all of my machines. I generally have more faith in its quality and direction than the original CppNix version.
nix.settings.experimental-features = [ "nix-command" "flakes" ];
These two features are common to enable by default. The "nix" command is often easier to use than the older nix commands. And while I don't use flakes generally for my own projects, sometimes I need to use them for other things, so it's helpful to have them enabled.
nix.settings = {
substituters = [
"https://attic.midna.dev/homelab"
"https://nix-community.cachix.org"
"https://nixos-apple-silicon.cachix.org"
];
trusted-public-keys = [
"homelab:07TYgsLY1ISZ0T0Byzri5R5UsBCzu/92hMiyzv83dwc="
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
"nixos-apple-silicon.cachix.org-1:8psDu5SA5dAD7qA0zMy5UT292TxeEPzIz8VVEr2Js20="
];
};I use a few binary caches for Nix packages. "attic.midna.dev" is my self-hosted attic cache. The others are for community projects. The nixos-apple-silicon one in particular can be nice to avoid kernel rebuilds, which are quite tedious, especially if my CI builder ends up being the one trying to build it.
The remaining Nix config items are not set for microVMs, either because they don't work or they cause other undesirable behavior in that context.
addNixPath = isStorePath pkgs.path;
nix.registry.nixpkgs.flake.outPath = mkIf addNixPath (builtins.storePath pkgs.path); nix.nixPath = mkIf addNixPath [ "nixpkgs=flake:nixpkgs" ];
These two settings do very similar things. The first sets the "nixpkgs" entry in the system's flake registry to point at the Nixpkgs sources that were used to build the system. This goes through builtins.storePath to avoid an extra copy of the path in the store, which is unnecessary and makes for strange diffs.
Then the second line adds an entry to the NIX_PATH environment variable, so that points to the same path as the flake registry entry. Doing it this way instead of setting the Nix path directly to the store path means that the shell environment doesn't have to be reloaded to see a new path, since the actual environment variable value doesn't actually change.
These entries are not added on microVMs because any change in their configuration will cause them to reboot. Having these entries would cause every Nixpkgs bump to reboot every microVM, even if there were no other changes to it.
nixpkgs.config.allowUnfree = true;
As nice as it would be to be principled about this, I do use some unfree software, so I find it easiest to just set this option globally.
nixpkgs.overlays = [
(final: prev: {
rycee = import inputs.rycee { pkgs = final; };
})
(import ../../../overlay.nix)
];I use two overlays for Nixpkgs on all of my systems. The first pulls in rycee's NUR expressions, which I use because they have packaged for Nix a large number of Firefox extensions. While obviously only desktop systems need those, it's easier to just add the overlay globally.
The second overlay is my own, which adds package definitions from the packages/ directory in my repo. With this, I can easily add new packages or override existing ones.
Both this and the nixpkgs.config setting above are skipped for microVMs because they use the host machine's pkgs, and evaluation will error if these options are set for them.
nix-index = import inputs.nix-index-database { inherit pkgs; };programs.nix-index = {
enable = true;
package = nix-index.nix-index-with-db;
};
environment.systemPackages = [ nix-index.comma-with-db ];nix-index is a useful tool to be able to query for what package contains a particular file. Out of the box, it's a bit inconvenient, as you have to remember to run the nix-index command to build or update the database before you can use nix-locate to look things up. I use the nix-index-database project to get a version that is prebundled with a regularly updated database that I don't have to generate myself.
This project also comes with a version of comma that is bundled with the same database. comma lets you run commands you don't have installed yet by conveniently typing ", " before the command. This can be very useful to run things you don't frequently use without having to update your NixOS config to include them. While there are builtin ways to do similar things, like "nix run nixpkgs#foo", comma is much more convenient.
This is omitted from microVMs both to avoid churn and because comma doesn't work on them, because they lack a running nix-daemon.
./ipv6.nix
{ lib, ... }:
let
inherit (lib) mkOption types;
in
{
options.mjm.ipv6Prefix = mkOption {
type = types.str;
default = "2601:282:0:30e0";
readOnly = true;
};
}This is a dumb problem, but dumb problems still need solutions. There's a few places in my config where I need to hardcode the IPv6 addresses of machines. My ISP unfortunately doesn't guarantee me a stable IPv6 prefix. It's mostly stable: it only seems to change when they come out and do non-trivial work here at the premises. When it does change, it's nice to be able to fix it in one place and have that affect everywhere that cares. It's still a pain to recover from that situation, but it's a little better without this bit of tedious busywork.
Long-term, I'm looking into how I can get a properly stable prefix, which would enable possibly making parts of my setup IPv6-only.
./home-manager.nix
{
inputs,
config,
localModulesPath,
lib,
...
}:
{
home-manager = {
useUserPackages = true;
useGlobalPkgs = true;
extraSpecialArgs = { inherit inputs; };
backupFileExtension = "bak";
<<hm-user>>
};
}I use home-manager to set up my dotfiles on all machines except microVMs. Servers will have less things enabled in home-manager, but it's still nice to have some things set up there. I use the NixOS/nix-darwin module for this, so home-manager activation is part of the overall system setup.
I personally think that useUserPackages and useGlobalPkgs should both be enabled by default when using home-manager this way. The former installs packages from home-manager via the users.users..packages option. The latter makes the pkgs argument for home-manager modules be the same as the NixOS system's, so you don't duplicate pkgs for no good reason. That does force any necessary nixpkgs configuration to happen on the NixOS side, but I find that a small price to pay.
users.mjm = lib.mkIf (!config.mjm.minimal.enable) {
imports =
let
machineSpecificConfig = ../../../hosts/${config.networking.hostName}/home.nix;
in
[ "${localModulesPath}/home-manager" ]
++ lib.optional (lib.pathExists machineSpecificConfig) machineSpecificConfig;
};This actually sets up the configuration for home-manager for the mjm user on the machine. Any machine will import "modules/home-manager", which pulls in all the default behavior as well as options to enable extra things. For machine-specific tweaks, there's some "magic" to look for a home.nix file in the directory corresponding to the host's configuration. If it exists, it will be imported as a home-manager module as well.
text/gemini;lang=en-USThis content has been proxied by September (UNKNO).