diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index aa4e2ccc46bce..ce79afd0ffe0d 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -807,6 +807,7 @@
./services/networking/smokeping.nix
./services/networking/softether.nix
./services/networking/solanum.nix
+ ./services/networking/sozu.nix
./services/networking/spacecookie.nix
./services/networking/spiped.nix
./services/networking/squid.nix
diff --git a/nixos/modules/services/networking/sozu.nix b/nixos/modules/services/networking/sozu.nix
new file mode 100644
index 0000000000000..0524a97d66afb
--- /dev/null
+++ b/nixos/modules/services/networking/sozu.nix
@@ -0,0 +1,547 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+ cfg = config.services.sozu;
+ format = pkgs.formats.toml {};
+
+ settings = format.generate "settings.toml" (
+ foldl' lib.mergeAttrs {} [
+ (if cfg.settings.saved_state == "" then {} else (getAttrs [ "saved_state" ] cfg.settings))
+ (if cfg.settings.log_access_target == "" then {} else (getAttrs [ "log_access_target" ] cfg.settings))
+ (if cfg.settings.listeners == [] then {} else (getAttrs [ "listeners" ] cfg.settings))
+ (if cfg.settings.applications == {} then {} else (getAttrs [ "applications" ] cfg.settings))
+ (if cfg.settings.metrics == {} then {} else (getAttrs [ "metrics" ] cfg.settings))
+ ]
+ );
+
+in
+{
+ options.services.sozu = {
+ enable = mkEnableOption "Sozu server";
+
+ package = mkOption {
+ type = types.package;
+ default = pkgs.sozu;
+ description = "Sozu package to use.";
+ };
+
+ configFile = mkOption {
+ type = types.either types.str types.path;
+ default = pkgs.writeText "config.toml" ''
+ automatic_save_state = ${if (cfg.automatic_save_state == true) then "true" else "false"}
+
+ log_level = "${cfg.log_level}"
+
+ log_target = "${cfg.log_target}"
+
+ command_socket = "${cfg.command_socket}"
+
+ command_buffer_size = ${toString cfg.command_buffer_size}
+
+ max_command_buffer_size = ${toString cfg.max_command_buffer_size}
+
+ worker_count = ${toString cfg.worker_count}
+
+ worker_automatic_restart = ${if (cfg.worker_automatic_restart == true) then "true" else "false"}
+
+ handle_process_affinity = ${if (cfg.handle_process_affinity == true) then "true" else "false"}
+
+ max_connections = ${toString cfg.max_connections}
+
+ max_buffers = ${toString cfg.max_buffers}
+
+ buffer_size = ${toString cfg.buffer_size}
+
+ ctl_command_timeout = ${toString cfg.ctl_command_timeout}
+
+ pid_file_path = "${cfg.pid_file_path}"
+
+ tls_provider = "${cfg.tls_provider}"
+
+ front_timeout = ${toString cfg.front_timeout}
+
+ zombie_check_interval = ${toString cfg.zombie_check_interval}
+
+ activate_listeners = ${if (cfg.activate_listeners == true) then "true" else "false"}
+
+ ${fileContents settings}
+ '';
+ description = ''
+ Override the configuration file used by Sozu.
+ By default, NixOS generates on automatically.
+ '';
+ };
+
+ automatic_save_state = mkOption {
+ type = types.bool;
+ default = false;
+ example = true;
+ description = ''
+ Save the configuration to the saved_state file every time we
+ receive a configuration message on the configuration socket.
+ Defaults to false, and will not work if the 'saved_state' option is
+ not set.
+ '';
+ };
+
+ log_level = mkOption {
+ type = types.str;
+ default = "info";
+ description = ''
+ Logging verbosity. Possible values are "error", "warn", "info",
+ "debug" and "trace". For performance reasons, the logs at "debug"
+ or "trace" level are not compiled by default. To activate them,
+ pass the "logs-debug" and "logs-trace" compilation options to cargo.
+ '';
+ };
+
+ log_target = mkOption {
+ type = types.str;
+ default = "stdout";
+ description = ''
+ Where the logs will be sent. It defaults to sending the logs on
+ standard output.
+ UDP address: "udp://127.0.0.1:9876"
+ To a TCP address: "tcp://127.0.0.1:9876"
+ To a unix socket: "unix:///var/sozu/logs
+ To a file: "file:///var/logs/sozu.log"
+ To stdout: "stdout"
+ '';
+ };
+
+ command_socket = mkOption {
+ type = types.either types.str types.path;
+ default = "/run/sozu/sozu.sock";
+ description = ''
+ Path to the unix socket file used to send commands to sozu.
+ Default value points to "sozu.sock" file in the current directory.
+ '';
+ };
+
+ command_buffer_size = mkOption {
+ type = types.int;
+ default = 1000000;
+ example = 16384;
+ description = ''
+ Size in bytes of the buffer used by the command socket protocol.
+ If the message sent to sozu is too large, or the data that sozu
+ must return is too large, the buffer will grow up to
+ max_command_buffer_size. If the buffer is still not large enough
+ sozu, will close the connection.
+ '';
+ };
+
+ max_command_buffer_size = mkOption {
+ type = types.int;
+ default = cfg.command_buffer_size * 2;
+ example = 163840;
+ description = ''
+ Maximum size in bytes of the buffer
+ used by the command socket protocol.
+ '';
+ };
+
+ worker_count = mkOption {
+ type = types.int;
+ default = 2;
+ description = ''
+ The number of worker processes that will handle traffic.
+ '';
+ };
+
+ worker_automatic_restart = mkOption {
+ type = types.bool;
+ default = true;
+ example = false;
+ description = ''
+ Indicates if workers should be automatically restarted if they
+ crash / hang.
+ Should be true for production and false for development.
+ '';
+ };
+
+ handle_process_affinity = mkOption {
+ type = types.bool;
+ default = false;
+ example = true;
+ description = ''
+ Indicates if worker process will be pinned on a core. If you
+ activate this, be sure that you do not have more workers than CPU
+ cores (and leave at least one core for the kernel and the master
+ process).
+ '';
+ };
+
+ max_connections = mkOption {
+ type = types.int;
+ # current max file descriptor soft limit is: 1024
+ # the worker needs two file descriptors per client connection
+ default = 1024 / 2;
+ example = 500;
+ description = ''
+ Maximum number of connections to a worker. If it reaches that
+ number and there are new connections available, the worker will
+ accept and close them immediately to indicate it is too busy to
+ handle traffic.
+ '';
+ };
+
+ max_buffers = mkOption {
+ type = types.int;
+ default = 1000;
+ example = 500;
+ description = ''
+ Maximum number of buffers used by the protocol implementations
+ for active connections (ie currently serving a request).
+ For now, you should estimate that
+ max_buffers = number of concurrent requests * 2.
+ '';
+ };
+
+ buffer_size = mkOption {
+ type = types.int;
+ default = 16384;
+ description = ''
+ Size of the buffers used by the protocol implementations. Each worker will
+ preallocate max_buffers * 2 * buffer_size bytes, so you should plan for this
+ memory usage. If you plan to use sozu's runtime upgrade feature, you should
+ leave enough memory for one more worker (also for the kernel, etc), so total
+ RAM should be larger than (worker count + 1) * max_buffers * 2 * buffer_size bytes.
+ '';
+ };
+
+ ctl_command_timeout = mkOption {
+ type = types.int;
+ default = 1000;
+ description = ''
+ How much time (in milliseconds) sozuctl will wait for a command
+ to complete.
+ '';
+ };
+
+ pid_file_path = mkOption {
+ type = types.either types.str types.path;
+ default = "/run/sozu/sozu.pid";
+ description = ''
+ PID file is a file containing the PID of the master process of sozu.
+ It can be helpful to help systemd or any other service system to keep track
+ of the main process across upgrades. PID file is not created unless this option
+ is set or if SOZU_PID_FILE_PATH environment variable was defined at build time.
+ '';
+ };
+
+ tls_provider = mkOption {
+ type = types.enum [ "openssl" "rustls" ];
+ default = "rustls";
+ description = ''
+ Defines how the TLS protocol will be handled by sozu. Possible values
+ are "openssl" or "rustls". The "openssl" option will only work if sozu
+ was built with the "use-openssl" feature.
+ '';
+ };
+
+ front_timeout = mkOption {
+ type = types.int;
+ default = 60;
+ description = ''
+ Maximum time of inactivity for a front socket, in seconds.
+ '';
+ };
+
+ zombie_check_interval = mkOption {
+ type = types.int;
+ default = 1800;
+ description = ''
+ Duration between zombie checks, in seconds.
+ In case of bugs in sozu's event loop and protocol implementations,
+ some client sessions could be stuck, not receiving any more event,
+ and consuming resources. Sozu verifies regularly if there are such
+ zombie sessions, logs their state and removes them.
+ '';
+ };
+
+ activate_listeners = mkOption {
+ type = types.bool;
+ default = true;
+ example = false;
+ description = ''
+ By default, all listeners start a TCP listen socket on startup.
+ If set to false, this option will prevent them from listening. You can then add
+ the complete configuration, and send an ActivateListener message afterwards.
+ '';
+ };
+
+ settings = mkOption {
+ description = ''
+ Settings that will be parsed into Sozu's config.toml.
+ Documentation here.
+ Also see example.
+ '';
+ default = {};
+ type = types.submodule
+ {
+ freeformType = format.type;
+
+ options = {
+
+ saved_state = mkOption {
+ type = types.either types.str types.path;
+ default = "";
+ example = "/run/sozu/state.json";
+ description = ''
+ Path to a file sozu can use to load an initial configuration state
+ for its routing. You can generate this file from sozu's current
+ routing by running the command sozuctl state save -f state.json.
+ '';
+ };
+
+ log_access_target = mkOption {
+ type = types.str;
+ default = "";
+ example = "file:///var/logs/sozu-access.log";
+ description = ''
+ Optional different target for access logs (IP addresses, domains,
+ URI, HTTP status, etc).
+ UDP address: "udp://127.0.0.1:9876"
+ To a TCP address: "tcp://127.0.0.1:9876"
+ To a unix socket: "unix:///var/sozu/access_logs
+ To a file: "file:///var/logs/sozu-access.log"
+ '';
+ };
+
+ listeners = mkOption {
+ default = [];
+
+ description = "Configuration options specific to a TCP listen socket.";
+
+ example = [
+ # Example for an HTTP (plaintext) listener
+ {
+ # Possible values are http, https or tcp
+ protocol = "http";
+ # Listening address
+ address = "127.0.0.1:8080";
+
+ # Specify a different IP than the one the socket sees, for logs and
+ # forwarded headers
+ public_address = "1.2.3.4:80";
+
+ # Configures the client socket to receive a PROXY protocol header
+ #expect_proxy = false;
+
+ # Path to custom 404 and 503 answers
+ # A 404 response is sent when sozu does not know about the requested domain or path
+ # A 503 response is sent if there are no backend servers available
+ answer_404 = "../lib/assets/404.html";
+ answer_503 = "../lib/assets/503.html";
+
+ # Defines the sticky session cookie's name, if `sticky_session` is
+ # activated format an application. Defaults to "SOZUBALANCEID"
+ sticky_name = "SOZUBALANCEID";
+ }
+
+ # Example for an HTTPS (OpenSSL or rustls based) listener
+ {
+ # Possible values are http, https or tcp
+ protocol = "https";
+ # Listening address
+ address = "127.0.0.1:8443";
+
+ # Specify a different IP than the one the socket sees, for logs and
+ # forwarded headers
+ #public_address = "1.2.3.4:81";
+
+ # Configures the client socket to receive a PROXY protocol header
+ # This option is incompatible with public_addresss
+ #expect_proxy = false;
+
+ # Path to custom 404 and 503 answers
+ # A 404 response is sent when sozu does not know about the
+ # requested domain or path
+ # A 503 response is sent if there are no backend servers available
+ answer_404 = "../lib/assets/404.html";
+ answer_503 = "../lib/assets/503.html";
+
+ # Defines the sticky session cookie's name, if `sticky_session` is
+ # activated format an application. Defaults to "SOZUBALANCEID"
+ sticky_name = "SOZUBALANCEID";
+
+ # Supported TLS versions. Possible values are "SSLv2", "SSLv3",
+ # "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3". Defaults to "TLSv1.2"
+ tls_versions = [ "TLSv1.2" ];
+
+ # Option specific to Openssl based HTTPS listeners
+ #cipher_list = "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256";
+
+ # Option specific to rustls based HTTPS listeners
+ rustls_cipher_list = [ "TLS13_CHACHA20_POLY1305_SHA256" ];
+ }
+ ];
+
+ type = types.listOf types.attrs;
+
+ };
+
+ applications = mkOption {
+ default = {};
+
+ description = "These applications will be routed by sozu directly from the start";
+
+ example = {
+ # Every application has an "application ID", here it is "MyApp".
+ # This is an example of a routing configuration for the HTTP and HTPPS proxies
+ MyApp = {
+ # The protocol option indicates if we will use HTTP or TCP proxying
+ # Possible values are thus "http" and "tcp"
+ # HTTPS proxies will use http here
+ protocol = "http";
+
+ # Per application load balancing algorithm
+ # The possible values are "roundrobin" and "random"
+ # Defaults to "roundrobin"
+ load_balancing_policy = "roundrobin";
+
+ # Force application to redirect http traffic to https
+ #https_redirect = true
+
+ # Frontends configuration:
+ # This specifies the listeners, domains, and certificates that will be configured for an application.
+ # Possible frontend options:
+ # - address: TCP listener.
+ # - hostname: Hostname of the application.
+ # - path_begin = "/api" # Optional. An application can receive requests going to a hostname and path prefix.
+ # - sticky_session = false # Activates sticky sessions for this application.
+ # - https_redirect = false # Activates automatic redirection to HTTPS for this application.
+ frontends = [
+ {
+ address = "0.0.0.0:8080";
+ hostname = "lolcatho.st";
+ }
+
+ {
+ address = "0.0.0.0:8443";
+ hostname = "lolcatho.st";
+ certificate = "../lib/assets/certificate.pem";
+ key = "../lib/assets/key.pem";
+ certificate_chain = "../lib/assets/certificate_chain.pem";
+ }
+ ];
+
+ # Backend configuration:
+ # This indicates the backend servers used by the application.
+ # Possible options:
+ # - addresss: IP and port of the backend server.
+ # - weight: Weight used by the load balancing algorithm.
+ # - sticky-id: Sticky session identifier.
+ backends = [
+ {
+ address = "127.0.0.1:1026";
+ }
+ ];
+ };
+
+ TcpTest = {
+ protocol = "tcp";
+
+ frontends = [
+ {
+ address = "0.0.0.0:8081";
+ }
+ ];
+
+ # Activates the proxy protocol to send IP information to the backend
+ send_proxy = false;
+
+ backends = [
+ {
+ address = "127.0.0.1:4000";
+ weight = 100;
+ }
+ {
+ address = "127.0.0.1:4001";
+ weight = 50;
+ }
+ ];
+ };
+ };
+
+ type = types.submodule {
+ freeformType = format.type;
+ };
+
+ };
+
+ metrics = mkOption {
+ default = {};
+
+ description = ''
+ Various statistics can be sent to a server that supports the statsd protocol.
+ You can see those statistics with sozuctl, like this:
+ sozuctl metrics
+ or sozuctl metrics --json for machine consumption
+ '';
+
+ example = {
+ address = "127.0.0.1:8125";
+ # use InfluxDB's statsd protocol flavor to add tags
+ tagged_metrics = false;
+ # metrics key prefix
+ prefix = "sozu";
+ };
+
+ type = types.submodule {
+ freeformType = format.type;
+ };
+
+ };
+ };
+ };
+ };
+
+ };
+
+ config = mkIf
+ cfg.enable
+ {
+ environment.etc."sozu/config.toml".source = cfg.configFile;
+
+ environment.systemPackages = with pkgs; [
+ cfg.package
+ ];
+
+ users.groups.sozu = {};
+ users.users.sozu = {
+ description = "Sozu Daemon User";
+ group = "sozu";
+ isSystemUser = true;
+ };
+
+ systemd.services.sozu = {
+ description = "Sozu - A HTTP reverse proxy, configurable at runtime, fast and safe, built in Rust.";
+ after = [ "network.target" ];
+ wants = [ "network.target" ];
+ wantedBy = [ "multi-user.target" ];
+ restartTriggers = [ cfg.configFile ];
+
+ serviceConfig = {
+ PIDFile = cfg.pid_file_path;
+ ExecStart = "${cfg.package}/bin/sozu start --config /etc/sozu/config.toml";
+ ExecReload = "${cfg.package}/bin/sozuctl --config /etc/sozu/config.toml reload";
+ Restart = "on-failure";
+ User = "sozu";
+ Group = "sozu";
+ RuntimeDirectory = "sozu";
+ AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ];
+ };
+
+ };
+
+ };
+
+ meta = with lib; {
+ maintainers = with maintainer; [ netcrns ];
+ };
+
+}
diff --git a/pkgs/servers/sozu/default.nix b/pkgs/servers/sozu/default.nix
index 07f85c889c212..2521439eb6ca9 100644
--- a/pkgs/servers/sozu/default.nix
+++ b/pkgs/servers/sozu/default.nix
@@ -1,26 +1,24 @@
-{ lib, stdenv, rustPlatform, fetchFromGitHub, darwin }:
+{ lib, stdenv, rustPlatform, fetchFromGitHub, Security }:
rustPlatform.buildRustPackage rec {
pname = "sozu";
- version = "0.11.56";
+ version = "0.12.0";
src = fetchFromGitHub {
owner = "sozu-proxy";
repo = pname;
rev = version;
- sha256 = "sha256-/XyBzhZCsX9sGk+iTFlDnblWfDCZdI4b9yfo4Z+Wp1U=";
+ sha256 = "sha256-oZ078U+Ly5CKk+XjjJ9TDAiYN+2CHng2kWgRThNo2XE=";
};
- cargoSha256 = "sha256-xnps3/i6BpzdwUAQmb8aoOPc39L2P52y/ZDAeLoEIU8=";
+ cargoSha256 = "sha256-6UYD0VNvmver5/gkYUCyjbX4ZcxgbMFcqZ/WjypnylM=";
- buildInputs =
- lib.optional stdenv.isDarwin darwin.apple_sdk.frameworks.Security;
+ buildInputs = lib.optionals stdenv.isDarwin [ Security ];
meta = with lib; {
- description =
- "Open Source HTTP Reverse Proxy built in Rust for Immutable Infrastructures";
+ description = "Open Source HTTP Reverse Proxy built in Rust for Immutable Infrastructures";
homepage = "https://www.sozu.io";
- license = licenses.agpl3;
- maintainers = with maintainers; [ Br1ght0ne ];
+ license = licenses.agpl3Only;
+ maintainers = with maintainers; [ Br1ght0ne netcrns ];
};
}
diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix
index 9f5c2551fae41..a765e07dffe6b 100644
--- a/pkgs/top-level/all-packages.nix
+++ b/pkgs/top-level/all-packages.nix
@@ -8652,7 +8652,9 @@ in
soundkonverter = libsForQt5.soundkonverter;
- sozu = callPackage ../servers/sozu { };
+ sozu = callPackage ../servers/sozu {
+ inherit (darwin.apple_sdk.frameworks) Security;
+ };
sparsehash = callPackage ../development/libraries/sparsehash { };