Files
nixos/flake.nix
Simon Gardling d00ff42e8e site-config: dedupe cross-host values, fix stale dark-reader urls, drop desktop 1g hugepages
new site-config.nix holds values previously duplicated across hosts:
  domain, old_domain, contact_email, timezone, binary_cache (url + pubkey),
  dns_servers, lan (cidr + gateway), hosts.{muffin,yarn} (ip/alias/ssh_host_key),
  ssh_keys.{laptop,desktop,ci_deploy}.

threaded through specialArgs on all three hosts + home-manager extraSpecialArgs +
homeConfigurations.primary + serverLib. service-configs.nix now takes
{ site_config } as a function arg and drops its https namespace; per-service
domains (gitea/matrix/ntfy/mollysocket/livekit/firefox-sync/grafana) are
derived from site_config.domain. ~15 service files and 6 vm tests migrated.

breakage fixes rolled in:
 - home/progs/zen/dark-reader.nix: 5 stale *.gardling.com entries in
   disabledFor rewritten to *.sigkill.computer (caddy 301s the old names so
   these never fired and the new sigkill urls were getting dark-reader applied)
 - modules/desktop-common.nix: drop unused hugepagesz=1G/hugepages=3
   kernelParams (no consumer on mreow or yarn; xmrig on muffin still reserves
   its own via services/monero/xmrig.nix)

verification: muffin toplevel is bit-identical to pre-refactor baseline.
mreow/yarn toplevels differ only in boot.json kernelParams + darkreader
storage.js (nix-diff verified). deployGuardTest and fail2banVaultwardenTest
(latter exercises site_config.domain via bitwarden.nix) pass.
2026-04-22 20:48:29 -04:00

445 lines
15 KiB
Nix

{
description = "Unified NixOS flake for mreow (laptop), yarn (desktop), muffin (server)";
inputs = {
# Two channels: unstable for desktops, 25.11 for server.
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
nixpkgs-stable.url = "github:NixOS/nixpkgs/nixos-25.11";
home-manager = {
url = "github:nix-community/home-manager";
inputs.nixpkgs.follows = "nixpkgs";
};
home-manager-stable = {
url = "github:nix-community/home-manager/release-25.11";
inputs.nixpkgs.follows = "nixpkgs-stable";
};
# Shared across all hosts
lanzaboote = {
url = "github:nix-community/lanzaboote";
inputs.nixpkgs.follows = "nixpkgs";
inputs.rust-overlay.follows = "rust-overlay";
};
nixos-hardware.url = "github:NixOS/nixos-hardware/master";
disko = {
url = "github:nix-community/disko/latest";
inputs.nixpkgs.follows = "nixpkgs";
};
impermanence = {
url = "github:nix-community/impermanence";
inputs.nixpkgs.follows = "nixpkgs";
inputs.home-manager.follows = "home-manager";
};
# Desktop (mreow + yarn)
rust-overlay = {
url = "github:oxalica/rust-overlay";
inputs.nixpkgs.follows = "nixpkgs";
};
zen-browser = {
url = "github:0xc000022070/zen-browser-flake";
inputs.nixpkgs.follows = "nixpkgs";
inputs.home-manager.follows = "home-manager";
};
firefox-addons = {
url = "gitlab:rycee/nur-expressions?dir=pkgs/firefox-addons";
inputs.nixpkgs.follows = "nixpkgs";
};
niri = {
url = "github:sodiboo/niri-flake";
inputs.nixpkgs.follows = "nixpkgs";
inputs.nixpkgs-stable.follows = "nixpkgs";
};
emacs-overlay = {
url = "github:nix-community/emacs-overlay";
inputs.nixpkgs.follows = "nixpkgs";
inputs.nixpkgs-stable.follows = "nixpkgs";
};
nix-flatpak.url = "github:gmodena/nix-flatpak/";
nix-doom-emacs-unstraightened = {
url = "github:marienz/nix-doom-emacs-unstraightened";
inputs.nixpkgs.follows = "nixpkgs";
inputs.emacs-overlay.follows = "emacs-overlay";
};
jovian-nixos = {
url = "github:Jovian-Experiments/Jovian-NixOS";
inputs.nixpkgs.follows = "nixpkgs";
};
noctalia = {
url = "github:noctalia-dev/noctalia-shell";
inputs.nixpkgs.follows = "nixpkgs";
};
nix-cachyos-kernel = {
url = "github:xddxdd/nix-cachyos-kernel/release";
inputs.nixpkgs.follows = "nixpkgs";
};
llm-agents = {
url = "github:numtide/llm-agents.nix";
inputs.nixpkgs.follows = "nixpkgs";
};
json2steamshortcut = {
url = "github:ChrisOboe/json2steamshortcut";
inputs.nixpkgs.follows = "nixpkgs";
};
# Server (muffin) — follows nixpkgs-stable
nix-minecraft = {
url = "github:Infinidoge/nix-minecraft";
inputs.nixpkgs.follows = "nixpkgs-stable";
};
vpn-confinement.url = "github:Maroka-chan/VPN-Confinement";
llamacpp = {
url = "github:TheTom/llama-cpp-turboquant/feature/turboquant-kv-cache";
inputs.nixpkgs.follows = "nixpkgs-stable";
};
srvos = {
url = "github:nix-community/srvos";
inputs.nixpkgs.follows = "nixpkgs-stable";
};
deploy-rs = {
url = "github:serokell/deploy-rs";
inputs.nixpkgs.follows = "nixpkgs-stable";
};
agenix = {
url = "github:ryantm/agenix";
inputs.nixpkgs.follows = "nixpkgs-stable";
inputs.home-manager.follows = "home-manager-stable";
inputs.darwin.follows = "";
};
senior_project-website = {
url = "github:Titaniumtown/senior-project-website";
flake = false;
};
website = {
url = "git+https://git.sigkill.computer/titaniumtown/website";
flake = false;
};
trackerlist = {
url = "github:ngosang/trackerslist";
flake = false;
};
ytbn-graphing-software = {
url = "git+https://git.sigkill.computer/titaniumtown/YTBN-Graphing-Software";
};
arr-init = {
url = "git+ssh://gitea@git.gardling.com/titaniumtown/arr-init";
inputs.nixpkgs.follows = "nixpkgs-stable";
};
nixpkgs-p2pool-module = {
url = "github:JacoMalan1/nixpkgs/create-p2pool-service";
flake = false;
};
qbittorrent-metrics-exporter = {
url = "git+https://codeberg.org/anriha/qbittorrent-metrics-exporter";
inputs.nixpkgs.follows = "nixpkgs-stable";
};
};
outputs =
inputs@{
self,
nixpkgs,
nixpkgs-stable,
home-manager,
home-manager-stable,
lanzaboote,
nixos-hardware,
disko,
impermanence,
nix-minecraft,
vpn-confinement,
srvos,
deploy-rs,
agenix,
arr-init,
nixpkgs-p2pool-module,
jovian-nixos,
...
}:
let
username = "primary";
system = "x86_64-linux";
niriPackage = inputs.niri.packages.${system}.niri-unstable;
# --- Desktop-channel pkgs (used by portable homeConfigurations) ---
desktopPkgs = import nixpkgs { inherit system; };
# --- Server (muffin) plumbing ---
bootstrapPkgs = import nixpkgs-stable { inherit system; };
patchedStableSrc = bootstrapPkgs.applyPatches {
name = "nixpkgs-stable-patched";
src = nixpkgs-stable;
patches = [
./patches/nixpkgs/0001-firefox-syncserver-add-postgresql-backend-support.patch
];
};
serverPkgs = import patchedStableSrc {
inherit system;
targetPlatform = system;
buildPlatform = builtins.currentSystem;
};
siteConfig = import ./site-config.nix;
serviceConfigs = import ./hosts/muffin/service-configs.nix { site_config = siteConfig; };
serverLib = import ./lib {
inherit inputs;
lib = nixpkgs-stable.lib;
pkgs = serverPkgs;
service_configs = serviceConfigs;
site_config = siteConfig;
};
testSuite = import ./tests/tests.nix {
pkgs = serverPkgs;
lib = serverLib;
inherit inputs;
site_config = siteConfig;
config = self.nixosConfigurations.muffin.config;
};
# --- Host builders ---
# Desktop: unstable + home-manager-unstable + niri-unstable
mkDesktopHost =
hostname:
nixpkgs.lib.nixosSystem {
specialArgs = {
inherit inputs username hostname;
niri-package = niriPackage;
site_config = siteConfig;
};
modules = [
home-manager.nixosModules.home-manager
(
{ config, ... }:
{
home-manager.useUserPackages = true;
home-manager.sharedModules = [
inputs.zen-browser.homeModules.twilight
];
home-manager.extraSpecialArgs = {
inherit
inputs
hostname
username
;
niri-package = niriPackage;
homeDirectory = "/home/${username}";
stateVersion = config.system.stateVersion;
site_config = siteConfig;
};
home-manager.users.${username} = import ./hosts/${hostname}/home.nix;
}
)
./hosts/${hostname}/default.nix
];
};
# Server: stable + home-manager-stable + srvos + agenix + patched pkgs
muffinHost = serverLib.nixosSystem {
inherit system;
specialArgs = {
inherit
username
inputs
;
hostname = "muffin";
eth_interface = "enp4s0";
service_configs = serviceConfigs;
site_config = siteConfig;
lib = serverLib;
};
modules = [
# SAFETY! port sanity checks
(
{ config, lib, ... }:
let
publicPorts = lib.attrValues serviceConfigs.ports.public;
privatePorts = lib.attrValues serviceConfigs.ports.private;
allPortNumbers = map (p: p.port) (publicPorts ++ privatePorts);
uniquePortNumbers = lib.unique allPortNumbers;
publicTcp = map (p: p.port) (lib.filter (p: p.proto == "tcp" || p.proto == "both") publicPorts);
publicUdp = map (p: p.port) (lib.filter (p: p.proto == "udp" || p.proto == "both") publicPorts);
privatePortNumbers = map (p: p.port) privatePorts;
fwTcp = config.networking.firewall.allowedTCPPorts;
fwUdp = config.networking.firewall.allowedUDPPorts;
missingTcp = lib.filter (p: !(builtins.elem p fwTcp)) publicTcp;
missingUdp = lib.filter (p: !(builtins.elem p fwUdp)) publicUdp;
leakedTcp = lib.filter (p: builtins.elem p fwTcp) privatePortNumbers;
leakedUdp = lib.filter (p: builtins.elem p fwUdp) privatePortNumbers;
in
{
config.assertions = [
{
assertion = (lib.length allPortNumbers) == (lib.length uniquePortNumbers);
message = "Duplicate port numbers detected in ports.public / ports.private";
}
{
assertion = missingTcp == [ ];
message = "Public ports missing from allowedTCPPorts: ${builtins.toString missingTcp}";
}
{
assertion = missingUdp == [ ];
message = "Public ports missing from allowedUDPPorts: ${builtins.toString missingUdp}";
}
{
assertion = leakedTcp == [ ] && leakedUdp == [ ];
message = "Private ports leaked into firewall allow-lists TCP: ${builtins.toString leakedTcp}, UDP: ${builtins.toString leakedUdp}";
}
];
}
)
srvos.nixosModules.server
srvos.nixosModules.mixins-terminfo
./hosts/muffin/disk.nix
./hosts/muffin/default.nix
# Firefox-syncserver: swap upstream module + package for patched versions.
{
disabledModules = [ "services/networking/firefox-syncserver.nix" ];
imports = [
"${patchedStableSrc}/nixos/modules/services/networking/firefox-syncserver.nix"
];
nixpkgs.overlays = [
nix-minecraft.overlay
(import ./lib/overlays.nix)
(_final: prev: {
syncstorage-rs =
prev.callPackage "${patchedStableSrc}/pkgs/by-name/sy/syncstorage-rs/package.nix"
{ };
})
# NOTE: systemd patch is applied via `systemd.package` in the module
# list below, not via an overlay. An overlay replaces pkgs.systemd
# for every consumer, which cascades through udev-check-hook and
# causes the entire closure (fish, e2fsprogs, valkey, …) to rebuild
# and re-run flaky test suites in the sandbox. `systemd.package`
# only injects the patched systemd into the runtime init chain.
];
nixpkgs.config.allowUnfreePredicate =
pkg:
builtins.elem (nixpkgs-stable.lib.getName pkg) [
"minecraft-server"
];
}
# Runtime-only systemd patch: reset FreezerState on inactive/failed
# transitions so a SIGKILL to a frozen unit doesn't strand
# FreezerState=frozen (unrecoverable without a reboot, upstream issue
# #38517). PR #38528 closed only the watchdog path; this closes
# systemctl kill / OOM / segfault paths too.
#
# Applied via systemd.package, not via overlay, so pkgs.systemd stays
# untouched for every other consumer — no udev-check-hook cascade,
# no fish/e2fsprogs/valkey rebuild, no flaky-test fallout.
(
{ pkgs, ... }:
{
systemd.package = pkgs.systemd.overrideAttrs (old: {
patches = (old.patches or [ ]) ++ [
./patches/systemd/0001-core-unit-reset-freezer-state-on-inactive-failed.patch
];
});
}
)
lanzaboote.nixosModules.lanzaboote
arr-init.nixosModules.default
(import "${nixpkgs-p2pool-module}/nixos/modules/services/networking/p2pool.nix")
home-manager-stable.nixosModules.home-manager
(
{ ... }:
{
home-manager.extraSpecialArgs = {
site_config = siteConfig;
};
home-manager.users.${username} = import ./hosts/muffin/home.nix;
}
)
]
++ (with nixos-hardware.nixosModules; [
common-cpu-amd-pstate
common-cpu-amd-zenpower
common-pc-ssd
common-gpu-intel
]);
};
in
{
formatter.${system} = nixpkgs.legacyPackages.${system}.nixfmt-tree;
nixosConfigurations = {
mreow = mkDesktopHost "mreow";
yarn = mkDesktopHost "yarn";
muffin = muffinHost;
};
# Standalone home-manager profile — usable on any x86_64-linux machine
# with nix installed (NixOS or not). Activate with:
# nix run home-manager/master -- switch --flake ".#primary"
# Ships the shared terminal profile (fish, helix, modern CLI, git).
homeConfigurations.primary = home-manager.lib.homeManagerConfiguration {
pkgs = desktopPkgs;
extraSpecialArgs = {
site_config = siteConfig;
};
modules = [
./home/profiles/terminal.nix
{
home = {
username = username;
homeDirectory = "/home/${username}";
stateVersion = "24.11";
};
}
];
};
deploy.nodes.muffin = {
hostname = siteConfig.hosts.muffin.alias;
profiles.system = {
sshUser = "root";
user = "root";
# Deploy guard enforcement lives in the preflight driver (deploy.sh
# and .gitea/workflows/deploy.yml) — not in activation. Activation-
# time enforcement is unsafe: deploy-rs sets the new profile pointer
# before running deploy-rs-activate, so a non-zero activation exit
# triggers auto-rollback which re-runs switch-to-configuration on the
# previous generation. That re-activation rotates agenix secrets,
# reinstalls lanzaboote, and reloads systemd units — side effects we
# want to avoid when the deploy is supposed to be a no-op blocked by
# the guard. Blocking before the deploy-rs invocation is the only
# clean way to leave the running system untouched.
path = deploy-rs.lib.${system}.activate.nixos self.nixosConfigurations.muffin;
};
};
checks.${system} = testSuite;
packages.${system} = {
tests = serverPkgs.linkFarm "all-tests" (
serverPkgs.lib.mapAttrsToList (name: test: {
name = name;
path = test;
}) testSuite
);
# Buildenv of every binary in the portable terminal profile. Install
# without home-manager via:
# nix profile install ".#cli-tools"
cli-tools = self.homeConfigurations.primary.config.home.path;
}
// (serverPkgs.lib.mapAttrs' (name: test: {
name = "test-${name}";
value = test;
}) testSuite);
lib = serverLib;
};
}