Merge pull request #268806 from Izorkin/init-angie

angie: init at 1.4.0
This commit is contained in:
Peder Bergebakken Sundt 2023-12-19 13:51:51 +01:00 committed by GitHub
commit 1a647a10b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 389 additions and 102 deletions

View File

@ -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.<name>.quic requires using nginxQuic package,
which can be achieved by setting `services.nginx.package = pkgs.nginxQuic;`.
services.nginx.service.virtualHosts.<name>.quic requires using nginxQuic or angie packages,
which can be achieved by setting `services.nginx.package = pkgs.nginxQuic;` or
`services.nginx.package = pkgs.angieQuic;`.
'';
}

View File

@ -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 {};

148
nixos/tests/angie-api.nix Normal file
View File

@ -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" <<EOF
<html><body>Hello World!</body></html>
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()
'';
})

View File

@ -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" <<EOF
<html><body>Hello World!</body></html>
EOF
cat > "$out/example.txt" <<EOF
Check http3 protocol.
EOF
'');
};
};
};
client = { pkgs, ... }: {
environment.systemPackages = [ pkgs.curlHTTP3 ];
networking = {
interfaces.eth1 = {
ipv4.addresses = [
{ address = "192.168.2.201"; prefixLength = 24; }
];
};
extraHosts = hosts;
};
security.pki.certificates = [
(builtins.readFile ./common/acme/server/ca.cert.pem)
];
};
};
testScript = ''
start_all()
server.wait_for_unit("nginx")
server.wait_for_open_port(443)
# Check http connections
client.succeed("curl --verbose --http3-only https://acme.test | grep 'Hello World!'")
# Check downloadings
client.succeed("curl --verbose --http3-only https://acme.test/example.txt --output /tmp/example.txt")
client.succeed("cat /tmp/example.txt | grep 'Check http3 protocol.'")
# Check header reading
client.succeed("curl --verbose --http3-only --head https://acme.test | grep 'content-type'")
client.succeed("curl --verbose --http3-only --head https://acme.test | grep 'HTTP/3 200'")
client.succeed("curl --verbose --http3-only --head https://acme.test/error | grep 'HTTP/3 404'")
# Check change User-Agent
client.succeed("curl --verbose --http3-only --user-agent 'Curl test 3.0' https://acme.test")
server.succeed("cat /var/log/nginx/access.log | grep 'Curl test 3.0'")
server.shutdown()
client.shutdown()
'';
};
extraHosts = hosts;
firewall.allowedTCPPorts = [ 443 ];
firewall.allowedUDPPorts = [ 443 ];
};
security.pki.certificates = [
(builtins.readFile ./common/acme/server/ca.cert.pem)
];
services.nginx = {
enable = true;
package = pkgs.nginxQuic;
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" <<EOF
<html><body>Hello World!</body></html>
EOF
cat > "$out/example.txt" <<EOF
Check http3 protocol.
EOF
'');
};
};
};
client = { pkgs, ... }: {
environment.systemPackages = [ pkgs.curlHTTP3 ];
networking = {
interfaces.eth1 = {
ipv4.addresses = [
{ address = "192.168.2.201"; prefixLength = 24; }
];
};
extraHosts = hosts;
};
security.pki.certificates = [
(builtins.readFile ./common/acme/server/ca.cert.pem)
];
};
};
testScript = ''
start_all()
server.wait_for_unit("nginx")
server.wait_for_open_port(443)
# Check http connections
client.succeed("curl --verbose --http3-only https://acme.test | grep 'Hello World!'")
# Check downloadings
client.succeed("curl --verbose --http3-only https://acme.test/example.txt --output /tmp/example.txt")
client.succeed("cat /tmp/example.txt | grep 'Check http3 protocol.'")
# Check header reading
client.succeed("curl --verbose --http3-only --head https://acme.test | grep 'content-type'")
client.succeed("curl --verbose --http3-only --head https://acme.test | grep 'HTTP/3 200'")
client.succeed("curl --verbose --http3-only --head https://acme.test/error | grep 'HTTP/3 404'")
# Check change User-Agent
client.succeed("curl --verbose --http3-only --user-agent 'Curl test 3.0' https://acme.test")
server.succeed("cat /var/log/nginx/access.log | grep 'Curl test 3.0'")
server.shutdown()
client.shutdown()
'';
})
}
)
[ pkgs.angieQuic pkgs.nginxQuic ]
)

View File

@ -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 ]
)

View File

@ -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 ];
};
}

View File

@ -0,0 +1,47 @@
{ 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;
angie-api = nixosTests.angie-api;
angie-http3 = nixosTests.nginx-http3.angieQuic;
};
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 ];
};
}

View File

@ -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
@ -68,6 +69,7 @@ stdenv.mkDerivation {
++ mapModules "inputs";
configureFlags = [
"--sbin-path=bin/nginx"
"--with-http_ssl_module"
"--with-http_v2_module"
"--with-http_realip_module"
@ -178,13 +180,13 @@ stdenv.mkDerivation {
if [[ -e man/nginx.8 ]]; then
installManPage man/nginx.8
fi
'';
'' + preInstall;
disallowedReferences = map (m: m.src) modules;
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 = {

View File

@ -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
'';

View File

@ -3252,6 +3252,27 @@ 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;
};
angie-console-light = callPackage ../servers/http/angie/console-light.nix { };
angle-grinder = callPackage ../tools/text/angle-grinder { };
ansifilter = callPackage ../tools/text/ansifilter { };