[solved][flakes] How to use nixosModule in configuration container?

I’m at my wit’s end trying to understand why I get this error.

error: The option `containers.rev-proxy.services.log2ban-hammer' does not exist. Definition values:
       - In `/nix/store/giacnj560kxrspb2ccwf8s4m05ikska1-source/nixos/modules/virtualisation/nixos-containers.nix':
           {
             enable = true;
             redis = {
               host = "127.0.0.1";
             };
           ...

Yet, I can use that service in the configuration.nix (root?).

# /etc/nixos/configuration.nix
{ config, pkgs, ... }: {
  imports = ...;

  networking = ...;

  services.log2ban-hammer = {
    enable = true;
    redis.host = "127.0.0.1";
  };

  ...
}

The setup

I converted NixOS server A to use nix flakes, thusly.

# /etc/nixos/flake.nix
{
  description = "server A config";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-22.05-small";

    log2ban = {
      url = "git+https://gitea.local/boxofrox/log2ban";
      inputs.nixpkgs.follows = "nixpkgs";
    };
  };

  outputs = { self, nixpkgs, deploy-rs, log2ban, ... }:
    let
      system = "x86_64-linux";

      inherit (nixpkgs) lib;

      pkgs = import nixpkgs { inherit system; };

    in {
      nixosConfigurations.server-a = lib.nixosSystem {
        inherit system;
        modules = [
          log2ban.nixosModules.${system}.log2ban-hammer
          ({ pkgs, ... }: {
            nixpkgs.overlays = [ (final: prev: { log2ban = log2ban.packages.${system}.default; }) ];
          })
          ./configuration.nix
        ];
      };
    };
}

The container on server A is created like so:

# /etc/nixos/configuration.nix
{ config, pkgs, ... }: {
  imports = [
    ./containers/rev-proxy/default.nix
  ];

  networking = ...;

  ...
}

# /etc/nixos/containers/rev-proxy/default.nix
{ ... }: {
  containers.rev-proxy = {
    autoStart = true;

    config = { pkgs, ... }: {
      imports = [ ];

      networking.firewall = {
        enable = true;

        allowedTCPPorts = [ 80 443 ];
      };

      services.log2ban-hammer = {
        enable = true;
        redis.host = "127.0.0.1";
      };

      system.stateVersion = "22.05";
    };
  };
}

So, if the configuration.nix can use services.log2ban-hammer, then the import of the log2ban.nixosModule in the flake.nix put the module in what I presume is the “nixpkgs environment”, so what must I do to get the module in the container’s “nixpkgs environment”?

My main reason for using the flake.outputs.nixosConfigurations.<name>.modules was to use the system var defined in the flake instead of trying to snatch the value from pkgs, lib, or config, inside the configuration.nix, and mucking something up.

This behavior is not intuitive to me, and even less intuitive is trying to decipher what things are in nix without a type system to describe what things are expected to look like.

1 Like

Do the same as you did for the host system but in the container. The container is evaluated like another nixos system and does not forward new modules.

you are talking about a nixos configuration. nixpkgs environment would be something under the nixpkgs option.

nixosModules should not have a system, thats only for packages.

I don’t think a stronger type system would help you much here. Nix would still not know what option you are trying to use.

I was trying to refer to whatever source provides the packages and option [schema?] used to evaluate the container’s nixos configuration. If that makes sense, I’m still unclear on the terminology.

Then I’m using flake-utils.lib.eachDefaultSystem improperly in the flake for log2ban. I do think a type system/schema would make this more obvious. Looking at the wiki again, the wiki does show a schema [1], and it seems to be up to date.

[1]: Flakes - NixOS Wiki

So, I figure I need to update my log2ban flake to merge nixosModules like so…

 {
   inputs = {
     naersk.url = "github:nmattia/naersk/master";
     nixpkgs.url = "github:NixOS/nixpkgs/nixos-22.05-small";
     utils.url = "github:numtide/flake-utils";
   };
 
   outputs = { self, nixpkgs, naersk, utils, ... }:
     utils.lib.eachDefaultSystem (system:
       let
         pkgs = import nixpkgs { inherit system; };
         naersk-lib = pkgs.callPackage naersk {};
       in {
         packages.default = naersk-lib.buildPackage {
           root = ./.;
         };
 
         apps.default = utils.lib.mkApp {
           drv = self.packages.${system}.default;
         };
 
-        nixosModules = {
-          log2ban-journald = import ./nix/modules/log2ban-journald.nix;
-        };
       }
-    );
+    ) // {
+        nixosModules = {
+          log2ban-journald = import ./nix/modules/log2ban-journald.nix;
+        };
+    };
 }

…then import the nixos modules into the container like by:

  1. Add log2ban to specialArgs to pass the value into the configuration.nix
 # /etc/nixos/flake.nix
 }
   ...
-  outputs = { self, nixpkgs, deploy-rs, phpNuke, ... }:
+  outputs = { self, nixpkgs, deploy-rs, log2ban, phpNuke, ... }:
     let
       system = "x86_64-linux";

       inherit (nixpkgs) lib;

       pkgs = import nixpkgs { inherit system; };
 
     in {
       nixosConfigurations.prod-1 = lib.nixosSystem {
         inherit system;
-        specialArgs = { inherit phpNuke; };
+        specialArgs = { inherit log2ban phpNuke; };
         modules = [
-          log2ban.nixosModules.${system}.log2ban-journald
+           log2ban.nixosModules.log2ban-journald
           ({ pkgs, ... }: {
             nixpkgs.overlays = [ (final: prev: { log2ban = log2ban.packages.${system}.default; }) ];
           })
           ./configuration.nix
         ];
       };
     };
 }
  1. Add parameter for log2ban in configuration.nix, and… hope that the rev-proxy/default.nix in imports can access this argument? … I can’t tell if this necessary/useful.
 # /etc/nixos/configuration.nix
 # Add log2ban parameter... and hope the "imports" files are given this argument?
-{ config, pkgs, phpNuke, ... }:
+{ config, pkgs, log2ban, phpNuke, ... }:
 
 {
   imports =
     [ # Include the results of the hardware scan.
       ./hardware-configuration.nix
       ./containers/rev-proxy/default.nix
     ];
   ...
 }
  1. Add log2ban parameter to rev-proxy.default.nix, then include the nixos module in the container imports, and I suppose I’ll need an overlay so the log2ban package is available in the container’s “nixos configuration”.
 # /etc/nixos/containers/rev-proxy/default.nix
-{ ... }:
+{ log2ban, ... }:
 
 {
   containers.rev-proxy = {
     autoStart = true;
 
     config = { pkgs, ... }: {
+      imports = [
+        log2ban.nixosModules.log2ban-journald
+      ];
 
+      nixpkgs.overlays = [
+        (final: prev: { log2ban = log2ban.packages.x86_64-linux.default; })
+      ];
 
       ...
     };
   };
 }

This builds without error now, though I’m still a bit dense and uncertain I did this correctly.

  1. The configuration.nix log2ban parameter seems superfluous. I don’t see how it serves any purpose in injecting the log2ban flake input into the files of the imports list.
  2. I’m confused why the configuration.nix did not require me to import/overlay the log2ban modules/packages, but the rev-proxy/default.nix does.
  3. I used a hard-coded value of x86_64-linux in the rev-proxy/default.nix. Is there a variable I should utilize instead (e.g. pkgs.system)?

@Sandro Thanks for setting me straight on the nixosModules and suggesting I import the log2ban modules into the container.

I am not sure which package you mean but the container options are mostly the same as the host one.

You are right on that but flakes are still experimental and we need some better documentation before removing that status.

Not sure what the best way would be here and if something like config.imports could be simply forwarded to the container.

You need to specify system at least in lib.nixosSystem and you should refer everything to that.

You had it in lib.nixosSystem which got forwarded into configuration.nix but apparently not into the container. Not sure if you are doing something wrong because I haven’t used containers like this yet.

I do have lib.nixosSystem { inherit system; modules = [ ... ]; }. I’m not sure what expression (lib.system?) would refer to that inherit system value.

I suppose I can use specialArgs = { inherit system; } to make it available to modules as an argument.

Indeed, I am doing something wrong. It’s just trying figure out what that something might be that’s frustrated me. Thanks for taking the time to share your knowledge. I’m making forward progress again.

I found that pkgs.system exists and decided to use that instead. Given that pkgs is an argument provided to the container configuration, it makes sense that I would select for my overlay package the same system used by nixpkgs packages provided to the container.