From bf651830a9e64bbea8b6fec1952bc800f0505cfb Mon Sep 17 00:00:00 2001 From: Ilan Joselevich Date: Mon, 21 Sep 2026 14:48:14 +0200 Subject: [PATCH 1/4] nginx: let modules provide nativeBuildInputs Some modules run their own build system from their config script and need build tools in the nginx build. Assisted-by: Claude:claude-fable-5-1 --- pkgs/servers/http/nginx/generic.nix | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkgs/servers/http/nginx/generic.nix b/pkgs/servers/http/nginx/generic.nix index ee5cbca73e81..91617bc154f5 100644 --- a/pkgs/servers/http/nginx/generic.nix +++ b/pkgs/servers/http/nginx/generic.nix @@ -94,7 +94,8 @@ stdenv.mkDerivation { installShellFiles removeReferencesTo ] - ++ nativeBuildInputs; + ++ nativeBuildInputs + ++ mapModules "nativeBuildInputs"; buildInputs = [ openssl From 315b3cde54ae09e66c46a0c645bcf1a5cc1acfcd Mon Sep 17 00:00:00 2001 From: Ilan Joselevich Date: Mon, 21 Sep 2026 14:49:16 +0200 Subject: [PATCH 2/4] nginx: let modules override the nginx derivation A module that brings cmake needs dontUseCmakeConfigure set on nginx, which the existing per-module attributes can't express. Assisted-by: Claude:claude-fable-5-1 --- pkgs/servers/http/nginx/generic.nix | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pkgs/servers/http/nginx/generic.nix b/pkgs/servers/http/nginx/generic.nix index 91617bc154f5..5e95c49d927e 100644 --- a/pkgs/servers/http/nginx/generic.nix +++ b/pkgs/servers/http/nginx/generic.nix @@ -68,12 +68,19 @@ let throw "Module ${mod.name} does not support nginx version ${nginxVersion}!" ); + # Modules can adjust the nginx derivation through passthru.forNginx. + mkDerivation = + args: + lib.foldl (drv: mod: drv.overrideAttrs mod.forNginx) (stdenv.mkDerivation args) ( + lib.filter (mod: mod ? forNginx) modules + ); + in assert lib.assertMsg (lib.unique moduleNames == moduleNames) "nginx: duplicate modules: ${lib.concatStringsSep ", " moduleNames}. A common cause for this is that services.nginx.additionalModules adds a module which the nixos module itself already adds."; -stdenv.mkDerivation { +mkDerivation { inherit pname version nginxVersion; outputs = [ From dba0cf96a9a9e57508562f144eae3188ca6f2dd2 Mon Sep 17 00:00:00 2001 From: Ilan Joselevich Date: Mon, 21 Sep 2026 14:49:31 +0200 Subject: [PATCH 3/4] opentelemetry-cpp: expose opentelemetry-proto in passthru Assisted-by: Claude:claude-fable-5-1 --- pkgs/by-name/op/opentelemetry-cpp/package.nix | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkgs/by-name/op/opentelemetry-cpp/package.nix b/pkgs/by-name/op/opentelemetry-cpp/package.nix index 619927712215..9731d1834b20 100644 --- a/pkgs/by-name/op/opentelemetry-cpp/package.nix +++ b/pkgs/by-name/op/opentelemetry-cpp/package.nix @@ -101,6 +101,9 @@ stdenv.mkDerivation (finalAttrs: { passthru.updateScript = nix-update-script { }; + # For dependents that compile the protos themselves. + passthru.opentelemetry-proto = opentelemetry-proto; + passthru.tests = { # Unfortunately there is no such thing as finalAttrs.finalPackage.override, # so we have to resort to this. From c3d9063e08054e05caebb1057fad210d3bf2d351 Mon Sep 17 00:00:00 2001 From: Ilan Joselevich Date: Mon, 21 Sep 2026 14:50:11 +0200 Subject: [PATCH 4/4] nginxModules.otel: init at 0.1.2 Assisted-by: Claude:claude-fable-5-1 --- nixos/tests/all-tests.nix | 1 + nixos/tests/nginx-otel.nix | 56 +++++++++++++++ .../http/nginx/modules/otel/package.nix | 71 +++++++++++++++++++ 3 files changed, 128 insertions(+) create mode 100644 nixos/tests/nginx-otel.nix create mode 100644 pkgs/servers/http/nginx/modules/otel/package.nix diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index e7276e362108..2e6db69b07d7 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -1253,6 +1253,7 @@ in nginx-modsecurity = runTest ./nginx-modsecurity.nix; nginx-moreheaders = runTest ./nginx-moreheaders.nix; nginx-njs = runTest ./nginx-njs.nix; + nginx-otel = runTest ./nginx-otel.nix; nginx-proxyprotocol = runTest ./nginx-proxyprotocol/default.nix; nginx-pubhtml = runTest ./nginx-pubhtml.nix; nginx-redirectcode = runTest ./nginx-redirectcode.nix; diff --git a/nixos/tests/nginx-otel.nix b/nixos/tests/nginx-otel.nix new file mode 100644 index 000000000000..7aa37d532cca --- /dev/null +++ b/nixos/tests/nginx-otel.nix @@ -0,0 +1,56 @@ +{ + name = "nginx-otel"; + + nodes.machine = + { pkgs, ... }: + { + services.opentelemetry-collector = { + enable = true; + settings = { + receivers.otlp.protocols.grpc.endpoint = "127.0.0.1:4317"; + exporters.debug.verbosity = "detailed"; + service.pipelines.traces = { + receivers = [ "otlp" ]; + exporters = [ "debug" ]; + }; + }; + }; + services.nginx = { + enable = true; + additionalModules = [ pkgs.nginxModules.otel ]; + commonHttpConfig = '' + otel_exporter { + endpoint localhost:4317; + } + otel_service_name "nginx-test"; + otel_trace on; + ''; + virtualHosts."localhost".locations."/".extraConfig = '' + otel_trace_context propagate; + otel_span_name "handle"; + return 200 "otel-ok"; + ''; + }; + }; + + testScript = + { nodes, ... }: + let + cfg = nodes.machine.services.nginx; + in + '' + machine.wait_for_unit("opentelemetry-collector") + machine.wait_for_open_port(4317) + machine.wait_for_unit("nginx") + machine.wait_for_open_port(80) + + machine.succeed("test -e ${cfg.package}/modules/ngx_otel_module.so") + machine.succeed("grep -F ngx_otel_module.so ${cfg.package}/etc/nginx/dynamic-modules.conf") + + response = machine.wait_until_succeeds("curl -fsS http://127.0.0.1/") + t.assertIn("otel-ok", response) + + machine.wait_until_succeeds("journalctl -u opentelemetry-collector --grep 'service.name: Str\\(nginx-test\\)'") + machine.wait_until_succeeds("journalctl -u opentelemetry-collector --grep 'Name +: handle'") + ''; +} diff --git a/pkgs/servers/http/nginx/modules/otel/package.nix b/pkgs/servers/http/nginx/modules/otel/package.nix new file mode 100644 index 000000000000..436074995cce --- /dev/null +++ b/pkgs/servers/http/nginx/modules/otel/package.nix @@ -0,0 +1,71 @@ +{ + abseil-cpp, + c-ares, + cmake, + fetchFromGitHub, + grpc, + lib, + mkNginxPlugin, + nixosTests, + nlohmann_json, + openssl, + opentelemetry-cpp, + pkg-config, + protobuf, + re2, + zlib, +}: + +mkNginxPlugin (finalAttrs: { + pname = "otel"; + version = "0.1.2"; + + src = fetchFromGitHub { + owner = "nginxinc"; + repo = "nginx-otel"; + tag = "v${finalAttrs.version}"; + hash = "sha256-pGe+1nPH8zUQhcyVxH5/nxwNFMsoOYCUecuDVs1rS4o="; + }; + + # nginx-otel can only be loaded dynamically. + dynamic = true; + + nativeBuildInputs = [ + cmake + pkg-config + protobuf + grpc + ]; + + buildInputs = [ + grpc + protobuf + opentelemetry-cpp + c-ares + re2 + abseil-cpp + nlohmann_json + openssl + zlib + ]; + + # Read by the module's config script. nginx's install step does not know + # about the cmake-built .so, so cmake writes it into the modules dir itself. + preConfigure = '' + export NGX_OTEL_CMAKE_OPTS="-DNGX_OTEL_GRPC=package -DNGX_OTEL_SDK=package -DNGX_OTEL_PROTO_DIR=${opentelemetry-cpp.opentelemetry-proto} -DCMAKE_LIBRARY_OUTPUT_DIRECTORY=$out/modules" + ''; + + passthru = { + # cmake's setup hook would replace nginx's configurePhase. + forNginx.dontUseCmakeConfigure = true; + + tests = { inherit (nixosTests) nginx-otel; }; + }; + + meta = { + description = "OpenTelemetry support for nginx"; + homepage = "https://github.com/nginxinc/nginx-otel"; + license = lib.licenses.asl20; + maintainers = with lib.maintainers; [ kranzes ]; + }; +})