forgejo's F3 init resolves data-dir before checking ENABLED, so `forgejo admin user create` still fataled on the RO nix-store default. set [F3] PATH = /var/lib/forgejo/data/f3 alongside the disable.
139 lines
4.7 KiB
Nix
139 lines
4.7 KiB
Nix
{
|
|
pkgs,
|
|
lib,
|
|
config,
|
|
...
|
|
}:
|
|
let
|
|
cfg = config.services.hive-forge;
|
|
in
|
|
{
|
|
# Private Forgejo for hyperhive agents, wrapped in a nixos-container
|
|
# so it doesn't fight any `services.forgejo` the operator already
|
|
# runs on the host. The container shares the host network namespace
|
|
# (`privateNetwork = false`) so agents reach the forge at
|
|
# `http://localhost:<httpPort>` without any extra plumbing —
|
|
# nixos-container is just here for state + systemd-unit isolation,
|
|
# not network isolation.
|
|
#
|
|
# Container name is `hive-forge` (not `h-*`), so hive-c0re's
|
|
# lifecycle scanner ignores it; the operator manages it via the
|
|
# standard `nixos-container` CLI.
|
|
#
|
|
# State lives at `/var/lib/nixos-containers/hive-forge/var/lib/forgejo/`
|
|
# and survives container restart / host reboot. To wipe, destroy the
|
|
# container.
|
|
|
|
options.services.hive-forge = {
|
|
enable = lib.mkEnableOption "hive-forge — private Forgejo (in a nixos-container) for hyperhive agents";
|
|
|
|
httpPort = lib.mkOption {
|
|
type = lib.types.port;
|
|
default = 3000;
|
|
description = ''
|
|
TCP port the forge serves HTTP on. Default 3000 sits outside
|
|
hyperhive's claimed ranges (dashboard 7000, manager 8000,
|
|
sub-agents 8100..8999). Change this if you already have
|
|
another forgejo bound to 3000.
|
|
'';
|
|
};
|
|
|
|
sshPort = lib.mkOption {
|
|
type = lib.types.port;
|
|
default = 2222;
|
|
description = ''
|
|
TCP port the forge's built-in SSH server listens on. Kept off
|
|
22 so it doesn't clash with the host's openssh. Agents push
|
|
with `ssh -p <sshPort> git@<domain>:<owner>/<repo>.git`.
|
|
'';
|
|
};
|
|
|
|
domain = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "localhost";
|
|
example = "forge.internal";
|
|
description = ''
|
|
Hostname used in repo clone URLs the forge advertises. The
|
|
container shares host netns so `localhost` works for any
|
|
agent on the same host; set a real hostname when you want
|
|
clones from outside the host to look canonical.
|
|
'';
|
|
};
|
|
|
|
openFirewall = lib.mkOption {
|
|
type = lib.types.bool;
|
|
default = true;
|
|
description = ''
|
|
Open `httpPort` + `sshPort` in the host firewall. Off when
|
|
the forge should only be reachable from inside the host.
|
|
(The container shares host netns, so this is the only
|
|
firewall layer that matters.)
|
|
'';
|
|
};
|
|
};
|
|
|
|
config = lib.mkIf cfg.enable {
|
|
containers.hive-forge = {
|
|
autoStart = true;
|
|
ephemeral = false;
|
|
# Share host netns — forgejo's HTTP / SSH listeners then look
|
|
# exactly like a host-side service, no port forwarding dance,
|
|
# and agent containers (which also share host netns) reach it
|
|
# via plain `localhost`.
|
|
privateNetwork = false;
|
|
config =
|
|
{ pkgs, ... }:
|
|
{
|
|
system.stateVersion = "25.11";
|
|
services.forgejo = {
|
|
enable = true;
|
|
database.type = "sqlite3";
|
|
lfs.enable = true;
|
|
settings = {
|
|
server = {
|
|
DOMAIN = cfg.domain;
|
|
ROOT_URL = "http://${cfg.domain}:${toString cfg.httpPort}/";
|
|
HTTP_PORT = cfg.httpPort;
|
|
START_SSH_SERVER = true;
|
|
SSH_PORT = cfg.sshPort;
|
|
SSH_LISTEN_PORT = cfg.sshPort;
|
|
BUILTIN_SSH_SERVER_USER = "git";
|
|
DISABLE_SSH = false;
|
|
};
|
|
# Registration off — operator seeds agent users via
|
|
# `nixos-container run hive-forge -- forgejo admin
|
|
# user create …`.
|
|
service = {
|
|
DISABLE_REGISTRATION = true;
|
|
REQUIRE_SIGNIN_VIEW = false;
|
|
};
|
|
repository = {
|
|
DEFAULT_BRANCH = "main";
|
|
DEFAULT_PRIVATE = "private";
|
|
};
|
|
log.LEVEL = "Warn";
|
|
# F3 (federation) computes its data dir relative to the
|
|
# forgejo binary, which lands in the read-only nix
|
|
# store and crashes anything that touches the F3
|
|
# subsystem — including `forgejo admin user create`,
|
|
# which init-ses F3 even when ENABLED=false. Pin the
|
|
# path absolute alongside the disable so the init
|
|
# resolution succeeds before the flag is checked.
|
|
"F3" = {
|
|
ENABLED = false;
|
|
PATH = "/var/lib/forgejo/data/f3";
|
|
};
|
|
};
|
|
};
|
|
environment.systemPackages = [ pkgs.forgejo ];
|
|
};
|
|
};
|
|
|
|
networking.firewall = lib.mkIf cfg.openFirewall {
|
|
allowedTCPPorts = [
|
|
cfg.httpPort
|
|
cfg.sshPort
|
|
];
|
|
};
|
|
};
|
|
}
|