From 00cb53de4fa2ba9fcdb52f504943d6ec8ebe5ce5 Mon Sep 17 00:00:00 2001 From: Izorkin Date: Mon, 20 Nov 2023 22:51:21 +0300 Subject: [PATCH 1/5] nginx: fix nginx binary pathname --- pkgs/servers/http/nginx/generic.nix | 3 ++- pkgs/servers/http/openresty/default.nix | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/pkgs/servers/http/nginx/generic.nix b/pkgs/servers/http/nginx/generic.nix index 4ca4bd75d6b6..5963d8c9745f 100644 --- a/pkgs/servers/http/nginx/generic.nix +++ b/pkgs/servers/http/nginx/generic.nix @@ -68,6 +68,7 @@ stdenv.mkDerivation { ++ mapModules "inputs"; configureFlags = [ + "--sbin-path=bin/nginx" "--with-http_ssl_module" "--with-http_v2_module" "--with-http_realip_module" @@ -184,7 +185,7 @@ stdenv.mkDerivation { postInstall = let - noSourceRefs = lib.concatMapStrings (m: "remove-references-to -t ${m.src} $out/sbin/nginx\n") modules; + noSourceRefs = lib.concatMapStrings (m: "remove-references-to -t ${m.src} $out/bin/nginx\n") modules; in noSourceRefs + postInstall; passthru = { diff --git a/pkgs/servers/http/openresty/default.nix b/pkgs/servers/http/openresty/default.nix index 433d8fd3969b..971c1e28cdb0 100644 --- a/pkgs/servers/http/openresty/default.nix +++ b/pkgs/servers/http/openresty/default.nix @@ -41,7 +41,7 @@ callPackage ../nginx/generic.nix args rec { postInstall = '' ln -s $out/luajit/bin/luajit-2.1.0-beta3 $out/bin/luajit-openresty - ln -s $out/nginx/sbin/nginx $out/bin/nginx + ln -s $out/nginx/bin/nginx $out/bin/nginx ln -s $out/nginx/conf $out/conf ln -s $out/nginx/html $out/html ''; From 86efccfa45b058d51c429105dc2108e2ad1da005 Mon Sep 17 00:00:00 2001 From: Izorkin Date: Mon, 20 Nov 2023 23:04:20 +0300 Subject: [PATCH 2/5] angie: init at 1.4.0 --- .../services/web-servers/nginx/default.nix | 14 +++--- nixos/tests/nginx-variants.nix | 10 ++--- pkgs/servers/http/angie/default.nix | 45 +++++++++++++++++++ pkgs/servers/http/nginx/generic.nix | 3 +- pkgs/top-level/all-packages.nix | 19 ++++++++ 5 files changed, 80 insertions(+), 11 deletions(-) create mode 100644 pkgs/servers/http/angie/default.nix diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix index 6ea24e65f220..6c08d0aee3d7 100644 --- a/nixos/modules/services/web-servers/nginx/default.nix +++ b/nixos/modules/services/web-servers/nginx/default.nix @@ -649,6 +649,8 @@ in Nginx package to use. This defaults to the stable version. Note that the nginx team recommends to use the mainline version which available in nixpkgs as `nginxMainline`. + Supported Nginx forks include `angie`, `openresty` and `tengine`. + For HTTP/3 support use `nginxQuic` or `angieQuic`. ''; }; @@ -1144,18 +1146,20 @@ in } { - assertion = cfg.package.pname != "nginxQuic" -> !(cfg.enableQuicBPF); + assertion = cfg.package.pname != "nginxQuic" && cfg.package.pname != "angieQuic" -> !(cfg.enableQuicBPF); message = '' services.nginx.enableQuicBPF requires using nginxQuic package, - which can be achieved by setting `services.nginx.package = pkgs.nginxQuic;`. + which can be achieved by setting `services.nginx.package = pkgs.nginxQuic;` or + `services.nginx.package = pkgs.angieQuic;`. ''; } { - assertion = cfg.package.pname != "nginxQuic" -> all (host: !host.quic) (attrValues virtualHosts); + assertion = cfg.package.pname != "nginxQuic" && cfg.package.pname != "angieQuic" -> all (host: !host.quic) (attrValues virtualHosts); message = '' - services.nginx.service.virtualHosts..quic requires using nginxQuic package, - which can be achieved by setting `services.nginx.package = pkgs.nginxQuic;`. + services.nginx.service.virtualHosts..quic requires using nginxQuic or angie packages, + which can be achieved by setting `services.nginx.package = pkgs.nginxQuic;` or + `services.nginx.package = pkgs.angieQuic;`. ''; } diff --git a/nixos/tests/nginx-variants.nix b/nixos/tests/nginx-variants.nix index 0faa0127669d..8c24052aacce 100644 --- a/nixos/tests/nginx-variants.nix +++ b/nixos/tests/nginx-variants.nix @@ -7,17 +7,17 @@ with import ../lib/testing-python.nix { inherit system pkgs; }; builtins.listToAttrs ( builtins.map - (nginxName: + (nginxPackage: { - name = nginxName; + name = pkgs.lib.getName nginxPackage; value = makeTest { - name = "nginx-variant-${nginxName}"; + name = "nginx-variant-${pkgs.lib.getName nginxPackage}"; nodes.machine = { pkgs, ... }: { services.nginx = { enable = true; virtualHosts.localhost.locations."/".return = "200 'foo'"; - package = pkgs."${nginxName}"; + package = nginxPackage; }; }; @@ -29,5 +29,5 @@ builtins.listToAttrs ( }; } ) - [ "nginxStable" "nginxMainline" "nginxQuic" "nginxShibboleth" "openresty" "tengine" ] + [ pkgs.angie pkgs.angieQuic pkgs.nginxStable pkgs.nginxMainline pkgs.nginxQuic pkgs.nginxShibboleth pkgs.openresty pkgs.tengine ] ) diff --git a/pkgs/servers/http/angie/default.nix b/pkgs/servers/http/angie/default.nix new file mode 100644 index 000000000000..05fc6ba670fa --- /dev/null +++ b/pkgs/servers/http/angie/default.nix @@ -0,0 +1,45 @@ +{ callPackage +, runCommand +, lib +, fetchurl +, nixosTests +, withQuic ? false +, fetchpatch +, ... +}@args: + +callPackage ../nginx/generic.nix args rec { + version = "1.4.0"; + pname = if withQuic then "angieQuic" else "angie"; + + src = fetchurl { + url = "https://download.angie.software/files/angie-${version}.tar.gz"; + hash = "sha256-gaQsPwoxtt6oVSDX1JCWvyUwDQaNprya79CCwu4z8b4="; + }; + + configureFlags = lib.optional withQuic [ + "--with-http_v3_module" + ]; + + preInstall = '' + if [[ -e man/angie.8 ]]; then + installManPage man/angie.8 + fi + ''; + + postInstall = '' + ln -s $out/bin/nginx $out/bin/angie + ''; + + passthru.tests = { + angie = nixosTests.nginx-variants.angie; + }; + + meta = { + description = "Angie is an efficient, powerful, and scalable web server that was forked from nginx"; + homepage = "https://angie.software/en/"; + license = lib.licenses.bsd2; + platforms = lib.platforms.all; + maintainers = with lib.maintainers; [ izorkin ]; + }; +} diff --git a/pkgs/servers/http/nginx/generic.nix b/pkgs/servers/http/nginx/generic.nix index 5963d8c9745f..b9466e8060f8 100644 --- a/pkgs/servers/http/nginx/generic.nix +++ b/pkgs/servers/http/nginx/generic.nix @@ -25,6 +25,7 @@ outer@{ lib, stdenv, fetchurl, fetchpatch, openssl, zlib, pcre, libxml2, libxslt , fixPatch ? p: p , postPatch ? "" , preConfigure ? "" +, preInstall ? "" , postInstall ? "" , meta ? null , nginx-doc ? outer.nginx-doc @@ -179,7 +180,7 @@ stdenv.mkDerivation { if [[ -e man/nginx.8 ]]; then installManPage man/nginx.8 fi - ''; + '' + preInstall; disallowedReferences = map (m: m.src) modules; diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index e4736778d84b..08243d502a6a 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -3250,6 +3250,25 @@ with pkgs; anewer = callPackage ../tools/text/anewer { }; + angie = callPackage ../servers/http/angie { + zlib = zlib-ng.override { withZlibCompat = true; }; + withPerl = false; + # We don't use `with` statement here on purpose! + # See https://github.com/NixOS/nixpkgs/pull/10474#discussion_r42369334 + modules = [ nginxModules.rtmp nginxModules.dav nginxModules.moreheaders ]; + }; + + angieQuic = callPackage ../servers/http/angie { + zlib = zlib-ng.override { withZlibCompat = true; }; + withPerl = false; + withQuic = true; + # We don't use `with` statement here on purpose! + # See https://github.com/NixOS/nixpkgs/pull/10474#discussion_r42369334 + modules = [ nginxModules.rtmp nginxModules.dav nginxModules.moreheaders ]; + # Use latest quictls to allow http3 support + openssl = quictls; + }; + angle-grinder = callPackage ../tools/text/angle-grinder { }; ansifilter = callPackage ../tools/text/ansifilter { }; From c580ebee409e5bfad058c4c39dad5535fcbbee5a Mon Sep 17 00:00:00 2001 From: Izorkin Date: Mon, 20 Nov 2023 23:08:06 +0300 Subject: [PATCH 3/5] angie-console-light: init at 1.1.1 --- pkgs/servers/http/angie/console-light.nix | 48 +++++++++++++++++++++++ pkgs/top-level/all-packages.nix | 2 + 2 files changed, 50 insertions(+) create mode 100644 pkgs/servers/http/angie/console-light.nix diff --git a/pkgs/servers/http/angie/console-light.nix b/pkgs/servers/http/angie/console-light.nix new file mode 100644 index 000000000000..c39a2001c16c --- /dev/null +++ b/pkgs/servers/http/angie/console-light.nix @@ -0,0 +1,48 @@ +{ lib +, stdenv +, fetchurl +, gzip +, brotli +}: + +stdenv.mkDerivation rec { + version = "1.1.1"; + pname = "angie-console-light"; + + src = fetchurl { + url = "https://download.angie.software/files/${pname}/${pname}-${version}.tar.gz"; + hash = "sha256-Teg+EPl4IvmScTTX3F3rdM6qZ3ztFkMks9oo2B1xHTs="; + }; + + outputs = [ "out" "doc" ]; + + nativeBuildInputs = [ brotli ]; + + dontConfigure = true; + dontBuild = true; + + installPhase = '' + runHook preInstall + + mkdir -p $out/share/angie-console-light + mv ./html $out/share/angie-console-light + + mkdir -p $doc/share/doc/angie-console-light + mv ./LICENSE $doc/share/doc/angie-console-light + + # Create static gzip and brotli files + find -L $out -type f -regextype posix-extended -iregex '.*\.(html|js|txt)' \ + -exec gzip --best --keep --force {} ';' \ + -exec brotli --best --keep --no-copy-stat {} ';' + + runHook postInstall + ''; + + meta = { + description = "Console Light is a lightweight, real-time activity monitoring interface."; + homepage = "https://angie.software/en/console/"; + license = lib.licenses.asl20; + platforms = lib.platforms.all; + maintainers = with lib.maintainers; [ izorkin ]; + }; +} diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index 08243d502a6a..37917bf091c2 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -3269,6 +3269,8 @@ with pkgs; openssl = quictls; }; + angie-console-light = callPackage ../servers/http/angie/console-light.nix { }; + angle-grinder = callPackage ../tools/text/angle-grinder { }; ansifilter = callPackage ../tools/text/ansifilter { }; From b79f1854093a172684321bf1ce8bf26781694362 Mon Sep 17 00:00:00 2001 From: Izorkin Date: Mon, 20 Nov 2023 23:16:02 +0300 Subject: [PATCH 4/5] nixos/tests/nginx-http3: add angie package in testing --- nixos/tests/nginx-http3.nix | 194 +++++++++++++++------------- pkgs/servers/http/angie/default.nix | 1 + 2 files changed, 106 insertions(+), 89 deletions(-) diff --git a/nixos/tests/nginx-http3.nix b/nixos/tests/nginx-http3.nix index fc9f31037f98..22f7f61f10ce 100644 --- a/nixos/tests/nginx-http3.nix +++ b/nixos/tests/nginx-http3.nix @@ -1,97 +1,113 @@ -import ./make-test-python.nix ({lib, pkgs, ...}: +{ system ? builtins.currentSystem, + config ? {}, + pkgs ? import ../.. { inherit system config; } +}: + +with import ../lib/testing-python.nix { inherit system pkgs; }; + let hosts = '' 192.168.2.101 acme.test ''; in -{ - name = "nginx-http3"; - meta.maintainers = with pkgs.lib.maintainers; [ izorkin ]; - nodes = { - server = { pkgs, ... }: { - networking = { - interfaces.eth1 = { - ipv4.addresses = [ - { address = "192.168.2.101"; prefixLength = 24; } - ]; +builtins.listToAttrs ( + builtins.map + (nginxPackage: + { + name = pkgs.lib.getName nginxPackage; + value = makeTest { + name = "nginx-http3-${pkgs.lib.getName nginxPackage}"; + meta.maintainers = with pkgs.lib.maintainers; [ izorkin ]; + + nodes = { + server = { lib, pkgs, ... }: { + networking = { + interfaces.eth1 = { + ipv4.addresses = [ + { address = "192.168.2.101"; prefixLength = 24; } + ]; + }; + extraHosts = hosts; + firewall.allowedTCPPorts = [ 443 ]; + firewall.allowedUDPPorts = [ 443 ]; + }; + + security.pki.certificates = [ + (builtins.readFile ./common/acme/server/ca.cert.pem) + ]; + + services.nginx = { + enable = true; + package = nginxPackage; + + virtualHosts."acme.test" = { + onlySSL = true; + sslCertificate = ./common/acme/server/acme.test.cert.pem; + sslCertificateKey = ./common/acme/server/acme.test.key.pem; + http2 = true; + http3 = true; + http3_hq = false; + quic = true; + reuseport = true; + root = lib.mkForce (pkgs.runCommandLocal "testdir" {} '' + mkdir "$out" + cat > "$out/index.html" <Hello World! + EOF + cat > "$out/example.txt" < "$out/index.html" <Hello World! - EOF - cat > "$out/example.txt" < Date: Mon, 20 Nov 2023 23:22:02 +0300 Subject: [PATCH 5/5] nixos/tests: add test api in angie package --- nixos/tests/all-tests.nix | 1 + nixos/tests/angie-api.nix | 148 ++++++++++++++++++++++++++++ pkgs/servers/http/angie/default.nix | 1 + 3 files changed, 150 insertions(+) create mode 100644 nixos/tests/angie-api.nix diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index c9234fc52536..375532c1f8f9 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -120,6 +120,7 @@ in { amazon-ssm-agent = handleTest ./amazon-ssm-agent.nix {}; amd-sev = runTest ./amd-sev.nix; anbox = runTest ./anbox.nix; + angie-api = handleTest ./angie-api.nix {}; anki-sync-server = handleTest ./anki-sync-server.nix {}; anuko-time-tracker = handleTest ./anuko-time-tracker.nix {}; apcupsd = handleTest ./apcupsd.nix {}; diff --git a/nixos/tests/angie-api.nix b/nixos/tests/angie-api.nix new file mode 100644 index 000000000000..4c8d6b54247b --- /dev/null +++ b/nixos/tests/angie-api.nix @@ -0,0 +1,148 @@ +import ./make-test-python.nix ({lib, pkgs, ...}: +let + hosts = '' + 192.168.2.101 example.com + 192.168.2.101 api.example.com + 192.168.2.101 backend.example.com + ''; + +in +{ + name = "angie-api"; + meta.maintainers = with pkgs.lib.maintainers; [ izorkin ]; + + nodes = { + server = { pkgs, ... }: { + networking = { + interfaces.eth1 = { + ipv4.addresses = [ + { address = "192.168.2.101"; prefixLength = 24; } + ]; + }; + extraHosts = hosts; + firewall.allowedTCPPorts = [ 80 ]; + }; + + services.nginx = { + enable = true; + package = pkgs.angie; + + upstreams = { + "backend-http" = { + servers = { "backend.example.com:8080" = { fail_timeout = "0"; }; }; + extraConfig = '' + zone upstream 256k; + ''; + }; + "backend-socket" = { + servers = { "unix:/run/example.sock" = { fail_timeout = "0"; }; }; + extraConfig = '' + zone upstream 256k; + ''; + }; + }; + + virtualHosts."api.example.com" = { + locations."/console/" = { + extraConfig = '' + api /status/; + + allow 192.168.2.201; + deny all; + ''; + }; + }; + + virtualHosts."example.com" = { + locations."/test/" = { + root = lib.mkForce (pkgs.runCommandLocal "testdir" {} '' + mkdir -p "$out/test" + cat > "$out/test/index.html" <Hello World! + EOF + ''); + extraConfig = '' + status_zone test_zone; + + allow 192.168.2.201; + deny all; + ''; + }; + locations."/test/locked/" = { + extraConfig = '' + status_zone test_zone; + + deny all; + ''; + }; + locations."/test/error/" = { + extraConfig = '' + status_zone test_zone; + + allow all; + ''; + }; + locations."/upstream-http/" = { + proxyPass = "http://backend-http"; + }; + locations."/upstream-socket/" = { + proxyPass = "http://backend-socket"; + }; + }; + }; + }; + + client = { pkgs, ... }: { + environment.systemPackages = [ pkgs.jq ]; + networking = { + interfaces.eth1 = { + ipv4.addresses = [ + { address = "192.168.2.201"; prefixLength = 24; } + ]; + }; + extraHosts = hosts; + }; + }; + }; + + testScript = '' + start_all() + + server.wait_for_unit("nginx") + server.wait_for_open_port(80) + + # Check Angie version + client.succeed("curl --verbose http://api.example.com/console/ | jq -e '.angie.version' | grep '${pkgs.angie.version}'") + + # Check access + client.succeed("curl --verbose --head http://api.example.com/console/ | grep 'HTTP/1.1 200'") + server.succeed("curl --verbose --head http://api.example.com/console/ | grep 'HTTP/1.1 403 Forbidden'") + + # Check responses and requests + client.succeed("curl --verbose http://example.com/test/") + client.succeed("curl --verbose http://example.com/test/locked/") + client.succeed("curl --verbose http://example.com/test/locked/") + client.succeed("curl --verbose http://example.com/test/error/") + client.succeed("curl --verbose http://example.com/test/error/") + client.succeed("curl --verbose http://example.com/test/error/") + server.succeed("curl --verbose http://example.com/test/") + client.succeed("curl --verbose http://api.example.com/console/ | jq -e '.http.location_zones.test_zone.responses.\"200\"' | grep '1'") + client.succeed("curl --verbose http://api.example.com/console/ | jq -e '.http.location_zones.test_zone.responses.\"403\"' | grep '3'") + client.succeed("curl --verbose http://api.example.com/console/ | jq -e '.http.location_zones.test_zone.responses.\"404\"' | grep '3'") + client.succeed("curl --verbose http://api.example.com/console/ | jq -e '.http.location_zones.test_zone.requests.total' | grep '7'") + + # Check upstreams + client.succeed("curl --verbose http://api.example.com/console/ | jq -e '.http.upstreams.\"backend-http\".peers.\"192.168.2.101:8080\".state' | grep 'up'") + client.succeed("curl --verbose http://api.example.com/console/ | jq -e '.http.upstreams.\"backend-http\".peers.\"192.168.2.101:8080\".health.fails' | grep '0'") + client.succeed("curl --verbose http://api.example.com/console/ | jq -e '.http.upstreams.\"backend-socket\".peers.\"unix:/run/example.sock\".state' | grep 'up'") + client.succeed("curl --verbose http://api.example.com/console/ | jq -e '.http.upstreams.\"backend-socket\".peers.\"unix:/run/example.sock\".health.fails' | grep '0'") + client.succeed("curl --verbose http://example.com/upstream-http/") + client.succeed("curl --verbose http://example.com/upstream-socket/") + client.succeed("curl --verbose http://example.com/upstream-socket/") + client.succeed("curl --verbose http://api.example.com/console/ | jq -e '.http.upstreams.\"backend-http\".peers.\"192.168.2.101:8080\".health.fails' | grep '1'") + client.succeed("curl --verbose http://api.example.com/console/ | jq -e '.http.upstreams.\"backend-socket\".peers.\"unix:/run/example.sock\".health.fails' | grep '2'") + + server.shutdown() + client.shutdown() + ''; +}) diff --git a/pkgs/servers/http/angie/default.nix b/pkgs/servers/http/angie/default.nix index d540b55a084f..5c8f2ad7c699 100644 --- a/pkgs/servers/http/angie/default.nix +++ b/pkgs/servers/http/angie/default.nix @@ -33,6 +33,7 @@ callPackage ../nginx/generic.nix args rec { passthru.tests = { angie = nixosTests.nginx-variants.angie; + angie-api = nixosTests.angie-api; angie-http3 = nixosTests.nginx-http3.angieQuic; };