I’d like to use a nixpkgs PR (in this case my PR that adds tls mode to security.acme
) in my flake. Very common situation I’d think. There are multiple ways to do this:
- maintaining an own fork (meh)
- patching nixpkgs with
applyPatches
- blacklisting-and-reimporting the relevant modules with
disabledModules
Here’s a flake (also available in this repo) that demonstrates this:
{
description = "Patching nixpkgs in a flake";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-24.11";
# My fork from where I submitted PR#340136
# https://github.com/NixOS/nixpkgs/pull/340136
nixpkgs-yann.url = "github:nobodyinperson/nixpkgs?ref=acme-tls-mode";
# The corresponding patch file for PR#340136
nixpkgs-acme-tls-pr-patch = {
url =
"https://patch-diff.githubusercontent.com/raw/NixOS/nixpkgs/pull/340136.patch";
flake = false;
};
};
# 📟 Run VMs with:
# > nix build .#nixosConfigurations.<NAME>.config.system.build.vm && find -maxdepth 0 -name '*.qcow*' -delete && result/bin/run-*-vm
outputs = { self, ... }@inputs:
let
osConfig = {
security.acme.acceptTerms = true;
security.acme.defaults = {
tlsMode = true;
email = "me@example.org";
server = "https://acme-staging-v02.api.letsencrypt.org/directory";
};
services.nginx.enable = true;
services.nginx.virtualHosts."example.org".enableACME = true;
# 🍳 boilerplate to get VM usable
users.users.me = {
isNormalUser = true;
initialPassword = "asdf";
extraGroups = [ "wheel" ];
};
security.sudo.wheelNeedsPassword = false;
services.getty.autologinUser = "me";
console.keyMap = "de";
system.stateVersion = "nixos-24.11";
};
in {
nixosConfigurations = {
# 👉 Just using my fork to build the system.
# ✅ This works. But then I always have to rebase manually, which is tiring. 😪
viaFork = inputs.nixpkgs-yann.lib.nixosSystem {
system = "x86_64-linux";
modules = [ osConfig ];
};
# 👉 Patching nixpkgs with GitHub's auto-generated PR patch
# ✅ This below stunt also works, the reimporting of the nixpkgs flake seems to be the important thing,
# which many random posts about this topic seem to not mention.
# https://discourse.nixos.org/t/proper-way-of-applying-patch-to-system-managed-via-flake/21073/26?u=nobodyinperson
withApplyPatches = let
nixpkgs' = import inputs.nixpkgs { system = "x86_64-linux"; };
nixpkgsPatched' = nixpkgs'.applyPatches {
name = "nixpkgs-wth-acme-tls-mode";
src = inputs.nixpkgs;
patches = [ inputs.nixpkgs-acme-tls-pr-patch ];
};
nixpkgsPatched = (import "${nixpkgsPatched'}/flake.nix").outputs {
self = inputs.self;
};
in nixpkgsPatched.lib.nixosSystem {
system = "x86_64-linux";
modules = [ osConfig ];
};
# 👉 Via Blacklisting modules, as explained here:
# https://github.com/NixOS/nixpkgs/blob/cceb51f2d43b57023cdd7e8c168b7eeab0779e53/nixos/doc/manual/development/replace-modules.section.md
# 💥 Doesn't even build
withDisabledModules = inputs.nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
{
disabledModules = [
# disable acme and nginx modules (the ones touched in PR#340136)
"security/acme/default.nix" # 👈ℹ️ UPDATE: solution is to remove the `/default.nix` here, see error message
"services/web-servers/nginx/default.nix"
];
imports = [
# reimport acme and nginx modules (the ones touched in PR#340136)
"${inputs.nixpkgs-yann}/nixos/modules/services/web-servers/nginx/default.nix"
# `nix build .#nixosConfigurations.withDisabledModules.config.system.build.vm` says:
# 💥 error: The option `virtualisation.vmVariant.security.acme.certs' in `/nix/store/lb6ypkpf38qsd0p4gc5nqvb97s2brh5h-source/nixos/modules/security/acme' is already declared in `/nix/store/j5qxlcx2zr0bs6nvw45f8j3yf2ijfa48-source/nixos/modules/security/acme/default.nix'
"${inputs.nixpkgs-yann}/nixos/modules/security/acme/default.nix"
];
}
osConfig
];
};
};
};
}
While writing this MVE, I got the applyPatches
-approach to work, of which there is frustratingly few examples out there (and the ones existing often result in missing builtins.currentSystem
or lib.nixosSystem
errors etc.), so I’ll just leave this here.
However, I’d like to understand why the disabledModules
-approach doesn’t work. I blacklist the relevant modules, then reimport them. Why does it somehow import the acme module twice and thus throw an already declared
error?
❯ nix build .#nixosConfigurations.withDisabledModules.config.system.build.vm
error:
… while evaluating 'strict' to select 'drvPath' on it
at /builtin/derivation.nix:1:552:
… while calling the 'derivationStrict' builtin
at /builtin/derivation.nix:1:208:
(stack trace truncated; use '--show-trace' to show the full trace)
error: The option `virtualisation.vmVariant.security.acme.certs' in `/nix/store/lb6ypkpf38qsd0p4gc5nqvb97s2brh5h-source/nixos/modules/security/acme' is already declared in `/nix/store/j5qxlcx2zr0bs6nvw45f8j3yf2ijfa48-source/nixos/modules/security/acme/default.nix'.