summaryrefslogtreecommitdiffstats
path: root/nixos/modules/services/networking/nghttpx
diff options
context:
space:
mode:
authorParnell Springmeyer <ixmatus@users.noreply.github.com>2017-11-16 12:21:02 -0600
committerJörg Thalheim <Mic92@users.noreply.github.com>2017-11-16 18:21:02 +0000
commitcb11bf73a511819ee36c4bddb97573aacda0b161 (patch)
treef4256571834c529fb6fa204f3163a7b965302574 /nixos/modules/services/networking/nghttpx
parent8bd10a17c6c811b423126af1d3dc37aa82a7c131 (diff)
nixos/nghttpx: add module for the nghttpx proxy server (#31680)
* nghttpx: Add a new NixOS module for the nghttpx proxy server This change also adds a global `uid` and `gid` for a `nghttpx` user and group as well as an integration test. * nixos/nghttpx: fix building manual
Diffstat (limited to 'nixos/modules/services/networking/nghttpx')
-rw-r--r--nixos/modules/services/networking/nghttpx/backend-params-submodule.nix131
-rw-r--r--nixos/modules/services/networking/nghttpx/backend-submodule.nix50
-rw-r--r--nixos/modules/services/networking/nghttpx/default.nix117
-rw-r--r--nixos/modules/services/networking/nghttpx/frontend-params-submodule.nix64
-rw-r--r--nixos/modules/services/networking/nghttpx/frontend-submodule.nix36
-rw-r--r--nixos/modules/services/networking/nghttpx/nghttpx-options.nix142
-rw-r--r--nixos/modules/services/networking/nghttpx/server-options.nix18
-rw-r--r--nixos/modules/services/networking/nghttpx/tls-submodule.nix21
8 files changed, 579 insertions, 0 deletions
diff --git a/nixos/modules/services/networking/nghttpx/backend-params-submodule.nix b/nixos/modules/services/networking/nghttpx/backend-params-submodule.nix
new file mode 100644
index 000000000000..6523f4b8b9e0
--- /dev/null
+++ b/nixos/modules/services/networking/nghttpx/backend-params-submodule.nix
@@ -0,0 +1,131 @@
+{ lib, ...}:
+{ options = {
+ proto = lib.mkOption {
+ type = lib.types.enum [ "h2" "http/1.1" ];
+ default = "http/1.1";
+ description = ''
+ This option configures the protocol the backend server expects
+ to use.
+
+ Please see https://nghttp2.org/documentation/nghttpx.1.html#cmdoption-nghttpx-b
+ for more detail.
+ '';
+ };
+
+ tls = lib.mkOption {
+ type = lib.types.bool;
+ default = false;
+ description = ''
+ This option determines whether nghttpx will negotiate its
+ connection with a backend server using TLS or not. The burden
+ is on the backend server to provide the TLS certificate!
+
+ Please see https://nghttp2.org/documentation/nghttpx.1.html#cmdoption-nghttpx-b
+ for more detail.
+ '';
+ };
+
+ sni = lib.mkOption {
+ type = lib.types.nullOr lib.types.str;
+ default = null;
+ description = ''
+ Override the TLS SNI field value. This value (in nghttpx)
+ defaults to the host value of the backend configuration.
+
+ Please see https://nghttp2.org/documentation/nghttpx.1.html#cmdoption-nghttpx-b
+ for more detail.
+ '';
+ };
+
+ fall = lib.mkOption {
+ type = lib.types.int;
+ default = 0;
+ description = ''
+ If nghttpx cannot connect to the backend N times in a row, the
+ backend is assumed to be offline and is excluded from load
+ balancing. If N is 0 the backend is never excluded from load
+ balancing.
+
+ Please see https://nghttp2.org/documentation/nghttpx.1.html#cmdoption-nghttpx-b
+ for more detail.
+ '';
+ };
+
+ rise = lib.mkOption {
+ type = lib.types.int;
+ default = 0;
+ description = ''
+ If the backend is excluded from load balancing, nghttpx will
+ periodically attempt to make a connection to the backend. If
+ the connection is successful N times in a row the backend is
+ re-included in load balancing. If N is 0 a backend is never
+ reconsidered for load balancing once it falls.
+
+ Please see https://nghttp2.org/documentation/nghttpx.1.html#cmdoption-nghttpx-b
+ for more detail.
+ '';
+ };
+
+ affinity = lib.mkOption {
+ type = lib.types.enum [ "ip" "none" ];
+ default = "none";
+ description = ''
+ If "ip" is given, client IP based session affinity is
+ enabled. If "none" is given, session affinity is disabled.
+
+ Session affinity is enabled (by nghttpx) per-backend
+ pattern. If at least one backend has a non-"none" affinity,
+ then session affinity is enabled for all backend servers
+ sharing the same pattern.
+
+ It is advised to set affinity on all backends explicitly if
+ session affinity is desired. The session affinity may break if
+ one of the backend gets unreachable, or backend settings are
+ reloaded or replaced by API.
+
+ Please see https://nghttp2.org/documentation/nghttpx.1.html#cmdoption-nghttpx-b
+ for more detail.
+ '';
+ };
+
+ dns = lib.mkOption {
+ type = lib.types.bool;
+ default = false;
+ description = ''
+ Name resolution of a backends host name is done at start up,
+ or configuration reload. If "dns" is true, name resolution
+ takes place dynamically.
+
+ This is useful if a backends address changes frequently. If
+ "dns" is true, name resolution of a backend's host name at
+ start up, or configuration reload is skipped.
+
+ Please see https://nghttp2.org/documentation/nghttpx.1.html#cmdoption-nghttpx-b
+ for more detail.
+ '';
+ };
+
+ redirect-if-not-tls = lib.mkOption {
+ type = lib.types.bool;
+ default = false;
+ description = ''
+ If true, a backend match requires the frontend connection be
+ TLS encrypted. If it is not, nghttpx responds to the request
+ with a 308 status code and https URI the client should use
+ instead in the Location header.
+
+ The port number in the redirect URI is 443 by default and can
+ be changed using 'services.nghttpx.redirect-https-port'
+ option.
+
+ If at least one backend has "redirect-if-not-tls" set to true,
+ this feature is enabled for all backend servers with the same
+ pattern. It is advised to set "redirect-if-no-tls" parameter
+ to all backends explicitly if this feature is desired.
+
+ Please see https://nghttp2.org/documentation/nghttpx.1.html#cmdoption-nghttpx-b
+ for more detail.
+ '';
+ };
+ };
+}
diff --git a/nixos/modules/services/networking/nghttpx/backend-submodule.nix b/nixos/modules/services/networking/nghttpx/backend-submodule.nix
new file mode 100644
index 000000000000..eb559e926e76
--- /dev/null
+++ b/nixos/modules/services/networking/nghttpx/backend-submodule.nix
@@ -0,0 +1,50 @@
+{ lib, ... }:
+{ options = {
+ server = lib.mkOption {
+ type =
+ lib.types.either
+ (lib.types.submodule (import ./server-options.nix))
+ (lib.types.path);
+ example = {
+ host = "127.0.0.1";
+ port = 8888;
+ };
+ default = {
+ host = "127.0.0.1";
+ port = 80;
+ };
+ description = ''
+ Backend server location specified as either a host:port pair
+ or a unix domain docket.
+ '';
+ };
+
+ patterns = lib.mkOption {
+ type = lib.types.listOf lib.types.str;
+ example = [
+ "*.host.net/v1/"
+ "host.org/v2/mypath"
+ "/somepath"
+ ];
+ default = [];
+ description = ''
+ List of nghttpx backend patterns.
+
+ Please see https://nghttp2.org/documentation/nghttpx.1.html#cmdoption-nghttpx-b
+ for more information on the pattern syntax and nghttpxs behavior.
+ '';
+ };
+
+ params = lib.mkOption {
+ type = lib.types.nullOr (lib.types.submodule (import ./backend-params-submodule.nix));
+ example = {
+ proto = "h2";
+ tls = true;
+ };
+ default = null;
+ description = ''
+ Parameters to configure a backend.
+ '';
+ };
+ };
+}
diff --git a/nixos/modules/services/networking/nghttpx/default.nix b/nixos/modules/services/networking/nghttpx/default.nix
new file mode 100644
index 000000000000..d6e1906e3881
--- /dev/null
+++ b/nixos/modules/services/networking/nghttpx/default.nix
@@ -0,0 +1,117 @@
+{config, pkgs, lib, ...}:
+let
+ cfg = config.services.nghttpx;
+
+ # renderHost :: Either ServerOptions Path -> String
+ renderHost = server:
+ if builtins.isString server
+ then "unix://${server}"
+ else "${server.host},${builtins.toString server.port}";
+
+ # Filter out submodule parameters whose value is null or false or is
+ # the key _module.
+ #
+ # filterParams :: ParamsSubmodule -> ParamsSubmodule
+ filterParams = p:
+ lib.filterAttrs
+ (n: v: ("_module" != n) && (null != v) && (false != v))
+ (lib.optionalAttrs (null != p) p);
+
+ # renderBackend :: BackendSubmodule -> String
+ renderBackend = backend:
+ let
+ host = renderHost backend.server;
+ patterns = lib.concatStringsSep ":" backend.patterns;
+
+ # Render a set of backend parameters, this is somewhat
+ # complicated because nghttpx backend patterns can be entirely
+ # omitted and the params may be given as a mixed collection of
+ # 'key=val' pairs or atoms (e.g: 'proto=h2;tls')
+ params =
+ lib.mapAttrsToList
+ (n: v:
+ if builtins.isBool v
+ then n
+ else if builtins.isString v
+ then "${n}=${v}"
+ else "${n}=${builtins.toString v}")
+ (filterParams backend.params);
+
+ # NB: params are delimited by a ";" which is the same delimiter
+ # to separate the host;[pattern];[params] sections of a backend
+ sections =
+ builtins.filter (e: "" != e) ([
+ host
+ patterns
+ ]++params);
+ formattedSections = lib.concatStringsSep ";" sections;
+ in
+ "backend=${formattedSections}";
+
+ # renderFrontend :: FrontendSubmodule -> String
+ renderFrontend = frontend:
+ let
+ host = renderHost frontend.server;
+ params0 =
+ lib.mapAttrsToList
+ (n: v: if builtins.isBool v then n else v)
+ (filterParams frontend.params);
+
+ # NB: nghttpx doesn't accept "tls", you must omit "no-tls" for
+ # the default behavior of turning on TLS.
+ params1 = lib.remove "tls" params0;
+
+ sections = [ host] ++ params1;
+ formattedSections = lib.concatStringsSep ";" sections;
+ in
+ "frontend=${formattedSections}";
+
+ configurationFile = pkgs.writeText "nghttpx.conf" ''
+ ${lib.optionalString (null != cfg.tls) ("private-key-file="+cfg.tls.key)}
+ ${lib.optionalString (null != cfg.tls) ("certificate-file="+cfg.tls.crt)}
+
+ user=nghttpx
+
+ ${lib.concatMapStringsSep "\n" renderFrontend cfg.frontends}
+ ${lib.concatMapStringsSep "\n" renderBackend cfg.backends}
+
+ backlog=${builtins.toString cfg.backlog}
+ backend-address-family=${cfg.backend-address-family}
+
+ workers=${builtins.toString cfg.workers}
+ rlimit-nofile=${builtins.toString cfg.rlimit-nofile}
+
+ ${lib.optionalString cfg.single-thread "single-thread=yes"}
+ ${lib.optionalString cfg.single-process "single-process=yes"}
+
+ ${cfg.extraConfig}
+ '';
+in
+{ imports = [
+ ./nghttpx-options.nix
+ ];
+
+ config = lib.mkIf cfg.enable {
+
+ users.groups.nghttpx = { };
+ users.users.nghttpx = {
+ group = config.users.groups.nghttpx.name;
+ };
+
+
+ systemd.services = {
+ nghttpx = {
+ wantedBy = [ "multi-user.target" ];
+ after = [ "network.target" ];
+ script = ''
+ ${pkgs.nghttp2}/bin/nghttpx --conf=${configurationFile}
+ '';
+
+ serviceConfig = {
+ Restart = "on-failure";
+ RestartSec = 60;
+ };
+ };
+ };
+ };
+}
diff --git a/nixos/modules/services/networking/nghttpx/frontend-params-submodule.nix b/nixos/modules/services/networking/nghttpx/frontend-params-submodule.nix
new file mode 100644
index 000000000000..33c8572bd14f
--- /dev/null
+++ b/nixos/modules/services/networking/nghttpx/frontend-params-submodule.nix
@@ -0,0 +1,64 @@
+{ lib, ...}:
+{ options = {
+ tls = lib.mkOption {
+ type = lib.types.enum [ "tls" "no-tls" ];
+ default = "tls";
+ description = ''
+ Enable or disable TLS. If true (enabled) the key and
+ certificate must be configured for nghttpx.
+
+ Please see https://nghttp2.org/documentation/nghttpx.1.html#cmdoption-nghttpx-f
+ for more detail.
+ '';
+ };
+
+ sni-fwd = lib.mkOption {
+ type = lib.types.bool;
+ default = false;
+ description = ''
+ When performing a match to select a backend server, SNI host
+ name received from the client is used instead of the request
+ host. See --backend option about the pattern match.
+
+ Please see https://nghttp2.org/documentation/nghttpx.1.html#cmdoption-nghttpx-f
+ for more detail.
+ '';
+ };
+
+ api = lib.mkOption {
+ type = lib.types.bool;
+ default = false;
+ description = ''
+ Enable API access for this frontend. This enables you to
+ dynamically modify nghttpx at run-time therefore this feature
+ is disabled by default and should be turned on with care.
+
+ Please see https://nghttp2.org/documentation/nghttpx.1.html#cmdoption-nghttpx-f
+ for more detail.
+ '';
+ };
+
+ healthmon = lib.mkOption {
+ type = lib.types.bool;
+ default = false;
+ description = ''
+ Make this frontend a health monitor endpoint. Any request
+ received on this frontend is responded to with a 200 OK.
+
+ Please see https://nghttp2.org/documentation/nghttpx.1.html#cmdoption-nghttpx-f
+ for more detail.
+ '';
+ };
+
+ proxyproto = lib.mkOption {
+ type = lib.types.bool;
+ default = false;
+ description = ''
+ Accept PROXY protocol version 1 on frontend connection.
+
+ Please see https://nghttp2.org/documentation/nghttpx.1.html#cmdoption-nghttpx-f
+ for more detail.
+ '';
+ };
+ };
+}
diff --git a/nixos/modules/services/networking/nghttpx/frontend-submodule.nix b/nixos/modules/services/networking/nghttpx/frontend-submodule.nix
new file mode 100644
index 000000000000..887ef4502131
--- /dev/null
+++ b/nixos/modules/services/networking/nghttpx/frontend-submodule.nix
@@ -0,0 +1,36 @@
+{ lib, ... }:
+{ options = {
+ server = lib.mkOption {
+ type =
+ lib.types.either
+ (lib.types.submodule (import ./server-options.nix))
+ (lib.types.path);
+ example = {
+ host = "127.0.0.1";
+ port = 8888;
+ };
+ default = {
+ host = "127.0.0.1";
+ port = 80;
+ };
+ description = ''
+ Frontend server interface binding specification as either a
+ host:port pair or a unix domain docket.
+
+ NB: a host of "*" listens on all interfaces and includes IPv6
+ addresses.
+ '';
+ };
+
+ params = lib.mkOption {
+ type = lib.types.nullOr (lib.types.submodule (import ./frontend-params-submodule.nix));
+ example = {
+ tls = "tls";
+ };
+ default = null;
+ description = ''
+ Parameters to configure a backend.
+ '';
+ };
+ };
+}
diff --git a/nixos/modules/services/networking/nghttpx/nghttpx-options.nix b/nixos/modules/services/networking/nghttpx/nghttpx-options.nix
new file mode 100644
index 000000000000..cce65be321a8
--- /dev/null
+++ b/nixos/modules/services/networking/nghttpx/nghttpx-options.nix
@@ -0,0 +1,142 @@
+{ config, lib, ... }:
+{ options.services.nghttpx = {
+ enable = lib.mkEnableOption "nghttpx";
+
+ frontends = lib.mkOption {
+ type = lib.types.listOf (lib.types.submodule (import ./frontend-submodule.nix));
+ description = ''
+ A list of frontend listener specifications.
+ '';
+ example = [
+ { server = {
+ host = "*";
+ port = 80;
+ };
+
+ params = {
+ tls = "no-tls";
+ };
+ }
+ ];
+ };
+
+ backends = lib.mkOption {
+ type = lib.types.listOf (lib.types.submodule (import ./backend-submodule.nix));
+ description = ''
+ A list of backend specifications.
+ '';
+ example = [
+ { server = {
+ host = "172.16.0.22";
+ port = 8443;
+ };
+ patterns = [ "/" ];
+ params = {
+ proto = "http/1.1";
+ redirect-if-not-tls = true;
+ };
+ }
+ ];
+ };
+
+ tls = lib.mkOption {
+ type = lib.types.nullOr (lib.types.submodule (import ./tls-submodule.nix));
+ default = null;
+ description = ''
+ TLS certificate and key paths. Note that this does not enable
+ TLS for a frontend listener, to do so, a frontend
+ specification must set <literal>params.tls</literal> to true.
+ '';
+ example = {
+ key = "/etc/ssl/keys/server.key";
+ crt = "/etc/ssl/certs/server.crt";
+ };
+ };
+
+ extraConfig = lib.mkOption {
+ type = lib.types.lines;
+ default = "";
+ description = ''
+ Extra configuration options to be appended to the generated
+ configuration file.
+ '';
+ };
+
+ single-process = lib.mkOption {
+ type = lib.types.bool;
+ default = false;
+ description = ''
+ Run this program in a single process mode for debugging
+ purpose. Without this option, nghttpx creates at least 2
+ processes: master and worker processes. If this option is
+ used, master and worker are unified into a single
+ process. nghttpx still spawns additional process if neverbleed
+ is used. In the single process mode, the signal handling
+ feature is disabled.
+
+ Please see https://nghttp2.org/documentation/nghttpx.1.html#cmdoption-nghttpx--single-process
+ '';
+ };
+
+ backlog = lib.mkOption {
+ type = lib.types.int;
+ default = 65536;
+ description = ''
+ Listen backlog size.
+
+ Please see https://nghttp2.org/documentation/nghttpx.1.html#cmdoption-nghttpx--backlog
+ '';
+ };
+
+ backend-address-family = lib.mkOption {
+ type = lib.types.enum [
+ "auto"
+ "IPv4"
+ "IPv6"
+ ];
+ default = "auto";
+ description = ''
+ Specify address family of backend connections. If "auto" is
+ given, both IPv4 and IPv6 are considered. If "IPv4" is given,
+ only IPv4 address is considered. If "IPv6" is given, only IPv6
+ address is considered.
+
+ Please see https://nghttp2.org/documentation/nghttpx.1.html#cmdoption-nghttpx--backend-address-family
+ '';
+ };
+
+ workers = lib.mkOption {
+ type = lib.types.int;
+ default = 1;
+ description = ''
+ Set the number of worker threads.
+
+ Please see https://nghttp2.org/documentation/nghttpx.1.html#cmdoption-nghttpx-n
+ '';
+ };
+
+ single-thread = lib.mkOption {
+ type = lib.types.bool;
+ default = false;
+ description = ''
+ Run everything in one thread inside the worker process. This
+ feature is provided for better debugging experience, or for
+ the platforms which lack thread support. If threading is
+ disabled, this option is always enabled.
+
+ Please see https://nghttp2.org/documentation/nghttpx.1.html#cmdoption-nghttpx--single-thread
+ '';
+ };
+
+ rlimit-nofile = lib.mkOption {
+ type = lib.types.int;
+ default = 0;
+ description = ''
+ Set maximum number of open files (RLIMIT_NOFILE) to &lt;N&gt;. If 0
+ is given, nghttpx does not set the limit.
+
+ Please see https://nghttp2.org/documentation/nghttpx.1.html#cmdoption-nghttpx--rlimit-nofile
+ '';
+ };
+ };
+}
diff --git a/nixos/modules/services/networking/nghttpx/server-options.nix b/nixos/modules/services/networking/nghttpx/server-options.nix
new file mode 100644
index 000000000000..ef23bfd793c5
--- /dev/null
+++ b/nixos/modules/services/networking/nghttpx/server-options.nix
@@ -0,0 +1,18 @@
+{ lib, ... }:
+{ options = {
+ host = lib.mkOption {
+ type = lib.types.str;
+ example = "127.0.0.1";
+ description = ''
+ Server host address.
+ '';
+ };
+ port = lib.mkOption {
+ type = lib.types.int;
+ example = 5088;
+ description = ''
+ Server host port.
+ '';
+ };
+ };
+}
diff --git a/nixos/modules/services/networking/nghttpx/tls-submodule.nix b/nixos/modules/services/networking/nghttpx/tls-submodule.nix
new file mode 100644
index 000000000000..8f3cdaae2c81
--- /dev/null
+++ b/nixos/modules/services/networking/nghttpx/tls-submodule.nix
@@ -0,0 +1,21 @@
+{lib, ...}:
+{ options = {
+ key = lib.mkOption {
+ type = lib.types.str;
+ example = "/etc/ssl/keys/mykeyfile.key";
+ default = "/etc/ssl/keys/server.key";
+ description = ''
+ Path to the TLS key file.
+ '';
+ };
+
+ crt = lib.mkOption {
+ type = lib.types.str;
+ example = "/etc/ssl/certs/mycert.crt";
+ default = "/etc/ssl/certs/server.crt";
+ description = ''
+ Path to the TLS certificate file.
+ '';
+ };
+ };
+}