201 lines
7.6 KiB
Nix
201 lines
7.6 KiB
Nix
{
|
|
pkgs,
|
|
lib,
|
|
config,
|
|
...
|
|
}:
|
|
let
|
|
cfg = config.hyperhive.matrix;
|
|
hyperhiveDomain = config.hyperhive.domain;
|
|
effectiveServerName =
|
|
if cfg.serverName != null then cfg.serverName else "matrix.${hyperhiveDomain}";
|
|
in
|
|
{
|
|
# Private Matrix homeserver (matrix-tuwunel — the official conduwuit
|
|
# successor) for hyperhive agents, wrapped in a nixos-container so it
|
|
# doesn't fight any existing `services.matrix-*` the operator may
|
|
# already run on the host. Same shape as `nix/modules/hive-forge.nix`:
|
|
# shared host netns (`privateNetwork = false`) so agents reach it at
|
|
# `http://localhost:<httpPort>` (or via the configured server_name
|
|
# for federation), nixos-container only here for state + systemd-unit
|
|
# isolation.
|
|
#
|
|
# Container name `hive-matrix` (not `h-*`) so the lifecycle scanner
|
|
# ignores it; operator manages via the standard `nixos-container` CLI.
|
|
#
|
|
# Persistent state at `/var/lib/nixos-containers/hive-matrix/var/lib/
|
|
# matrix-tuwunel/` (survives container restart / host reboot). To
|
|
# wipe, destroy the container.
|
|
#
|
|
# Initial rollout (#548): federation enabled (needed for multi-hive
|
|
# swarms; trusted_servers starts empty so no actual federation traffic
|
|
# leaves until peers are explicitly listed), registration via admin
|
|
# API only, e2ee disabled per operator call (tracked for follow-up at
|
|
# #551).
|
|
|
|
options.hyperhive.matrix = {
|
|
enable = lib.mkOption {
|
|
type = lib.types.bool;
|
|
default = false;
|
|
description = ''
|
|
Run hive-matrix — a private matrix-tuwunel homeserver (in a
|
|
nixos-container) for hyperhive agents. Off by default while
|
|
the integration phases in; flip to `true` once the operator
|
|
has set `hyperhive.domain` and is ready to onboard agents.
|
|
'';
|
|
};
|
|
|
|
package = lib.mkOption {
|
|
type = lib.types.package;
|
|
default = pkgs.matrix-tuwunel;
|
|
defaultText = lib.literalExpression "pkgs.matrix-tuwunel";
|
|
description = ''
|
|
matrix-tuwunel package to run inside the container. Defaults
|
|
to nixpkgs's `pkgs.matrix-tuwunel`. Override to pin a
|
|
specific upstream if you need an unreleased feature.
|
|
'';
|
|
};
|
|
|
|
serverName = lib.mkOption {
|
|
type = lib.types.nullOr lib.types.str;
|
|
default = null;
|
|
example = "chat.example.org";
|
|
description = ''
|
|
Matrix `server_name` — the host part of every user ID
|
|
(`@argus:<server_name>`) and room ID minted on this
|
|
homeserver. CRITICAL: must be stable from day one because
|
|
it's embedded irrevocably in the identifiers. Defaults to
|
|
`matrix.''${hyperhive.domain}` (always a subdomain — keeps
|
|
the root domain free for the dashboard or forge). Override
|
|
here only if you need a name that doesn't follow the
|
|
`matrix.<domain>` shape.
|
|
'';
|
|
};
|
|
|
|
httpPort = lib.mkOption {
|
|
type = lib.types.port;
|
|
default = 8008;
|
|
description = ''
|
|
TCP port tuwunel serves the matrix client-server API on.
|
|
Default 8008 is the matrix-spec well-known port. Sits
|
|
outside hyperhive's claimed ranges (dashboard 7000, manager
|
|
8000, sub-agents 8100..8999). Federation listens on
|
|
`federationPort` separately.
|
|
'';
|
|
};
|
|
|
|
openFirewall = lib.mkOption {
|
|
type = lib.types.bool;
|
|
default = true;
|
|
description = ''
|
|
Open `httpPort` in the host firewall. Off when the
|
|
homeserver should only be reachable from inside the host
|
|
(e.g. while bringing the integration up before announcing
|
|
it to other hives).
|
|
|
|
Note: federation (the matrix-spec well-known port 8448) is
|
|
intentionally not opened here. tuwunel serves the federation
|
|
API on the same `httpPort` as the client-server API by
|
|
default; reaching it on 8448 requires either binding tuwunel
|
|
to that port explicitly OR a reverse-proxy + `.well-known/
|
|
matrix/server` delegation, neither of which lives in this
|
|
module. Add that proxy config alongside whatever serves your
|
|
dashboard or forge on 443.
|
|
'';
|
|
};
|
|
|
|
trustedServers = lib.mkOption {
|
|
type = lib.types.listOf lib.types.str;
|
|
default = [ ];
|
|
example = [ "matrix.org" ];
|
|
description = ''
|
|
List of trusted matrix servers (homeservers whose signing
|
|
keys this server will fetch identity-server-style). Empty
|
|
by default — federation is enabled at the protocol level
|
|
but no peer is trusted until listed here, so the homeserver
|
|
is effectively closed until the operator declares hive
|
|
peers explicitly.
|
|
'';
|
|
};
|
|
|
|
maxRequestSize = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "20000000";
|
|
description = ''
|
|
Maximum size in bytes of a single matrix client request body.
|
|
Default 20 MB matches the matrix-spec recommendation for
|
|
media uploads. String-typed to match tuwunel's TOML config
|
|
shape (it accepts both integer + size-with-suffix strings).
|
|
'';
|
|
};
|
|
};
|
|
|
|
config = lib.mkIf cfg.enable {
|
|
# mara on #548: "there is no default, but it is required. add
|
|
# assertion." — fail eval with a helpful message rather than
|
|
# spawning a homeserver with a bogus server_name we can never
|
|
# change later. `hyperhive.domain` is host-wide; matrix derives
|
|
# the server_name from it (or from `cfg.serverName` if the
|
|
# operator wants to override).
|
|
assertions = [
|
|
{
|
|
assertion = hyperhiveDomain != null || cfg.serverName != null;
|
|
message = ''
|
|
hyperhive.matrix.enable = true requires either:
|
|
- hyperhive.domain set to your host's canonical domain
|
|
(recommended; shared with forge / dashboard), or
|
|
- hyperhive.matrix.serverName set explicitly.
|
|
|
|
The matrix server_name is embedded into every user ID and
|
|
room ID on this homeserver — it cannot be changed later
|
|
without losing every account and chat history. Pick a
|
|
stable hostname before enabling.
|
|
'';
|
|
}
|
|
];
|
|
|
|
containers.hive-matrix = {
|
|
autoStart = true;
|
|
ephemeral = false;
|
|
# Share host netns — tuwunel's listeners look exactly like
|
|
# host-side services, no port-forward plumbing, and agent
|
|
# containers (also host netns) reach it via plain `localhost`.
|
|
privateNetwork = false;
|
|
config =
|
|
{ ... }:
|
|
{
|
|
system.stateVersion = "26.05";
|
|
services.matrix-tuwunel = {
|
|
enable = true;
|
|
package = cfg.package;
|
|
settings.global = {
|
|
server_name = effectiveServerName;
|
|
address = "0.0.0.0";
|
|
port = cfg.httpPort;
|
|
max_request_size = cfg.maxRequestSize;
|
|
# Federation enabled at the protocol level so swarms
|
|
# can be wired up later by extending `trustedServers`
|
|
# without a homeserver restart. Empty trusted_servers
|
|
# keeps it effectively closed until peers are listed.
|
|
allow_federation = true;
|
|
trusted_servers = cfg.trustedServers;
|
|
# Registration off — operator seeds agent accounts via
|
|
# the tuwunel admin API (mirrors the forge pattern;
|
|
# see `hive-c0re/src/matrix.rs` once #548 PR 2 lands).
|
|
allow_registration = false;
|
|
# E2EE disabled in initial rollout per operator call
|
|
# (#548) — re-enabling tracked at #551.
|
|
allow_encryption = false;
|
|
};
|
|
};
|
|
environment.systemPackages = [ cfg.package ];
|
|
};
|
|
};
|
|
|
|
networking.firewall = lib.mkIf cfg.openFirewall {
|
|
allowedTCPPorts = [
|
|
cfg.httpPort
|
|
];
|
|
};
|
|
};
|
|
}
|