diff --git a/nixos/lib/test-driver/test_driver/machine.py b/nixos/lib/test-driver/test_driver/machine.py index 7ed001a1dfce..b1688cd3b64f 100644 --- a/nixos/lib/test-driver/test_driver/machine.py +++ b/nixos/lib/test-driver/test_driver/machine.py @@ -791,6 +791,28 @@ class Machine: with self.nested(f"waiting for TCP port {port} on {addr}"): retry(port_is_open, timeout) + def wait_for_open_unix_socket( + self, addr: str, is_datagram: bool = False, timeout: int = 900 + ) -> None: + """ + Wait until a process is listening on the given UNIX-domain socket + (default to a UNIX-domain stream socket). + """ + + nc_flags = [ + "-z", + "-uU" if is_datagram else "-U", + ] + + def socket_is_open(_: Any) -> bool: + status, _ = self.execute(f"nc {' '.join(nc_flags)} {addr}") + return status == 0 + + with self.nested( + f"waiting for UNIX-domain {'datagram' if is_datagram else 'stream'} on '{addr}'" + ): + retry(socket_is_open, timeout) + def wait_for_closed_port( self, port: int, addr: str = "localhost", timeout: int = 900 ) -> None: diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix index 955d6e19064e..9eebd18855c7 100644 --- a/nixos/modules/services/web-servers/nginx/default.nix +++ b/nixos/modules/services/web-servers/nginx/default.nix @@ -329,7 +329,7 @@ let listenString = { addr, port, ssl, proxyProtocol ? false, extraParameters ? [], ... }: # UDP listener for QUIC transport protocol. (optionalString (ssl && vhost.quic) (" - listen ${addr}:${toString port} quic " + listen ${addr}${optionalString (port != null) ":${toString port}"} quic " + optionalString vhost.default "default_server " + optionalString vhost.reuseport "reuseport " + optionalString (extraParameters != []) (concatStringsSep " " @@ -338,7 +338,7 @@ let in filter isCompatibleParameter extraParameters)) + ";")) + " - listen ${addr}:${toString port} " + listen ${addr}${optionalString (port != null) ":${toString port}"} " + optionalString (ssl && vhost.http2 && oldHTTP2) "http2 " + optionalString ssl "ssl " + optionalString vhost.default "default_server " diff --git a/nixos/modules/services/web-servers/nginx/vhost-options.nix b/nixos/modules/services/web-servers/nginx/vhost-options.nix index 7636c1b26115..c82f02ecefec 100644 --- a/nixos/modules/services/web-servers/nginx/vhost-options.nix +++ b/nixos/modules/services/web-servers/nginx/vhost-options.nix @@ -31,12 +31,12 @@ with lib; options = { addr = mkOption { type = str; - description = lib.mdDoc "IP address."; + description = lib.mdDoc "Listen address."; }; port = mkOption { - type = port; + type = types.nullOr port; description = lib.mdDoc "Port number."; - default = 80; + default = null; }; ssl = mkOption { type = bool; @@ -60,6 +60,7 @@ with lib; example = [ { addr = "195.154.1.1"; port = 443; ssl = true; } { addr = "192.154.1.1"; port = 80; } + { addr = "unix:/var/run/nginx.sock"; } ]; description = lib.mdDoc '' Listen addresses and ports for this virtual host. diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 33f8abf6ccd4..88fcbd59a1e7 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -559,6 +559,7 @@ in { nginx-sso = handleTest ./nginx-sso.nix {}; nginx-status-page = handleTest ./nginx-status-page.nix {}; nginx-tmpdir = handleTest ./nginx-tmpdir.nix {}; + nginx-unix-socket = handleTest ./nginx-unix-socket.nix {}; nginx-variants = handleTest ./nginx-variants.nix {}; nifi = handleTestOn ["x86_64-linux"] ./web-apps/nifi.nix {}; nitter = handleTest ./nitter.nix {}; diff --git a/nixos/tests/nginx-unix-socket.nix b/nixos/tests/nginx-unix-socket.nix new file mode 100644 index 000000000000..4640eaa171bd --- /dev/null +++ b/nixos/tests/nginx-unix-socket.nix @@ -0,0 +1,27 @@ +import ./make-test-python.nix ({ pkgs, ... }: +let + nginxSocketPath = "/var/run/nginx/test.sock"; +in +{ + name = "nginx-unix-socket"; + + nodes = { + webserver = { pkgs, lib, ... }: { + services.nginx = { + enable = true; + virtualHosts.localhost = { + serverName = "localhost"; + listen = [{ addr = "unix:${nginxSocketPath}"; }]; + locations."/test".return = "200 'foo'"; + }; + }; + }; + }; + + testScript = '' + webserver.wait_for_unit("nginx") + webserver.wait_for_open_unix_socket("${nginxSocketPath}") + + webserver.succeed("curl --fail --silent --unix-socket '${nginxSocketPath}' http://localhost/test | grep '^foo$'") + ''; +}) diff --git a/pkgs/servers/http/nginx/generic.nix b/pkgs/servers/http/nginx/generic.nix index 1f175c03d8a8..8f90adab101b 100644 --- a/pkgs/servers/http/nginx/generic.nix +++ b/pkgs/servers/http/nginx/generic.nix @@ -186,7 +186,7 @@ stdenv.mkDerivation { passthru = { inherit modules; tests = { - inherit (nixosTests) nginx nginx-auth nginx-etag nginx-globalredirect nginx-http3 nginx-proxyprotocol nginx-pubhtml nginx-sandbox nginx-sso nginx-status-page; + inherit (nixosTests) nginx nginx-auth nginx-etag nginx-globalredirect nginx-http3 nginx-proxyprotocol nginx-pubhtml nginx-sandbox nginx-sso nginx-status-page nginx-unix-socket; variants = lib.recurseIntoAttrs nixosTests.nginx-variants; acme-integration = nixosTests.acme; } // passthru.tests;