# 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; }; }; }