Files
sift/nix/module.nix
T
kyle 099b94979c p0: IANA special-purpose deny table, extra deny prefixes
Block 6to4/Teredo/NAT64-local/site-local/benchmarking/reserved
ranges from the IANA registries (families, not decoded embeds).
Guard.DenyPrefixes / -deny-prefix covers hairpin WAN /32s; home
addresses stay on-box, not in git. Control is tcp/tcp4/tcp6 only.
2026-09-22 21:33:52 -07:00

162 lines
5.0 KiB
Nix

{ config, lib, pkgs, ... }:
let
cfg = config.services.sift;
settingsFormat = pkgs.formats.toml { };
in
{
options.services.sift = {
enable = lib.mkEnableOption "sift LLM-oriented fetch and search";
package = lib.mkOption {
type = lib.types.package;
description = "sift package. The flake module sets this to packages.sift.";
};
listen = lib.mkOption {
type = lib.types.str;
default = "127.0.0.1:8890";
description = "Address the HTTP server binds to (loopback by default).";
};
tailscaleServe = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Advertise the listener on tailscale serve at https://<host>:8443.";
};
tailscaleHttpsPort = lib.mkOption {
type = lib.types.port;
default = 8443;
description = "HTTPS port for tailscale serve (443 is SearXNG on orion).";
};
denyPrefixes = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
description = ''
Extra CIDRs the SSRF guard blocks at pre-check and connect time.
Put home WAN /32s here (hairpin into LAN). Set on the host; do not
commit residential IPs to the sift repo.
'';
};
settings = lib.mkOption {
type = settingsFormat.type;
default = { };
description = "Written to /etc/sift/config.toml. Unused keys are reserved for P1+.";
};
};
config = lib.mkIf cfg.enable {
assertions = [
{
assertion = cfg.package != null;
message = "services.sift.package must be set (the flake module does this).";
}
];
users.users.sift = {
isSystemUser = true;
group = "sift";
home = "/var/lib/sift";
};
users.groups.sift = { };
environment.etc."sift/config.toml".source = settingsFormat.generate "sift.toml" (
{ listen = cfg.listen; } // cfg.settings
);
# Keys and env secrets are created on-box, never in the store.
systemd.tmpfiles.rules = [
"d /var/lib/sift 0750 root sift -"
];
system.activationScripts.sift-secrets = {
deps = [ "users" ];
text = ''
install -d -m 0750 -o root -g sift /var/lib/sift
if [ ! -f /var/lib/sift/keys.toml ]; then
umask 027
printf '%s\n' '# key-hash → { name, workspace }. Generated empty; fill on-box.' > /var/lib/sift/keys.toml
chown root:sift /var/lib/sift/keys.toml
chmod 0640 /var/lib/sift/keys.toml
fi
if [ ! -f /var/lib/sift/secret.env ]; then
umask 027
printf '%s\n' '# BRAVE_API_KEY= (set on-box; do not read SearXNG secret.env)' > /var/lib/sift/secret.env
chown root:sift /var/lib/sift/secret.env
chmod 0640 /var/lib/sift/secret.env
fi
'';
};
systemd.services.sift = {
description = "sift LLM-oriented fetch and search";
after = [ "network-online.target" ];
wants = [ "network-online.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "simple";
User = "sift";
Group = "sift";
ExecStart = "${lib.getExe cfg.package} -listen ${cfg.listen} -config /etc/sift/config.toml"
+ lib.concatMapStrings (p: " -deny-prefix ${lib.escapeShellArg p}") cfg.denyPrefixes;
WorkingDirectory = "/var/lib/sift";
Restart = "on-failure";
RestartSec = "5s";
NoNewPrivileges = true;
ProtectSystem = "strict";
ProtectHome = true;
PrivateTmp = true;
PrivateDevices = true;
ProtectKernelTunables = true;
ProtectKernelModules = true;
ProtectControlGroups = true;
ProtectHostname = true;
ProtectClock = true;
RestrictAddressFamilies = [
"AF_UNIX"
"AF_INET"
"AF_INET6"
];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
LockPersonality = true;
MemoryDenyWriteExecute = true;
SystemCallArchitectures = "native";
SystemCallFilter = [
"@system-service"
"~@privileged"
];
CapabilityBoundingSet = "";
AmbientCapabilities = "";
ReadWritePaths = [ "/var/lib/sift" ];
ConfigurationDirectory = "sift";
StateDirectory = "sift";
};
};
systemd.services.tailscale-serve-sift = lib.mkIf cfg.tailscaleServe {
description = "Advertise sift on Tailscale Serve :${toString cfg.tailscaleHttpsPort}";
after = [
"tailscaled.service"
"network-online.target"
"sift.service"
];
wants = [
"tailscaled.service"
"network-online.target"
];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
Restart = "on-failure";
RestartSec = "5s";
ExecStart = "${lib.getExe pkgs.tailscale} serve --bg --yes --https=${toString cfg.tailscaleHttpsPort} http://${cfg.listen}";
};
};
};
}