From e5c2c71280244eca8fd2dc87f2be0ca1db7f49dd Mon Sep 17 00:00:00 2001 From: Carl Dong Date: Fri, 7 Jul 2023 11:52:37 -0400 Subject: [PATCH] nixos/nginx: Allow empty port for listen directive When listening on unix sockets, it doesn't make sense to specify a port for nginx's listen directive. Since nginx defaults to port 80 when the port isn't specified (but the address is), we can change the default for the option to null as well without changing any behaviour. --- nixos/lib/test-driver/test_driver/machine.py | 22 +++++++++++++++ .../services/web-servers/nginx/default.nix | 4 +-- .../web-servers/nginx/vhost-options.nix | 7 ++--- nixos/tests/all-tests.nix | 1 + nixos/tests/nginx-unix-socket.nix | 27 +++++++++++++++++++ pkgs/servers/http/nginx/generic.nix | 2 +- 6 files changed, 57 insertions(+), 6 deletions(-) create mode 100644 nixos/tests/nginx-unix-socket.nix 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 3f19ed548121..bb44d68e275d 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -555,6 +555,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 3db19396bee9..b5e42c3dffb3 100644 --- a/pkgs/servers/http/nginx/generic.nix +++ b/pkgs/servers/http/nginx/generic.nix @@ -178,7 +178,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;