nixos/fedimintd: init services
This commit is contained in:
parent
78389c563c
commit
ba727987d4
@ -163,6 +163,8 @@
|
||||
|
||||
- [Veilid](https://veilid.com), a headless server that enables privacy-focused data sharing and messaging on a peer-to-peer network. Available as [services.veilid](#opt-services.veilid.enable).
|
||||
|
||||
- [Fedimint](https://github.com/fedimint/fedimint), a module based system for building federated applications (Federated E-Cash Mint). Available as [services.fedimintd](#opt-services.fedimintd).
|
||||
|
||||
## Backward Incompatibilities {#sec-release-24.11-incompatibilities}
|
||||
|
||||
- The `sound` options have been removed or renamed, as they had a lot of unintended side effects. See [below](#sec-release-24.11-migration-sound) for details.
|
||||
|
@ -1031,6 +1031,7 @@
|
||||
./services/networking/expressvpn.nix
|
||||
./services/networking/fakeroute.nix
|
||||
./services/networking/fastnetmon-advanced.nix
|
||||
./services/networking/fedimintd.nix
|
||||
./services/networking/ferm.nix
|
||||
./services/networking/firefox-syncserver.nix
|
||||
./services/networking/fireqos.nix
|
||||
|
304
nixos/modules/services/networking/fedimintd.nix
Normal file
304
nixos/modules/services/networking/fedimintd.nix
Normal file
@ -0,0 +1,304 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib)
|
||||
concatLists
|
||||
filterAttrs
|
||||
mapAttrs'
|
||||
mapAttrsToList
|
||||
mkEnableOption
|
||||
mkIf
|
||||
mkOption
|
||||
mkOverride
|
||||
mkPackageOption
|
||||
nameValuePair
|
||||
recursiveUpdate
|
||||
types
|
||||
;
|
||||
|
||||
fedimintdOpts =
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
name,
|
||||
...
|
||||
}:
|
||||
{
|
||||
options = {
|
||||
enable = mkEnableOption "fedimintd";
|
||||
|
||||
package = mkPackageOption pkgs "fedimint" { };
|
||||
|
||||
environment = mkOption {
|
||||
type = types.attrsOf types.str;
|
||||
description = "Extra Environment variables to pass to the fedimintd.";
|
||||
default = {
|
||||
RUST_BACKTRACE = "1";
|
||||
};
|
||||
example = {
|
||||
RUST_LOG = "info,fm=debug";
|
||||
RUST_BACKTRACE = "1";
|
||||
};
|
||||
};
|
||||
|
||||
p2p = {
|
||||
openFirewall = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Opens port in firewall for fedimintd's p2p port";
|
||||
};
|
||||
port = mkOption {
|
||||
type = types.port;
|
||||
default = 8173;
|
||||
description = "Port to bind on for p2p connections from peers";
|
||||
};
|
||||
bind = mkOption {
|
||||
type = types.str;
|
||||
default = "0.0.0.0";
|
||||
description = "Address to bind on for p2p connections from peers";
|
||||
};
|
||||
url = mkOption {
|
||||
type = types.str;
|
||||
example = "fedimint://p2p.myfedimint.com";
|
||||
description = ''
|
||||
Public address for p2p connections from peers
|
||||
'';
|
||||
};
|
||||
};
|
||||
api = {
|
||||
openFirewall = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Opens port in firewall for fedimintd's api port";
|
||||
};
|
||||
port = mkOption {
|
||||
type = types.port;
|
||||
default = 8174;
|
||||
description = "Port to bind on for API connections relied by the reverse proxy/tls terminator.";
|
||||
};
|
||||
bind = mkOption {
|
||||
type = types.str;
|
||||
default = "127.0.0.1";
|
||||
description = "Address to bind on for API connections relied by the reverse proxy/tls terminator.";
|
||||
};
|
||||
url = mkOption {
|
||||
type = types.str;
|
||||
description = ''
|
||||
Public URL of the API address of the reverse proxy/tls terminator. Usually starting with `wss://`.
|
||||
'';
|
||||
};
|
||||
};
|
||||
bitcoin = {
|
||||
network = mkOption {
|
||||
type = types.str;
|
||||
default = "signet";
|
||||
example = "bitcoin";
|
||||
description = "Bitcoin network to participate in.";
|
||||
};
|
||||
rpc = {
|
||||
url = mkOption {
|
||||
type = types.str;
|
||||
default = "http://127.0.0.1:38332";
|
||||
example = "signet";
|
||||
description = "Bitcoin node (bitcoind/electrum/esplora) address to connect to";
|
||||
};
|
||||
|
||||
kind = mkOption {
|
||||
type = types.str;
|
||||
default = "bitcoind";
|
||||
example = "electrum";
|
||||
description = "Kind of a bitcoin node.";
|
||||
};
|
||||
|
||||
secretFile = mkOption {
|
||||
type = types.nullOr types.path;
|
||||
default = null;
|
||||
description = ''
|
||||
If set the URL specified in `bitcoin.rpc.url` will get the content of this file added
|
||||
as an URL password, so `http://user@example.com` will turn into `http://user:SOMESECRET@example.com`.
|
||||
|
||||
Example:
|
||||
|
||||
`/etc/nix-bitcoin-secrets/bitcoin-rpcpassword-public` (for nix-bitcoin default)
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
consensus.finalityDelay = mkOption {
|
||||
type = types.ints.unsigned;
|
||||
default = 10;
|
||||
description = "Consensus peg-in finality delay.";
|
||||
};
|
||||
|
||||
dataDir = mkOption {
|
||||
type = types.path;
|
||||
default = "/var/lib/fedimintd-${name}/";
|
||||
readOnly = true;
|
||||
description = ''
|
||||
Path to the data dir fedimintd will use to store its data.
|
||||
Note that due to using the DynamicUser feature of systemd, this value should not be changed
|
||||
and is set to be read only.
|
||||
'';
|
||||
};
|
||||
|
||||
nginx = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to configure nginx for fedimintd
|
||||
'';
|
||||
};
|
||||
fqdn = mkOption {
|
||||
type = types.str;
|
||||
example = "api.myfedimint.com";
|
||||
description = "Public domain of the API address of the reverse proxy/tls terminator.";
|
||||
};
|
||||
config = mkOption {
|
||||
type = types.submodule (
|
||||
recursiveUpdate (import ../web-servers/nginx/vhost-options.nix {
|
||||
inherit config lib;
|
||||
}) { }
|
||||
);
|
||||
default = { };
|
||||
description = "Overrides to the nginx vhost section for api";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
options = {
|
||||
services.fedimintd = mkOption {
|
||||
type = types.attrsOf (types.submodule fedimintdOpts);
|
||||
default = { };
|
||||
description = "Specification of one or more fedimintd instances.";
|
||||
};
|
||||
};
|
||||
|
||||
config =
|
||||
let
|
||||
eachFedimintd = filterAttrs (fedimintdName: cfg: cfg.enable) config.services.fedimintd;
|
||||
eachFedimintdNginx = filterAttrs (fedimintdName: cfg: cfg.nginx.enable) eachFedimintd;
|
||||
in
|
||||
mkIf (eachFedimintd != { }) {
|
||||
|
||||
networking.firewall.allowedTCPPorts = concatLists (
|
||||
mapAttrsToList (
|
||||
fedimintdName: cfg:
|
||||
(lib.optional cfg.api.openFirewall cfg.api.port ++ lib.optional cfg.p2p.openFirewall cfg.p2p.port)
|
||||
) eachFedimintd
|
||||
);
|
||||
|
||||
systemd.services = mapAttrs' (
|
||||
fedimintdName: cfg:
|
||||
(nameValuePair "fedimintd-${fedimintdName}" (
|
||||
let
|
||||
startScript = pkgs.writeShellScript "fedimintd-start" (
|
||||
(
|
||||
if cfg.bitcoin.rpc.secretFile != null then
|
||||
''
|
||||
secret=$(${pkgs.coreutils}/bin/head -n 1 "${cfg.bitcoin.rpc.secretFile}")
|
||||
prefix="''${FM_BITCOIN_RPC_URL%*@*}" # Everything before the last '@'
|
||||
suffix="''${FM_BITCOIN_RPC_URL##*@}" # Everything after the last '@'
|
||||
FM_BITCOIN_RPC_URL="''${prefix}:''${secret}@''${suffix}"
|
||||
''
|
||||
else
|
||||
""
|
||||
)
|
||||
+ ''
|
||||
exec ${cfg.package}/bin/fedimintd
|
||||
''
|
||||
);
|
||||
in
|
||||
{
|
||||
description = "Fedimint Server";
|
||||
documentation = [ "https://github.com/fedimint/fedimint/" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
environment = lib.mkMerge [
|
||||
{
|
||||
FM_BIND_P2P = "${cfg.p2p.bind}:${toString cfg.p2p.port}";
|
||||
FM_BIND_API = "${cfg.api.bind}:${toString cfg.api.port}";
|
||||
FM_P2P_URL = cfg.p2p.url;
|
||||
FM_API_URL = cfg.api.url;
|
||||
FM_DATA_DIR = cfg.dataDir;
|
||||
FM_BITCOIN_NETWORK = cfg.bitcoin.network;
|
||||
FM_BITCOIN_RPC_URL = cfg.bitcoin.rpc.url;
|
||||
FM_BITCOIN_RPC_KIND = cfg.bitcoin.rpc.kind;
|
||||
}
|
||||
cfg.environment
|
||||
];
|
||||
serviceConfig = {
|
||||
DynamicUser = true;
|
||||
|
||||
StateDirectory = "fedimintd-${fedimintdName}";
|
||||
StateDirectoryMode = "0700";
|
||||
ExecStart = startScript;
|
||||
|
||||
Restart = "always";
|
||||
RestartSec = 10;
|
||||
StartLimitBurst = 5;
|
||||
UMask = "007";
|
||||
LimitNOFILE = "100000";
|
||||
|
||||
LockPersonality = true;
|
||||
MemoryDenyWriteExecute = true;
|
||||
NoNewPrivileges = true;
|
||||
PrivateDevices = true;
|
||||
PrivateMounts = true;
|
||||
PrivateTmp = true;
|
||||
ProtectClock = true;
|
||||
ProtectControlGroups = true;
|
||||
ProtectHostname = true;
|
||||
ProtectKernelLogs = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectKernelTunables = true;
|
||||
ProtectSystem = "full";
|
||||
RestrictAddressFamilies = [
|
||||
"AF_INET"
|
||||
"AF_INET6"
|
||||
];
|
||||
RestrictNamespaces = true;
|
||||
RestrictRealtime = true;
|
||||
SystemCallArchitectures = "native";
|
||||
SystemCallFilter = [
|
||||
"@system-service"
|
||||
"~@privileged"
|
||||
];
|
||||
};
|
||||
}
|
||||
))
|
||||
) eachFedimintd;
|
||||
|
||||
services.nginx.virtualHosts = mapAttrs' (
|
||||
fedimintdName: cfg:
|
||||
(nameValuePair cfg.nginx.fqdn (
|
||||
lib.mkMerge [
|
||||
cfg.nginx.config
|
||||
|
||||
{
|
||||
# Note: we want by default to enable OpenSSL, but it seems anything 100 and above is
|
||||
# overriden by default value from vhost-options.nix
|
||||
enableACME = mkOverride 99 true;
|
||||
forceSSL = mkOverride 99 true;
|
||||
# Currently Fedimint API only support JsonRPC on `/ws/` endpoint, so no need to handle `/`
|
||||
locations."/ws/" = {
|
||||
proxyPass = "http://127.0.0.1:${toString cfg.api.port}/";
|
||||
proxyWebsockets = true;
|
||||
extraConfig = ''
|
||||
proxy_pass_header Authorization;
|
||||
'';
|
||||
};
|
||||
}
|
||||
]
|
||||
))
|
||||
) eachFedimintdNginx;
|
||||
};
|
||||
|
||||
meta.maintainers = with lib.maintainers; [ dpc ];
|
||||
}
|
@ -322,6 +322,7 @@ in {
|
||||
fancontrol = handleTest ./fancontrol.nix {};
|
||||
fanout = handleTest ./fanout.nix {};
|
||||
fcitx5 = handleTest ./fcitx5 {};
|
||||
fedimintd = runTest ./fedimintd.nix;
|
||||
fenics = handleTest ./fenics.nix {};
|
||||
ferm = handleTest ./ferm.nix {};
|
||||
ferretdb = handleTest ./ferretdb.nix {};
|
||||
|
37
nixos/tests/fedimintd.nix
Normal file
37
nixos/tests/fedimintd.nix
Normal file
@ -0,0 +1,37 @@
|
||||
# This test runs the fedimintd and verifies that it starts
|
||||
|
||||
{ pkgs, ... }:
|
||||
|
||||
{
|
||||
name = "fedimintd";
|
||||
|
||||
meta = with pkgs.lib.maintainers; {
|
||||
maintainers = [ dpc ];
|
||||
};
|
||||
|
||||
nodes.machine =
|
||||
{ ... }:
|
||||
{
|
||||
services.fedimintd."mainnet" = {
|
||||
enable = true;
|
||||
p2p = {
|
||||
url = "fedimint://example.com";
|
||||
};
|
||||
api = {
|
||||
url = "wss://example.com";
|
||||
};
|
||||
environment = {
|
||||
"FM_REL_NOTES_ACK" = "0_4_xyz";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
testScript =
|
||||
{ nodes, ... }:
|
||||
''
|
||||
start_all()
|
||||
|
||||
machine.wait_for_unit("fedimintd-mainnet.service")
|
||||
machine.wait_for_open_port(${toString nodes.machine.services.fedimintd.mainnet.api.port})
|
||||
'';
|
||||
}
|
Loading…
Reference in New Issue
Block a user