How to add local files into nginx derivation for nix-shell?

How do I create a nix-shell for nginx and refer to config files in my git repo?

Secondly, can you configure nginx via nix-shell in an elegant way similar to nixos server services? (I’ve using nixpkgs single user installation on macOS).

Her’s what I’ve got so far that’s failing to find the nginx.conf file in my local directory containing the shell.nix file.

{ pkgs ? import <nixpkgs> {} }:
with pkgs;

let
  nginx = pkgs.nginx.overrideAttrs (oldAttrs: rec {
    name = "signature-nginx-${oldAttrs.version}";
    postInstall = oldAttrs.postInstall + ‘'
      # ./nginx.conf not found
      cp ./nginx.conf $out/config/nginx.conf
    '';
  });

in mkShell {
  name = “my-shell";
  buildInputs = [
    nginx
  ];

  shellHook = ‘'
    echo Let’s Nix!;
  '';
}
1 Like

Well one option seemed to be to reverse the requirement. i.e., rather than overriding the derivation, start up nginx from its installation dir and refer to the desired config file.

e.g.,

{ pkgs ? import <nixpkgs> {} }:
with pkgs;

mkShell {
  name = “nginx-shell";
  buildInputs = [
    nginx
  ];

  shellHook = ''
    
    function ns() {
      pushd env/nginx >/dev/null
      nginx -c nginx.conf -p $PWD $@
      popd > /dev/null
    }

    function nst() {
      pushd env/nginx >/dev/null
      nginx -t -c nginx.conf -p $PWD $@
      popd > /dev/null
    }

    echo “Run nginx when ready"
  '';
  NGINX_HOME = "${nginx}";
}

Assumes config exists in ./env/nginx.

I’d still love to be able to create a derivation, but this gets me working for now.

1 Like

For what it’s worth, your original code didn’t work because the file you were importing didn’t exist within the build. Using cp ${./nginx.conf} $out/conf/nginx.conf would have worked, since the nix expression ./nginx.conf refers to a path next to the expression file, and nix will then track this dependency and determine that the build needs in, then going on to import the path into the nix store and substitute it as appropriate — if you make that change and add -v to the cp command, you’ll find that the actual postInstall refers to a path like /nix/store/m3cbp1dgpn7jy70i1qhxr19si7p2ag8s-nginx.conf.

That said, overriding nginx like this is not the most efficient way to do this, since every change to your config file will require rebuilding nginx from source. A better option might be to use a wrapper, like so:

{ pkgs ? import <nixpkgs> {} }:
with pkgs;

let
  nginx-with-config = pkgs.writeScriptBin "nginx" ''
    exec ${pkgs.nginx}/bin/nginx -c ${./nginx.conf} "$@"
  '';

in mkShell {
  name = "my-shell";
  buildInputs = [
    nginx-with-config 
  ];

  shellHook = ''
    echo Let’s Nix!;
  '';
}

Running nix-shell --run 'cat $(which nginx)' will show you that the same import-into-store thing happens here.

1 Like
  1. Why did you choose writeScriptBin?

    … and not, say,

    • writeScript,
    • writeShellScript ,
    • writeShellScriptBin,
    • or writeTextFile with executable = true;?

    These all seem to do the same thing so simply out of habit? (There are so many ways to do the same thing with Nix that I certainly try to stick one way in my scripts to avoid future confusion.)

  2. Also, when does it matter if the written into the Nix store has a specific directory structure? That is, embedded in bin or similar.


For future self:

Please do not bump old threads with tangential questions, doing so notifies everyone involved. And it is not like the question can only be answered by the original poster. And it is possible they have forgot the reason. Instead, open a new thread and link to the old one:

How to reply to a linked topic


The point of Bin variant of trivial builders is that the produced output will follow FHS so adding them to derivations inputs will put the script on PATH.

I think writeScriptBin was probably a mistake since it will not include a shebang and thus it might not be executable (in most shells). writeShellScriptBin would have been the correct choice here.

2 Likes