237 lines
6.3 KiB
Nix
237 lines
6.3 KiB
Nix
# This module sets configuration for all NixOS machines defined in this flake
|
|
|
|
{ config, options, lib, pkgs, ... }:
|
|
|
|
let
|
|
hqPrefix64 = "fd23:42:c3d2:523";
|
|
# TODO: Is this stable? Is there a better place to specifiy this?
|
|
|
|
# Generate a deterministic IPv6 address for a 64 bit prefix
|
|
# and seed string. Prefix must not contain trailing ':'.
|
|
toIpv6Address = prefix64: seed:
|
|
with builtins;
|
|
let
|
|
digest = builtins.hashString "sha256" seed;
|
|
hextets = map (i: substring (4 * i) 4 digest) [ 0 1 2 3 ];
|
|
in concatStringsSep ":" ([ prefix64 ] ++ hextets);
|
|
|
|
# Generate a deterministic public IPv6 addresses
|
|
# for the HQ networking using a seed string.
|
|
toHqPrivateAddress = toIpv6Address hqPrefix64;
|
|
|
|
in {
|
|
|
|
imports = [
|
|
./stats.nix
|
|
./audio-server
|
|
./ceph-storage.nix
|
|
./cache.nix
|
|
];
|
|
|
|
|
|
config = let
|
|
cfg = config.c3d2;
|
|
mkIfIsInHq = x: lib.mkIf cfg.isInHq (lib.mkDefault x);
|
|
in {
|
|
# Configuration specific to this machine
|
|
|
|
assertions = [
|
|
{
|
|
assertion = cfg.isInHq -> (config.users.users.root.password == null);
|
|
message = "Root passwords not allowed in HQ";
|
|
}
|
|
{
|
|
assertion = cfg.hq.enableBinaryCache -> cfg.mergeHostsFile;
|
|
message = "mergeHostsFile must be enabled for enableBinaryCache";
|
|
}
|
|
{
|
|
assertion = cfg.hq.enableMpdProxy -> cfg.mergeHostsFile;
|
|
message = "mergeHostsFile must be enabled for enableMpdProxy";
|
|
}
|
|
{
|
|
assertion = cfg.isInHq -> builtins.hasAttr config.networking.hostName cfg.hosts;
|
|
message = "${config.networking.hostName} is not registered in ${
|
|
toString ../host-registry.nix
|
|
}";
|
|
}
|
|
( # Check for host registry address collisions
|
|
let
|
|
getAddrHosts = key:
|
|
builtins.foldl' (result: host:
|
|
if cfg.hosts.${host}.${key} != null
|
|
then let
|
|
addr = cfg.hosts."${host}"."${key}";
|
|
in if result ? "${addr}"
|
|
then result // {
|
|
"${addr}" = result."${addr}" ++ [ host ];
|
|
}
|
|
else result // {
|
|
"${addr}" = [ host ];
|
|
}
|
|
else result
|
|
) {} (builtins.attrNames cfg.hosts);
|
|
dupHosts =
|
|
builtins.concatMap (hosts:
|
|
if builtins.length hosts == 1
|
|
then []
|
|
else hosts
|
|
) (
|
|
builtins.attrValues (
|
|
getAddrHosts "ip4" // getAddrHosts "ip6"
|
|
)
|
|
);
|
|
in {
|
|
assertion = dupHosts == [];
|
|
message = "Hosts have duplicate addresses: ${
|
|
lib.concatStringsSep " " dupHosts
|
|
}";
|
|
})
|
|
];
|
|
|
|
c3d2.allUsersCanSshRoot = lib.mkDefault true;
|
|
|
|
networking.defaultGateway = lib.mkIf (!config.networking.useNetworkd) (
|
|
mkIfIsInHq "172.22.99.4"
|
|
);
|
|
|
|
networking.domain = mkIfIsInHq "hq.c3d2.de";
|
|
|
|
systemd.network.networks =
|
|
if cfg.hq.interface != null && config.networking.useNetworkd
|
|
then {
|
|
"40-eth0".routes = [ {
|
|
routeConfig = {
|
|
Gateway = "172.22.99.4";
|
|
GatewayOnLink = true;
|
|
};
|
|
} ];
|
|
} else {};
|
|
networking.interfaces =
|
|
/* (if cfg.hq.externalInterface == null then
|
|
{ }
|
|
else {
|
|
"${cfg.hq.externalInterface}" = {
|
|
ipv6.addresses = [{
|
|
address = toHqPublicAddress config.networking.hostName;
|
|
prefixLength = 64;
|
|
}];
|
|
};
|
|
}) //
|
|
*/
|
|
if cfg.hq.interface == null then
|
|
{ }
|
|
else {
|
|
"${cfg.hq.interface}" = {
|
|
ipv6.addresses = [{
|
|
address = toHqPrivateAddress config.networking.hostName;
|
|
prefixLength = 64;
|
|
}];
|
|
};
|
|
};
|
|
|
|
nix = {
|
|
autoOptimiseStore = true;
|
|
extraOptions = "experimental-features = nix-command flakes";
|
|
gc = {
|
|
automatic = true;
|
|
dates = "weekly";
|
|
};
|
|
package = pkgs.nixUnstable;
|
|
registry.c3d2 = {
|
|
from = {
|
|
id = "c3d2";
|
|
type = "indirect";
|
|
};
|
|
to = {
|
|
type = "git";
|
|
url = "https://gitea.c3d2.de/C3D2/nix-config.git";
|
|
};
|
|
};
|
|
};
|
|
|
|
# Required for deployment
|
|
services.openssh = {
|
|
enable = true;
|
|
permitRootLogin = "prohibit-password";
|
|
};
|
|
|
|
environment = {
|
|
systemPackages = with pkgs; [
|
|
curl wget
|
|
git
|
|
htop
|
|
tmux
|
|
vim
|
|
# Pipeview
|
|
pv
|
|
# Network debugging
|
|
tcpdump bmon ethtool mtr
|
|
];
|
|
variables = {
|
|
TERM = "xterm-256color";
|
|
};
|
|
};
|
|
|
|
programs = {
|
|
ssh.knownHosts = with builtins;
|
|
let
|
|
intersectKeys = intersectAttrs {
|
|
publicKey = null;
|
|
publicKeyFile = null;
|
|
};
|
|
list = map (name:
|
|
let
|
|
host = getAttr name cfg.hosts;
|
|
sshAttrs = intersectKeys host;
|
|
in if sshAttrs == { } then
|
|
null
|
|
else {
|
|
inherit name;
|
|
value = let
|
|
ip6 = if host.ip6 != null then
|
|
host.ip6
|
|
else
|
|
toHqPrivateAddress name;
|
|
in {
|
|
publicKey = null;
|
|
publicKeyFile = null;
|
|
hostNames = [ ip6 "${name}.hq.c3d2.de" "${name}.hq" name ];
|
|
} // sshAttrs;
|
|
}) (builtins.attrNames cfg.hosts);
|
|
keyedHosts = filter (x: x.value.publicKey != null || x.value.publicKeyFile != null) list;
|
|
in listToAttrs keyedHosts;
|
|
|
|
vim.defaultEditor = true;
|
|
};
|
|
|
|
services.mpd.extraConfig = lib.mkIf cfg.hq.enableMpdProxy ''
|
|
database {
|
|
plugin "proxy"
|
|
host "mpd-index.c3d2"
|
|
}
|
|
'';
|
|
|
|
time.timeZone = lib.mkDefault "Europe/Berlin";
|
|
|
|
# Reboot on hang
|
|
systemd.watchdog = lib.mkIf (!config.boot.isContainer) {
|
|
runtimeTime = "15s";
|
|
rebootTime = "15s";
|
|
};
|
|
|
|
# Defaults for LetsEncrypt
|
|
security.acme =
|
|
if options.security.acme ? defaults
|
|
then {
|
|
acceptTerms = true;
|
|
# NixOS>=22.05
|
|
defaults.email = cfg.acmeEmail;
|
|
}
|
|
else {
|
|
acceptTerms = true;
|
|
# TODO: NixOS<=21.05
|
|
email = cfg.acmeEmail;
|
|
};
|
|
};
|
|
}
|