Expose option from module

I am trying to expose an option from a module using mkOption, I’m still new and have not been able to read through enough to now how to achieve this.

I’ve tried something like what is mentioned below

Continuing the discussion from Passing parameters into import:

#flake.nix
{
  description = "Nixos config flake";

  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-24.05";

    home-manager = {
      url = "github:nix-community/home-manager/release-24.05";
      inputs.nixpkgs.follows = "nixpkgs";
    };
  };

  outputs = { self, nixpkgs, ... }@inputs:
    let
      system = "x86_64-linux";
      pkgs = nixpkgs.legacyPackages.${system};
    in
    {
      nixosConfigurations = {
        oak = nixpkgs.lib.nixosSystem {
          specialArgs = { inherit inputs; };
          modules = [
            ./hosts/oak/configuration.nix
            ./modNixos
            inputs.home-manager.nixosModules.default
          ];
        };
        samara = nixpkgs.lib.nixosSystem {
          specialArgs = { inherit inputs; };
          modules = [
            ./hosts/samara/configuration.nix
            ./modNixos
            inputs.home-manager.nixosModules.default
          ];
        };
      };
    };
}

Loading lamp.nix in a group from default.nix

#default.nix
{ pkgs, lib, ... }:

{
  imports = [
    ./services/lamp.nix
    ./system/nfs-mounts.nix
    ./services/php.nix
  ]; 

  phpMod.enable = lib.mkDefault true;
}

lamp.nix is where I set the mkOption, but I’m getting an error:

error: undefined variable 'webPath'

at /nix/store/qi0gjwwzgi3mmpc3vqss6i15y894bbz6-source/modNixos/services/lamp.nix:77:16:

76|     extraConfig = ''
77|       root * ${webPath}/${site}
|                ^
78|       php_fastcgi unix/${config.services.phpfpm.pools."${site}.${tld}".socket}

I would think that setting a default would do the trick, but I’m certainly missing something.

#lamp.nix
{ config, pkgs, lib, ... }:
let
  php' = pkgs.php83.buildEnv {
    extensions = ({ enabled, all }: enabled ++ (with all; [
      xdebug
      imagick
    ]));
    extraConfig = ''
      memory_limit = 1024M
      xdebug.mode = debug
      xdebug.start_with_request = yes
      xdebug.idekey = gdbp
    '';
  };
  
  options = {
    lampWebRoot = lib.mkOption {
      default = "/mnt/www";
      example = "/the/web/path";
      description = "Set Web Server Root Directory";
    };
  };

  # config = lib.mkIf config.phpMod.enable {
  config = {
    webPath = config.lampWebRoot;
  };
  
  tld = "localhost";
  
  # Add sites here and the rest will be handled... Caddy, Mariadb databases, directory creation and permissions.
  sites = [
    "devpress"
    "ecotechie"
    "nerdpress"
  ];
in
{
  networking.hosts = {
    "127.0.0.1" = map (site: "${site}") sites;
  };

  services.mysql.enable = true;
  services.mysql.package = pkgs.mariadb;
  services.mysql.ensureDatabases = map (site: "${site}") sites;
  services.mysql.ensureUsers = [
    # NOTE: it is important that `name` matches `$USER` name, this allows us to avoid password authentication
    { name = "sergio";
      ensurePermissions = {
        "*.*" = "ALL PRIVILEGES";
      };
    }
  ];

  services.phpfpm.pools = lib.listToAttrs (map (site: lib.nameValuePair "${site}.${tld}" {
    user = "sergio";
    group = "users";
    phpPackage = php';
    settings = {
      "listen.owner" = config.services.caddy.user;
      "listen.group" = config.services.caddy.group;
      "pm" = "dynamic";
      "pm.max_children" = 5;
      "pm.start_servers" = 2;
      "pm.min_spare_servers" = 1;
      "pm.max_spare_servers" = 5;
      "php_admin_value[error_log]" = "stderr";
      "php_admin_flag[log_errors]" = true;
      "catch_workers_output" = true;
    };
  }) sites);

  services.caddy.enable = true;
  services.caddy.virtualHosts = lib.listToAttrs (map (site: lib.nameValuePair "https://${site}.${tld}:443" {
    extraConfig = ''
      root * ${webPath}/${site}
      php_fastcgi unix/${config.services.phpfpm.pools."${site}.${tld}".socket}
      file_server
    ''; }) sites);

  # automatically create a directory for each site with appropriate ownership+permissions
  systemd.tmpfiles.rules = map (site: "d ${webPath}/${site} 0755 sergio caddy") sites;
}

Also, how/where would I set webPath or I guess it would be lampWebRoot if I wanted it to be different for another host… Essentially, I want the default for all hosts, but different for the Samara host declared in flake.nix

The lamp.nix you posted does not correspond with the snippet shown in the error message. Please post the actual file you got the error with.

Also, that error has nothing to do with the module system, that’s just a plain old undefined variable.

Hi, thanks for having a look! That is the lamp.nix file. The only “edit” was my adding “#lamp.nix” at the beginning when pasting here.

This is the place where the error comes up on that file:

    extraConfig = ''
      root * ${webPath}/${site}
      php_fastcgi unix/${config.services.phpfpm.pools."${site}.${tld}".socket}
      file_server
    ''; }) sites);

On the same file, I was hoping that the following bit would be defining the default content of webPath

  options = {
    lampWebRoot = lib.mkOption {
      default = "/mnt/www";
      example = "/the/web/path";
      description = "Set Web Server Root Directory";
    };
  };

  config = {
    webPath = config.lampWebRoot;
  };

Good point, though it seems to my noob eyes that I defined a default here:

  options = {
    lampWebRoot = lib.mkOption {
      default = "/mnt/www";
      example = "/the/web/path";
      description = "Set Web Server Root Directory";
    };
  };

and then “defined” webPath with the content of lampWebRoot’s default?

  config = {
    webPath = config.lampWebRoot;
  };

Though, I would love to understand how/where I would define this lampWebRoot for other hosts… Even though the bare minimum default isn’t working. :frowning_face:

Your module’s function creates temporary variables in the let, but then doesn’t use them. The variable at the error doesn’t exist indeed. Only the config variable exists.
https://nix.dev/tutorials/nix-language#names-and-values

If you intend to use module system for config parametrization, it’s not enough to define local variables in the let, they aren’t going to implicitly get exported. Instead, you should have an options and a config attribute in the output attribute set of the module function.
https://nix.dev/tutorials/module-system/a-basic-module/

Thank for that input! I think I understood most of it. I really need to read up more. :smile:

This is what I ended up going with, and it seems to be working. At least for the default assignment:

in
{
  options = {
    lampWebRoot = lib.mkOption {
      default = "/mnt/www";
      example = "/the/web/path";
      description = "Set Web Server Root Directory";
    };
  };

  config = {

    networking.hosts = {
      "127.0.0.1" = map (site: "${site}") sites;
    };

    services.mysql.enable = true;
    services.mysql.package = pkgs.mariadb;
    services.mysql.ensureDatabases = map (site: "${site}") sites;
    services.mysql.ensureUsers = [
      # NOTE: it is important that `name` matches `$USER` name, this allows us to avoid password authentication
      { name = "sergio";
        ensurePermissions = {
          "*.*" = "ALL PRIVILEGES";
        };
      }
    ];

    services.phpfpm.pools = lib.listToAttrs (map (site: lib.nameValuePair "${site}.${tld}" {
      user = "sergio";
      group = "users";
      phpPackage = php';
      settings = {
        "listen.owner" = config.services.caddy.user;
        "listen.group" = config.services.caddy.group;
        "pm" = "dynamic";
        "pm.max_children" = 5;
        "pm.start_servers" = 2;
        "pm.min_spare_servers" = 1;
        "pm.max_spare_servers" = 5;
        "php_admin_value[error_log]" = "stderr";
        "php_admin_flag[log_errors]" = true;
        "catch_workers_output" = true;
      };
    }) sites);

    services.caddy.enable = true;
    services.caddy.virtualHosts = lib.listToAttrs (map (site: lib.nameValuePair "https://${site}.${tld}:443" {
      extraConfig = ''
        root * ${config.lampWebRoot}/${site}
        php_fastcgi unix/${config.services.phpfpm.pools."${site}.${tld}".socket}
        file_server
      ''; }) sites);

    # automatically create a directory for each site with appropriate ownership+permissions
    systemd.tmpfiles.rules = map (site: "d ${config.lampWebRoot}/${site} 0755 sergio caddy") sites;
  };
}

I’ll try later today to use this configuration on the samara host:

    let
      system = "x86_64-linux";
      pkgs = nixpkgs.legacyPackages.${system};
    in
    {
      nixosConfigurations = {
        oak = nixpkgs.lib.nixosSystem {
          specialArgs = { inherit inputs; };
          modules = [
            ./hosts/oak/configuration.nix
            ./modNixos
            inputs.home-manager.nixosModules.default
          ];
        };
        samara = nixpkgs.lib.nixosSystem {
          specialArgs = { inherit inputs; };
          modules = [
            ./hosts/samara/configuration.nix
            ./modNixos
            inputs.home-manager.nixosModules.default
          ];
          config.lampWebRoot = "/var/www";
        };
      };
    };