How to combine apacheHttpd + apacheHttpdPackages?

I’m trying to use nixpkgs (not NixOS) to create a flake that packages Apache Httpd Server with the mod_perl module. I can see that both the server and the module are packaged in Nixpkgs, but I’m unclear on how I should use the two together.

Other frameworks like Python and PHP provide a functions like withPackages or withExtensions, but the apacheHttpd doesn’t seem to have anything similar.

I’ve looked at the NixOS implementation, and from what I can tell I need to:

  1. Override mod_perl to use the outPath of my apacheHttpd package in it’s build step
  2. Move or symlink the resulting modules/mod_perl.so file into my apacheHttpd package’s module directory
  3. Add a LoadModule perl_module modules/mod_perl.so line to my package’s httpd.conf

Unfortunately, I’m struggling with how to do these steps in a Flake, has anyone built something like this before?

What you’re saying is correct, though not necessarily easy as you have found.

As you have noticed we don’t explicitly support what you want because the way we compile httpd plugins are .so files which are generally referenced in config files.

But all is not lost …

My memory is rough on this but I’m fairly certain there is a reliable way to pass plugins via the command line in an extensible way. What we can do is create a wrapper around the package and passes the plugins via command line option. This is analogous (though not the same) to what we do with php.

I’ll try to find a few minutes to write an example up for you.

Out of curiosity what is your intention with this? You’ll need a configuration file - how are you providing that?

Thank you! What you’re saying about the wrapper makes sense, I can take a look at the php example as well.

For my intention, I’m looking for a way to setup a LAMP stack that I can run on multiple machines/OS’s, without having to reinstall and configure everything from scratch.

For the config – one option would be to generate the config in the Nix derivation (like the nixOS module does), but I’m leaning towards keeping the project’s httpd.conf in my project directory, and then starting apache with apachectl start -f httpd.conf

I didn’t actually load up a website, but after some minor tweaking this snippet really appears to do what you want:

{
  description = "A very basic flake";

  outputs = { self, nixpkgs }: {

    packages.x86_64-linux.apache = with nixpkgs.legacyPackages.x86_64-linux;
      let
        mod_perl = pkgs.apacheHttpdPackages.mod_perl.override { apacheHttpd = apacheHttpd.out; };
      in
        symlinkJoin {
          name = "httpd-with-plugins";
          paths = [ apacheHttpd ];
          nativeBuildInputs = [ makeWrapper ];
          postBuild = ''
            wrapProgram $out/bin/httpd --add-flags -C --add-flags "'LoadModule perl_module ${mod_perl}/modules/mod_perl.so'"
          '';
        };

  };
}

On a related note you may want to keep a close eye on system-manager which looks very promising from our amazing community friends at :heart: Numtide :heart:.

1 Like

Looks like that works! Need to test it with an actual example, but it does seem to load the module:

❯ ./result/bin/httpd -t -D DUMP_MODULES     
Loaded Modules:
 core_module (static)
 so_module (static)
 http_module (static)
 **perl_module (shared)**
 mpm_event_module (shared)
 authn_file_module (shared)
...

System manager looks interesting, having NixOS modules on other systems w/ nixpkgs would be really useful. I’ll keep an eye onit

Great!

I’m curious about how well this will work for you. A few years back I made use of httpd on NixOS to support a ton of fairly complicated mod_perl applications with great success.

If you don’t mind let me know how it goes. :smiley:

There was one more piece missing – when I tried to actually run a perl script with the flake above, I got the following perl error:

[Sun Jul 02 11:42:47.730155 2023] [perl:error] [pid 28837:tid 6162722816] [client ::1:56920] failed to resolve handler `ModPerl::Registry’: Can’t locate ModPerl/Registry.pm in @INC (you may need to install the ModPerl::Registry module)

It looks like for this to run successfully, you need perl, apacheHttpd, and mod_perl all bundled together. I fixed this by adding pkg.perl.out as an input to mod_perl, and then adding both perl and mod_perl to the symlinkJoin. So my final flake looked like this:

{
  description = "A very basic flake";

  inputs = {
      nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
      flake-utils.url = "github:numtide/flake-utils";
  };

  outputs = { self, nixpkgs, flake-utils } :
    flake-utils.lib.eachDefaultSystem (system:
      let
        pkgs = nixpkgs.legacyPackages.${system};
        mod_perl = pkgs.apacheHttpdPackages.mod_perl.override { apacheHttpd = pkgs.apacheHttpd.out; perl = pkgs.perl.out;};
      in {
        packages = with pkgs; rec {
          apache = symlinkJoin {
            name = "apache-with-perl";
            paths = [apacheHttpd perl mod_perl];
            nativeBuildInputs = [makeWrapper];
            postBuild = ''
              wrapProgram $out/bin/httpd --add-flags -C --add-flags "'LoadModule perl_module ${mod_perl}/modules/mod_perl.so'";
          '';
          };
          default = apache;
        };
      }
    );
}

Once I had this, i could now run the hello world example on the mod_perl docs

This is what I had done on NixOS:

{ config, pkgs, lib, ... }:
let
  perlEnv = pkgs.perl.withPackages (perlPackages: with perlPackages; [
    CGI
    CGIMinimal
    DataDumper
    DBDmysql
    DBDOracle
    DBDsybase
    DBI
    HTTPMessage
    ImageSize
    IOSocketSSL
    JSON
    LWP
    LWPProtocolHttps
    MathBigInt
    MIMEBase64
    MIMELite
    NetSFTPForeign
    NetSNPP
    URI
    URIFind
  ];
in
{
  config = {
    services.httpd.extraConfig = ''
      SetEnv PERL5LIB ${perlEnv}/lib/perl5/site_perl
    '';
  };
}

In your case I think you just add another argument, like so:

--add-flags -C --add-flags "'SetEnv PERL5LIB ${perlEnv}/lib/perl5/site_perl'"
1 Like