librespeed: test module
This commit is contained in:
parent
50be012843
commit
7b2b29aa9f
6 changed files with 322 additions and 0 deletions
|
@ -8,6 +8,7 @@
|
||||||
../../services/nginx.nix
|
../../services/nginx.nix
|
||||||
../../services/hydra
|
../../services/hydra
|
||||||
../../services/update-nixfiles.nix
|
../../services/update-nixfiles.nix
|
||||||
|
../../services/librespeed.nix
|
||||||
];
|
];
|
||||||
boot.binfmt.emulatedSystems = [ "aarch64-linux" ];
|
boot.binfmt.emulatedSystems = [ "aarch64-linux" ];
|
||||||
|
|
||||||
|
|
6
config/services/librespeed.nix
Normal file
6
config/services/librespeed.nix
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{ ... }: {
|
||||||
|
services.librespeed = {
|
||||||
|
enable = true;
|
||||||
|
domain = "speed.kyouma.net";
|
||||||
|
};
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
imports = [
|
imports = [
|
||||||
./deployment
|
./deployment
|
||||||
./graphical
|
./graphical
|
||||||
|
./librespeed
|
||||||
./machine-type
|
./machine-type
|
||||||
./nginx
|
./nginx
|
||||||
./ooklaserver
|
./ooklaserver
|
||||||
|
|
277
modules/librespeed/default.nix
Normal file
277
modules/librespeed/default.nix
Normal file
|
@ -0,0 +1,277 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
let
|
||||||
|
cfg = config.services.librespeed;
|
||||||
|
in {
|
||||||
|
options.services.librespeed = let
|
||||||
|
inherit (lib) mkOption types;
|
||||||
|
in {
|
||||||
|
enable = lib.mkEnableOption "LibreSpeed server";
|
||||||
|
package = lib.mkPackageOption pkgs "librespeed-rust" {};
|
||||||
|
configureNginx = mkOption {
|
||||||
|
description = "Configure nginx as a reverse proxy for LibreSpeed.";
|
||||||
|
default = if (cfg.domain != null) then true else false;
|
||||||
|
type = types.bool;
|
||||||
|
};
|
||||||
|
contactEmail = mkOption {
|
||||||
|
description = "Email address listed in the privacy policy.";
|
||||||
|
default = if (cfg.domain != null) then "webmaster@${cfg.domain}" else "webmaster@${config.networking.fqdn}";
|
||||||
|
type = types.str;
|
||||||
|
};
|
||||||
|
domain = mkOption {
|
||||||
|
description = ''
|
||||||
|
If not `null`, this will add an entry to `services.librespeed.servers` and
|
||||||
|
configure an nginx reverse proxy at the specified FQDN, unless explicitly disabled.
|
||||||
|
'';
|
||||||
|
default = null;
|
||||||
|
type = with types; nullOr nonEmptyStr;
|
||||||
|
};
|
||||||
|
openFirewall = mkOption {
|
||||||
|
description = ''
|
||||||
|
Whether to open the firewall for the specified port.
|
||||||
|
This is only necessary if no reverse proxy is used.
|
||||||
|
'';
|
||||||
|
default = false;
|
||||||
|
type = types.bool;
|
||||||
|
};
|
||||||
|
pageTitle = mkOption {
|
||||||
|
description = "Title of the webpage.";
|
||||||
|
default = "LibreSpeed";
|
||||||
|
type = types.str;
|
||||||
|
};
|
||||||
|
secrets = mkOption {
|
||||||
|
description = ''
|
||||||
|
Attribute set of filesystem paths.
|
||||||
|
The contents of the specified paths will be read at service start time and merged with the attributes provided in `settings`.
|
||||||
|
'';
|
||||||
|
default = {};
|
||||||
|
type = with types; nullOr (attrsOf path);
|
||||||
|
};
|
||||||
|
servers = mkOption {
|
||||||
|
description = "LibreSpeed servers that should apper in the server list.";
|
||||||
|
type = types.listOf (types.submodule {
|
||||||
|
options = let
|
||||||
|
inherit (types) nonEmptyStr;
|
||||||
|
in {
|
||||||
|
name = mkOption {
|
||||||
|
description = "Name shown in the server list.";
|
||||||
|
type = nonEmptyStr;
|
||||||
|
};
|
||||||
|
server = mkOption {
|
||||||
|
description = "URL to the server. You may use `//` instead of `http://` or `https://`.";
|
||||||
|
type = nonEmptyStr;
|
||||||
|
};
|
||||||
|
dlURL = mkOption {
|
||||||
|
description = ''
|
||||||
|
URL path to download test on this server.
|
||||||
|
Append `.php` to the default value if the server uses the php implementation.
|
||||||
|
'';
|
||||||
|
default = "backend/garbage";
|
||||||
|
type = nonEmptyStr;
|
||||||
|
};
|
||||||
|
ulURL = mkOption {
|
||||||
|
description = ''
|
||||||
|
URL path to upload test on this server.
|
||||||
|
Append `.php` to the default value if the server uses the php implementation.
|
||||||
|
'';
|
||||||
|
default = "backend/empty";
|
||||||
|
type = nonEmptyStr;
|
||||||
|
};
|
||||||
|
pingURL = mkOption {
|
||||||
|
description = ''
|
||||||
|
URL path to latency/jitter test on this server.
|
||||||
|
Append `.php` to the default value if the server uses the php implementation.
|
||||||
|
'';
|
||||||
|
default = "backend/empty";
|
||||||
|
type = nonEmptyStr;
|
||||||
|
};
|
||||||
|
getIpURL = mkOption {
|
||||||
|
description = ''
|
||||||
|
URL path to IP lookup on this server.
|
||||||
|
Append `.php` to the default value if the server uses the php implementation.
|
||||||
|
'';
|
||||||
|
default = "backend/getIP";
|
||||||
|
type = nonEmptyStr;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
settings = mkOption {
|
||||||
|
description = ''
|
||||||
|
LibreSpeed configuration written as Nix expression.
|
||||||
|
All values set to `null` will be excluded from the evaluated config.
|
||||||
|
This is useful if you want to omit certain defaults when using a different LibreSpeed implementation.
|
||||||
|
|
||||||
|
See [github.com/librespeed][librespeed] for configuration help.
|
||||||
|
|
||||||
|
[librespeed]: https://github.com/librespeed/speedtest-rust
|
||||||
|
'';
|
||||||
|
default = {};
|
||||||
|
type = with types; nullOr (attrsOf (oneOf [
|
||||||
|
bool
|
||||||
|
int
|
||||||
|
str
|
||||||
|
null
|
||||||
|
]));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
assertions = [
|
||||||
|
{
|
||||||
|
assertion = cfg.configureNginx -> cfg.domain != null;
|
||||||
|
message = ''
|
||||||
|
`services.librespeed.configureNginx` requires `services.librespeed.domain` to be set.
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
networking.firewall = lib.mkIf (cfg.openFirewall) {
|
||||||
|
allowedTCPPorts = [ cfg.settings.listen_port ];
|
||||||
|
};
|
||||||
|
services.nginx.virtualHosts = lib.mkIf cfg.configureNginx {
|
||||||
|
${cfg.domain} = {
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://${cfg.settings.bind_address}:${toString cfg.settings.listen_port}";
|
||||||
|
recommendedProxySettings = true;
|
||||||
|
};
|
||||||
|
enableACME = true;
|
||||||
|
forceSSL = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
security.acme.certs = lib.mkIf cfg.configureNginx {
|
||||||
|
${cfg.domain} = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.librespeed.servers = lib.mkIf (cfg.domain != null) [
|
||||||
|
{
|
||||||
|
name = cfg.domain;
|
||||||
|
server = "https://${cfg.domain}";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
services.librespeed.settings = let
|
||||||
|
inherit (lib) mkDefault mkIf;
|
||||||
|
|
||||||
|
assets = pkgs.runCommand "librespeed-assets" {
|
||||||
|
preferLocal = true;
|
||||||
|
|
||||||
|
serverList = ''
|
||||||
|
function get_servers() {
|
||||||
|
return ${builtins.toJSON cfg.servers}
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
} ''
|
||||||
|
cp -r ${pkgs.librespeed-rust}/assets $out
|
||||||
|
cat >$out/server_list.js <<<"$serverList"
|
||||||
|
substitute ${pkgs.librespeed-rust}/assets/index.html $out/index.html \
|
||||||
|
--replace-fail "LibreSpeed Example" ${lib.escapeShellArg (lib.escapeXML cfg.pageTitle)} \
|
||||||
|
--replace-fail "PUT@YOUR_EMAIL.HERE" ${lib.escapeShellArg (lib.escapeXML cfg.contactEmail)} \
|
||||||
|
--replace-fail "TO BE FILLED BY DEVELOPER" ${lib.escapeShellArg (lib.escapeXML cfg.contactEmail)}
|
||||||
|
'';
|
||||||
|
in {
|
||||||
|
speed_test_dir = assets;
|
||||||
|
bind_address = mkDefault (if cfg.configureNginx then "127.0.0.1" else "0.0.0.0");
|
||||||
|
listen_port = mkDefault 8989;
|
||||||
|
base_url = mkDefault "backend";
|
||||||
|
worker_threads = mkDefault "auto";
|
||||||
|
|
||||||
|
database_type = mkDefault "none";
|
||||||
|
database_file = mkIf (cfg.settings.database_type == "sqlite") mkDefault "/var/lib/librespeed/speedtest.sqlite";
|
||||||
|
|
||||||
|
#librespeed-rust will fail to start if the following config parameters are omitted.
|
||||||
|
ipinfo_api_key = mkIf (!cfg.secrets ? "ipinfo_api_key") "";
|
||||||
|
stats_password = mkIf (!cfg.secrets ? "stats_password") "";
|
||||||
|
tls_key_file = mkDefault "";
|
||||||
|
tls_cet_file = mkDefault "";
|
||||||
|
|
||||||
|
enable_tls = mkDefault false;
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services = let
|
||||||
|
configFile = let
|
||||||
|
anyToString = arg: if (lib.isBool arg) then
|
||||||
|
lib.boolToString arg
|
||||||
|
else if (lib.isInt arg) then
|
||||||
|
toString arg
|
||||||
|
else "\"${lib.escape [ "\"" ] (toString arg)}\"";
|
||||||
|
in
|
||||||
|
with lib; pipe cfg.settings [
|
||||||
|
(filterAttrs (_: val: val != null))
|
||||||
|
(mapAttrs (name: val: "${path}=${anyToString val}"))
|
||||||
|
(concatLines attrValues)
|
||||||
|
(pkgs.writeText "${cfg.package.name}-config.toml")
|
||||||
|
];
|
||||||
|
in {
|
||||||
|
librespeed-secrets = lib.mkIf (cfg.secrets != {}) {
|
||||||
|
description = "LibreSpeed secret helper";
|
||||||
|
|
||||||
|
ExecStart = let
|
||||||
|
script = pkgs.writeShellApplication {
|
||||||
|
name = "librespeed-secrets";
|
||||||
|
runtimeInputs = [ pkgs.coreutils ];
|
||||||
|
text = ''
|
||||||
|
cp ${configFile} ''${RUNTIME_DIRECTORY%%:*}/config.toml
|
||||||
|
'' + lib.pipe cfg.secrets [
|
||||||
|
(lib.mapAttrs (name: file: ''
|
||||||
|
cat >>''${RUNTIME_DIRECTORY%%:*}/config.toml <<EOF
|
||||||
|
${name}="$(<${lib.escapeShellArg file})"
|
||||||
|
EOF
|
||||||
|
''))
|
||||||
|
(lib.concatLines lib.attrValues)
|
||||||
|
];
|
||||||
|
};
|
||||||
|
in lib.getExe script;
|
||||||
|
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
RemainAfterExit = true;
|
||||||
|
RuntimeDirectory = "librespeed";
|
||||||
|
UMask = "u=rw";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
librespeed = {
|
||||||
|
description = "LibreSpeed server daemon";
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
wants = [ "network-online.target" ];
|
||||||
|
requires = lib.optionals (cfg.secrets != {}) [ "librespeed-secrets.service" ];
|
||||||
|
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "simple";
|
||||||
|
Restart = "always";
|
||||||
|
|
||||||
|
DynamicUser = true;
|
||||||
|
|
||||||
|
ExecStartPre = lib.mkIf (!cfg.secrets ? "ipinfo_api_key") "${lib.getExe cfg.package} --update-ipdb";
|
||||||
|
ExecStart = "${lib.getExe cfg.package} -c ${if (cfg.secrets == {}) then configFile else "\${RUNTIME_DIRECTORY%%:*}/config.toml"}";
|
||||||
|
WorkingDirectory = "/var/cache/librespeed";
|
||||||
|
RuntimeDirectory = "librespeed";
|
||||||
|
RuntimeDirectoryPreserve = true;
|
||||||
|
StateDirectory = "librespeed";
|
||||||
|
CacheDirectory = "librespeed";
|
||||||
|
SyslogIdentifier = "librespeed";
|
||||||
|
|
||||||
|
ReadOnlyPaths = [ cfg.package ];
|
||||||
|
RestrictSUIDSGID = true;
|
||||||
|
RestrictNamespaces = true;
|
||||||
|
PrivateTmp = true;
|
||||||
|
PrivateDevices = true;
|
||||||
|
PrivateUsers = true;
|
||||||
|
ProtectHostname = true;
|
||||||
|
ProtectClock = true;
|
||||||
|
ProtectKernelTunables = true;
|
||||||
|
ProtectKernelModules = true;
|
||||||
|
ProtectKernelLogs = true;
|
||||||
|
ProtectControlGroups = true;
|
||||||
|
ProtectSystem = "strict";
|
||||||
|
ProtectHome = true;
|
||||||
|
ProtectProc = "invisible";
|
||||||
|
SystemCallArchitectures = "native";
|
||||||
|
SystemCallFilter = "@system-service";
|
||||||
|
SystemCallErrorNumber = "EPERM";
|
||||||
|
LockPersonality = true;
|
||||||
|
NoNewPrivileges = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
meta.maintainers = with lib.maintainers; [ snaki ];
|
||||||
|
}
|
36
pkgs/librespeed-rust/default.nix
Normal file
36
pkgs/librespeed-rust/default.nix
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
fetchFromGitHub,
|
||||||
|
rustPlatform,
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
version = "1.3.2";
|
||||||
|
src = fetchFromGitHub {
|
||||||
|
owner = "librespeed";
|
||||||
|
repo = "speedtest-rust";
|
||||||
|
rev = "refs/tags/v${version}";
|
||||||
|
hash = "sha256-z3lORjjJ89o+Du4mvKGydwxHU6Ra2jU5ue5Zsl/oIfY=";
|
||||||
|
};
|
||||||
|
in
|
||||||
|
rustPlatform.buildRustPackage {
|
||||||
|
pname = "librespeed-rust";
|
||||||
|
inherit version src;
|
||||||
|
|
||||||
|
cargoLock.lockFile = "${src}/Cargo.lock";
|
||||||
|
|
||||||
|
# error: linker `aarch64-linux-gnu-gcc` not found
|
||||||
|
postPatch = ''
|
||||||
|
rm .cargo/config.toml
|
||||||
|
'';
|
||||||
|
|
||||||
|
postInstall = ''
|
||||||
|
cp -r assets $out/
|
||||||
|
'';
|
||||||
|
|
||||||
|
meta = {
|
||||||
|
description = "A very lightweight speed test implementation in Rust.";
|
||||||
|
homepage = "https://github.com/librespeed/speedtest-rust";
|
||||||
|
license = lib.licenses.lgpl3Plus;
|
||||||
|
maintainers = with lib.maintainers; [ snaki ];
|
||||||
|
};
|
||||||
|
}
|
|
@ -3,4 +3,5 @@ final: prev: {
|
||||||
upgrade-system = final.callPackage ./upgrade-system/default.nix {};
|
upgrade-system = final.callPackage ./upgrade-system/default.nix {};
|
||||||
update-nixfiles = final.callPackage ./update-nixfiles/default.nix {};
|
update-nixfiles = final.callPackage ./update-nixfiles/default.nix {};
|
||||||
build-worker-oci = final.callPackage ./build-worker-oci/default.nix {};
|
build-worker-oci = final.callPackage ./build-worker-oci/default.nix {};
|
||||||
|
librespeed-rust = final.callPackage ./librespeed-rust/default.nix {};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue