as a NixoS module. A nice trick h
-
{ self, inputs, config, lib, homeLib, outputs, globals, nodes, minimal, configName, arch, type, ... }:
+{ self, inputs, config, lib, homeLib, outputs, globals, nodes, minimal, configName, arch, type, withHomeManager, ... }:
{
options.swarselmodules.home-manager = lib.mkEnableOption "home-manager";
config = lib.mkIf config.swarselmodules.home-manager {
- home-manager = lib.mkIf config.swarselsystems.withHomeManager {
+ home-manager = lib.mkIf withHomeManager {
useGlobalPkgs = true;
useUserPackages = true;
verbose = true;
@@ -7751,7 +8019,7 @@ For that reason, make sure that sops-nix is properly working before
description = "Leon S";
password = lib.mkIf (minimal || config.swarselsystems.isPublic) "setup";
hashedPasswordFile = lib.mkIf (!minimal && !config.swarselsystems.isPublic) config.sops.secrets.main-user-hashed-pw.path;
- extraGroups = [ "wheel" ] ++ lib.optionals (!minimal) [ "networkmanager" "syncthing" "docker" "lp" "audio" "video" "vboxusers" "libvirtd" "scanner" ];
+ extraGroups = [ "wheel" ] ++ lib.optionals (!minimal && !config.swarselsystems.isMicroVM) [ "networkmanager" "syncthing" "docker" "lp" "audio" "video" "vboxusers" "libvirtd" "scanner" ];
packages = with pkgs; [ ];
};
};
@@ -8533,7 +8801,7 @@ in
};
networking = {
- inherit (config.swarselsystems) hostName;
+ hostName = config.node.name;
hosts = {
"${globals.networks.home-lan.hosts.winters.ipv4}" = [ globals.services.transmission.domain ];
};
@@ -8928,7 +9196,7 @@ By default, stylix wants to style
-
{ self, lib, config, vars, ... }:
+{ self, lib, config, vars, withHomeManager, ... }:
{
options.swarselmodules.stylix = lib.mkEnableOption "stylix config";
config = {
@@ -8942,6 +9210,7 @@ By default, stylix wants to style
image = config.swarselsystems.wallpaper;
}
vars.stylix);
+ } // lib.optionalAttrs withHomeManager {
home-manager.users."${config.swarselsystems.mainUser}" = {
stylix = {
targets = vars.stylixHomeTargets;
@@ -9635,23 +9904,24 @@ This is used to better integrate Sway into the system on NixOS hosts. On the hom
-
{ lib, config, pkgs, ... }:
+{ lib, config, pkgs, withHomeManager, ... }:
let
inherit (config.swarselsystems) mainUser;
in
{
options.swarselmodules.sway = lib.mkEnableOption "sway config";
- config = lib.mkIf config.swarselmodules.sway {
- programs.sway = {
- enable = true;
- package = pkgs.swayfx;
- wrapperFeatures = {
- base = true;
- gtk = true;
+ config = lib.mkIf config.swarselmodules.sway
+ {
+ programs.sway = {
+ enable = true;
+ package = pkgs.swayfx;
+ wrapperFeatures = {
+ base = true;
+ gtk = true;
+ };
};
-
- inherit (config.home-manager.users.${mainUser}.wayland.windowManager.sway) extraSessionCommands;
- };
+ } // lib.optionalAttrs withHomeManager {
+ inherit (config.home-manager.users.${mainUser}.wayland.windowManager.sway) extraSessionCommands;
};
}
@@ -9959,17 +10229,19 @@ in
}
config.swarselsystems.shellAliases;
- nixpkgs.config.permittedInsecurePackages = [
- # matrix
- "olm-3.2.16"
- # sonarr
- "aspnetcore-runtime-wrapped-6.0.36"
- "aspnetcore-runtime-6.0.36"
- "dotnet-sdk-wrapped-6.0.428"
- "dotnet-sdk-6.0.428"
- #
- "SDL_ttf-2.0.11"
- ];
+ nixpkgs.config = lib.mkIf (!config.swarselsystems.isMicroVM) {
+ permittedInsecurePackages = [
+ # matrix
+ "olm-3.2.16"
+ # sonarr
+ "aspnetcore-runtime-wrapped-6.0.36"
+ "aspnetcore-runtime-6.0.36"
+ "dotnet-sdk-wrapped-6.0.428"
+ "dotnet-sdk-6.0.428"
+ #
+ "SDL_ttf-2.0.11"
+ ];
+ };
};
}
@@ -9979,8 +10251,12 @@ in
3.2.3.3. System Packages (Server Programs)
+
+This is a collection of packages that are useful for server-type hosts that do not really fit into other modules; the optional part of the list is for packages that are built as part of Packages (config); systems that are not built with home-manager will not be able to pass the required parameters to build these packages, hence we cannot build them here. This mostly applies to microvms.
+
+
-
{ lib, config, pkgs, ... }:
+{ lib, config, pkgs, withHomeManager, ... }:
{
options.swarselmodules.server.packages = lib.mkEnableOption "enable packages on server";
config = lib.mkIf config.swarselmodules.server.packages {
@@ -9996,6 +10272,7 @@ in
tmux
busybox
swarsel-deploy
+ ] ++ lib.optionals withHomeManager [
swarsel-gens
swarsel-switch
];
@@ -10068,8 +10345,8 @@ in
-
-
3.2.3.5. acme
+
+
3.2.3.5. acme
{ self, pkgs, lib, config, globals, ... }:
@@ -10297,7 +10574,7 @@ Here I am forcing startWhenNeeded to false so that the value will n
-
{ self, lib, config, ... }:
+{ self, lib, config, withHomeManager, ... }:
{
options.swarselmodules.server.ssh = lib.mkEnableOption "enable ssh on server";
config = lib.mkIf config.swarselmodules.server.ssh {
@@ -10320,16 +10597,18 @@ Here I am forcing startWhenNeeded to false so that the value will n
}
];
};
- users.users."${config.swarselsystems.mainUser}".openssh.authorizedKeys.keyFiles = [
- (self + /secrets/public/ssh/yubikey.pub)
- (self + /secrets/public/ssh/magicant.pub)
- # (lib.mkIf config.swarselsystems.isBastionTarget (self + /secrets/public/ssh/jump.pub))
- ];
- users.users.root.openssh.authorizedKeys.keyFiles = [
- (self + /secrets/public/ssh/yubikey.pub)
- (self + /secrets/public/ssh/magicant.pub)
- # (lib.mkIf config.swarselsystems.isBastionTarget (self + /secrets/public/ssh/jump.pub))
- ];
+ users.users = {
+ "${config.swarselsystems.mainUser}".openssh.authorizedKeys.keyFiles = lib.mkIf withHomeManager [
+ (self + /secrets/public/ssh/yubikey.pub)
+ (self + /secrets/public/ssh/magicant.pub)
+ # (lib.mkIf config.swarselsystems.isBastionTarget (self + /secrets/public/ssh/jump.pub))
+ ];
+ root.openssh.authorizedKeys.keyFiles = [
+ (self + /secrets/public/ssh/yubikey.pub)
+ (self + /secrets/public/ssh/magicant.pub)
+ # (lib.mkIf config.swarselsystems.isBastionTarget (self + /secrets/public/ssh/jump.pub))
+ ];
+ };
security.sudo.extraConfig = ''
Defaults env_keep+=SSH_AUTH_SOCK
'';
@@ -10343,10 +10622,10 @@ Here I am forcing startWhenNeeded to false so that the value will n
3.2.3.8. Bastion
-
{ self, lib, config, ... }:
+{ self, lib, config, withHomeManager, ... }:
{
options.swarselmodules.server.bastion = lib.mkEnableOption "enable bastion on server";
- config = lib.mkIf config.swarselmodules.server.bastion {
+ config = lib.mkIf config.swarselmodules.server.bastion ({
users = {
groups = {
@@ -10395,6 +10674,7 @@ Here I am forcing startWhenNeeded to false so that the value will n
}
];
};
+ } // lib.optionalAttrs withHomeManager {
home-manager.users.jump.config = {
home.stateVersion = lib.mkDefault "23.05";
@@ -10408,7 +10688,7 @@ Here I am forcing startWhenNeeded to false so that the value will n
} // config.repo.secrets.local.ssh.hosts;
};
};
- };
+ });
}
@@ -10527,6 +10807,7 @@ in
inherit (config.repo.secrets.local.networking) defaultGateway4;
wanAddress4 = netConfig.wanAddress4 or null;
wanAddress6 = netConfig.wanAddress6 or null;
+ isHome = if (netPrefix == "home") then true else false;
};
networking = {
@@ -10757,8 +11038,8 @@ in
-
-
3.2.3.12. Attic setup
+
+
3.2.3.12. Attic setup
By default, attic only provides a cli client to authenticate to caches. I want all my servers to use my main binary cache, which is what I set up here.
@@ -10873,15 +11154,17 @@ in
lib.mkEnableOption "enable ${serviceName} settings";
swarselsystems.server.wireguard = {
- interfaces = lib.mkOption {
- type = lib.types.attrsOf (lib.types.submodule ({ name, config, ... }: {
+ interfaces = let
+ topConfig = config;
+ in lib.mkOption {
+ type = lib.types.attrsOf (lib.types.submodule ({ config, name, ... }: {
options = {
isServer = lib.mkEnableOption "set this interface as a wireguard server";
isClient = lib.mkEnableOption "set this interface as a wireguard client";
serverName = lib.mkOption {
type = lib.types.str;
- default = "";
+ default = if config.isServer then topConfig.node.name else "";
description = "Hostname of the WireGuard server this interface connects to (when isClient = true).";
};
@@ -10904,10 +11187,16 @@ in
description = "Name of the WireGuard interface.";
};
+ port = lib.mkOption {
+ type = lib.types.int;
+ default = servicePort;
+ description = "Port of the WireGuard interface.";
+ };
+
peers = lib.mkOption {
type = lib.types.listOf lib.types.str;
- default = [ ];
- description = "WireGuard peer config names (clients when this host is server, or additional peers).";
+ default = lib.attrNames (lib.filterAttrs (name: _: name != topConfig.node.name) globals.networks."${config.serverNetConfigPrefix}-${config.ifName}".hosts);
+ description = "WireGuard peer config names of this wireguardinterface.";
};
};
}));
@@ -10919,6 +11208,25 @@ in
config = lib.mkIf config.swarselmodules.server.${serviceName} {
+ assertions = lib.concatLists (
+ lib.flip lib.mapAttrsToList interfaces (
+ ifName: ifCfg:
+ let
+ assertionPrefix = "While evaluating the wireguard network ${ifName}:";
+ in
+ [
+ {
+ assertion = ifCfg.isServer || (ifCfg.isClient && ifCfg.serverName != "");
+ message = "${assertionPrefix}: This node must either be a server for the wireguard network or a client with serverName set.";
+ }
+ {
+ assertion = lib.stringLength ifName < 16;
+ message = "${assertionPrefix}: The specified linkName '${ifName}' is too long (must be max 15 characters).";
+ }
+ ]
+ )
+ );
+
environment.systemPackages = with pkgs; [
wireguard-tools
];
@@ -10927,7 +11235,6 @@ in
lib.mkMerge (
[
{
- # shared host private key
wireguard-private-key = {
inherit sopsFile;
owner = serviceUser;
@@ -10938,8 +11245,8 @@ in
] ++ (map
(i:
let
- simpleClientSecrets =
- lib.optionalAttrs (i.isClient && i.peers == [ ]) {
+ clientSecrets =
+ lib.optionalAttrs i.isClient {
"wireguard-${i.serverName}-${config.node.name}-${i.ifName}-presharedKey" = {
sopsFile = wgSopsFile;
owner = serviceUser;
@@ -10948,8 +11255,8 @@ in
};
};
- multiPeerSecrets =
- lib.optionalAttrs (i.peers != [ ]) (builtins.listToAttrs (map
+ serverSecrets =
+ lib.optionalAttrs i.isServer (builtins.listToAttrs (map
(clientName: {
name = "wireguard-${config.node.name}-${clientName}-${i.ifName}-presharedKey";
value = {
@@ -10961,17 +11268,72 @@ in
})
i.peers));
in
- simpleClientSecrets // multiPeerSecrets
+ clientSecrets // serverSecrets
)
ifaceList)
);
- networking = {
- firewall.checkReversePath =
- lib.mkIf (lib.any (i: i.isClient) ifaceList) "loose";
+ networking.firewall = {
+ checkReversePath = lib.mkIf (lib.any (i: i.isClient) ifaceList) "loose";
+ allowedUDPPorts = lib.mkMerge (
+ lib.flip lib.mapAttrsToList interfaces (
+ _: ifCfg:
+ lib.optional ifCfg.isServer ifCfg.port
+ )
+ );
+ };
- firewall.allowedUDPPorts =
- lib.mkIf (lib.any (i: i.isServer) ifaceList) [ servicePort ];
+ networking.nftables.firewall = {
+ zones = lib.mkMerge
+ (
+ lib.flip lib.mapAttrsToList interfaces (
+ ifName: ifCfg:
+ {
+ ${ifName}.interfaces = [ ifName ];
+ }
+ // lib.listToAttrs (map
+ (peer:
+ let
+ peerNet = globals.networks."${ifCfg.serverNetConfigPrefix}-${ifName}".hosts.${peer};
+ in
+ lib.nameValuePair "${ifName}-node-${peer}" {
+ parent = ifName;
+ ipv4Addresses = lib.optional (peerNet.ipv4 != null) peerNet.ipv4;
+ ipv6Addresses = lib.optional (peerNet.ipv6 != null) peerNet.ipv6;
+ }
+ )
+ ifCfg.peers)
+ )
+ );
+ rules = lib.mkMerge (
+ lib.flip lib.mapAttrsToList interfaces (
+ ifName: ifCfg:
+ let
+ inherit (config.networking.nftables.firewall) localZoneName;
+ netCfg = globals.networks."${ifCfg.serverNetConfigPrefix}-${ifName}";
+ in
+ {
+ "${ifName}-to-${localZoneName}" = {
+ inherit (netCfg.firewallRuleForAll) allowedTCPPorts allowedUDPPorts;
+ from = [ ifName ];
+ to = [ localZoneName ];
+ ignoreEmptyRule = true;
+ };
+ }
+ // lib.listToAttrs (map
+ (peer:
+ lib.nameValuePair "${ifName}-node-${peer}-to-${localZoneName}" (
+ lib.mkIf (netCfg.firewallRuleForNode ? ${peer}) {
+ inherit (netCfg.firewallRuleForNode.${peer}) allowedTCPPorts allowedUDPPorts;
+ from = [ "${ifName}-node-${peer}" ];
+ to = [ localZoneName ];
+ ignoreEmptyRule = true;
+ }
+ )
+ )
+ ifCfg.peers)
+ )
+ );
};
systemd.network = {
@@ -10989,14 +11351,10 @@ in
MTUBytes = 1408; # TODO: figure out where we lose those 12 bits (8 from pppoe maybe + ???)
};
- address =
- if i.isServer then [
- globals.networks."${config.swarselsystems.server.netConfigPrefix}-${ifName}".hosts.${config.node.name}.cidrv4
- globals.networks."${config.swarselsystems.server.netConfigPrefix}-${ifName}".hosts.${config.node.name}.cidrv6
- ] else [
- globals.networks."${i.serverNetConfigPrefix}-${ifName}".hosts.${config.node.name}.cidrv4
- globals.networks."${i.serverNetConfigPrefix}-${ifName}".hosts.${config.node.name}.cidrv6
- ];
+ address = [
+ globals.networks."${i.serverNetConfigPrefix}-${ifName}".hosts.${config.node.name}.cidrv4
+ globals.networks."${i.serverNetConfigPrefix}-${ifName}".hosts.${config.node.name}.cidrv6
+ ];
};
})
ifaceList);
@@ -11049,12 +11407,12 @@ in
builtins.readFile "${self}/secrets/public/wg/${clientName}.pub";
PresharedKeyFile =
- config.sops.secrets."wireguard-${config.node.name}-${clientName}-${i.ifName}-presharedKey".path;
+ config.sops.secrets."wireguard-${i.serverName}-${clientName}-${i.ifName}-presharedKey".path;
AllowedIPs =
let
clientInWgNetwork =
- globals.networks."${config.swarselsystems.server.netConfigPrefix}-${i.ifName}".hosts.${clientName};
+ globals.networks."${i.serverNetConfigPrefix}-${i.ifName}".hosts.${clientName};
in
(lib.optional (clientInWgNetwork.ipv4 != null)
(lib.net.cidr.make 32 clientInWgNetwork.ipv4))
@@ -11092,62 +11450,152 @@ in
3.2.3.15. Router
+
+This is the configuration to make Hintbooth (Router: HUNSN RM02) act as the router for my internal network. This is not a reusable module and highly adapted to its hardware.
+
+
-
{ lib, config, ... }:
+{ lib, config, globals, ... }:
let
serviceName = "router";
in
{
options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
- config = lib.mkIf config.swarselmodules.server.${serviceName} {
+ config = lib.mkIf config.swarselmodules.server.${serviceName}
+ {
+ services.avahi.reflector = true;
- systemd.network = {
- wait-online.anyInterface = true;
- networks = {
- "30-lan0" = {
- matchConfig.Name = "lan0";
- linkConfig.RequiredForOnline = "enslaved";
- networkConfig = {
- ConfigureWithoutCarrier = true;
+ networking.nftables = {
+ firewall = {
+ zones = {
+ untrusted.interfaces = [ "lan" ];
+ wgHome.interfaces = [ "wgHome" ];
+ adguardhome.ipv4Addresses = [ globals.networks.home-lan.vlans.services.hosts.hintbooth-adguardhome.ipv4 ];
+ adguardhome.ipv6Addresses = [ globals.networks.home-lan.vlans.services.hosts.hintbooth-adguardhome.ipv6 ];
+ }
+ // lib.flip lib.concatMapAttrs globals.networks.home-lan.vlans (
+ vlanName: _: {
+ "vlan-${vlanName}".interfaces = [ "me-${vlanName}" ];
+ }
+ );
+
+ rules = {
+ masquerade-internet = {
+ from = map (name: "vlan-${name}") (builtins.attrNames globals.networks.home-lan.vlans);
+ to = [ "untrusted" ];
+ # masquerade = true; NOTE: custom rule below for ip4 + ip6
+ late = true; # Only accept after any rejects have been processed
+ verdict = "accept";
+ };
+
+ # Allow access to the AdGuardHome DNS server from any VLAN that has internet access
+ access-adguardhome-dns = {
+ from = map (name: "vlan-${name}") (builtins.attrNames globals.networks.home-lan.vlans);
+ to = [ "adguardhome" ];
+ verdict = "accept";
+ };
+
+ # Allow devices in the home VLAN to talk to any of the services or home devices.
+ access-services = {
+ from = [ "vlan-home" ];
+ to = [
+ "vlan-services"
+ "vlan-devices"
+ ];
+ late = true;
+ verdict = "accept";
+ };
+
+ # Allow the services VLAN to talk to our wireguard server
+ services-to-local = {
+ from = [ "vlan-services" ];
+ to = [ "local" ];
+ allowedUDPPorts = [ 52829 ];
+ };
+
+ # Forward traffic between wireguard participants
+ forward-proxy-home-vpn-traffic = {
+ from = [ "wgHome" ];
+ to = [ "wgHome" ];
+ verdict = "accept";
+ };
};
};
- "30-lan1" = {
- matchConfig.Name = "lan1";
- linkConfig.RequiredForOnline = "enslaved";
- networkConfig = {
- ConfigureWithoutCarrier = true;
+
+ chains.postrouting = {
+ masquerade-internet = {
+ after = [ "hook" ];
+ late = true;
+ rules =
+ lib.forEach
+ (map (name: "vlan-${name}") (builtins.attrNames globals.networks.home-lan.vlans))
+ (
+ zone:
+ lib.concatStringsSep " " [
+ "meta protocol { ip, ip6 }"
+ (lib.head config.networking.nftables.firewall.zones.${zone}.ingressExpression)
+ (lib.head config.networking.nftables.firewall.zones.untrusted.egressExpression)
+ "masquerade random"
+ ]
+ );
};
};
- "30-lan2" = {
- matchConfig.Name = "lan2";
- linkConfig.RequiredForOnline = "enslaved";
- networkConfig = {
- ConfigureWithoutCarrier = true;
+ };
+
+ boot.kernel.sysctl = {
+ "net.ipv4.ip_forward" = 1;
+ "net.ipv4.conf.all.forwarding" = true;
+ "net.ipv6.conf.all.forwarding" = true;
+ };
+
+ systemd.network = {
+ wait-online.anyInterface = true;
+ networks = {
+ "30-lan1" = {
+ matchConfig.MACAddress = config.repo.secrets.local.networking.networks.lan1.mac;
+ linkConfig.RequiredForOnline = "enslaved";
+ networkConfig = {
+ Bridge = "br";
+ ConfigureWithoutCarrier = true;
+ };
+ };
+ "30-lan2" = {
+ matchConfig.MACAddress = config.repo.secrets.local.networking.networks.lan2.mac;
+ linkConfig.RequiredForOnline = "enslaved";
+ networkConfig = {
+ Bridge = "br";
+ ConfigureWithoutCarrier = true;
+ };
+ };
+ "30-lan3" = {
+ matchConfig.MACAddress = config.repo.secrets.local.networking.networks.lan3.mac;
+ linkConfig.RequiredForOnline = "enslaved";
+ networkConfig = {
+ Bridge = "br";
+ ConfigureWithoutCarrier = true;
+ };
+ };
+ "30-lan4" = {
+ matchConfig.MACAddress = config.repo.secrets.local.networking.networks.lan4.mac;
+ linkConfig.RequiredForOnline = "enslaved";
+ networkConfig = {
+ Bridge = "br";
+ ConfigureWithoutCarrier = true;
+ };
+ };
+ "30-lan5" = {
+ matchConfig.MACAddress = config.repo.secrets.local.networking.networks.lan5.mac;
+ linkConfig.RequiredForOnline = "enslaved";
+ networkConfig = {
+ Bridge = "br";
+ ConfigureWithoutCarrier = true;
+ };
};
};
- "30-lan3" = {
- matchConfig.Name = "lan3";
- linkConfig.RequiredForOnline = "enslaved";
- networkConfig = {
- ConfigureWithoutCarrier = true;
- };
- };
- "10-wan" = {
- matchConfig.Name = "wan";
- networkConfig = {
- # start a DHCP Client for IPv4 Addressing/Routing
- DHCP = "ipv4";
- DNSOverTLS = true;
- DNSSEC = true;
- IPv6PrivacyExtensions = false;
- IPForward = true;
- };
- # make routing on this interface a dependency for network-online.target
- linkConfig.RequiredForOnline = "routable";
+ };
+
+
};
- };
-};
- };
}
@@ -11161,7 +11609,7 @@ in
let
inherit (config.swarselsystems) sopsFile;
- inherit (confLib.gen { name = "kavita"; port = 8080; }) servicePort serviceName serviceUser serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
+ inherit (confLib.gen { name = "kavita"; port = 8080; }) servicePort serviceName serviceUser serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6 isHome;
in
{
options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
@@ -11190,7 +11638,7 @@ in
globals.services.${serviceName} = {
domain = serviceDomain;
- inherit proxyAddress4 proxyAddress6;
+ inherit proxyAddress4 proxyAddress6 isHome;
};
services.${serviceName} = {
@@ -11238,7 +11686,7 @@ in
{ pkgs, lib, config, globals, dns, confLib, ... }:
let
- inherit (confLib.gen { name = "jellyfin"; port = 8096; }) servicePort serviceName serviceUser serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
+ inherit (confLib.gen { name = "jellyfin"; port = 8096; }) servicePort serviceName serviceUser serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6 isHome;
in
{
options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
@@ -11270,7 +11718,7 @@ in
globals.services.${serviceName} = {
domain = serviceDomain;
- inherit proxyAddress4 proxyAddress6;
+ inherit proxyAddress4 proxyAddress6 isHome;
};
services.${serviceName} = {
@@ -11317,7 +11765,7 @@ in
{ pkgs, config, lib, globals, dns, confLib, ... }:
let
- inherit (confLib.gen { name = "navidrome"; port = 4040; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
+ inherit (confLib.gen { name = "navidrome"; port = 4040; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6 isHome;
in
{
options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
@@ -11358,7 +11806,7 @@ in
globals.services.${serviceName} = {
domain = serviceDomain;
- inherit proxyAddress4 proxyAddress6;
+ inherit proxyAddress4 proxyAddress6 isHome;
};
services.snapserver = {
@@ -11673,7 +12121,7 @@ in
{ lib, config, pkgs, globals, dns, confLib, ... }:
let
inherit (config.swarselsystems) sopsFile;
- inherit (confLib.gen { name = "matrix"; user = "matrix-synapse"; port = 8008; }) servicePort serviceName serviceUser serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
+ inherit (confLib.gen { name = "matrix"; user = "matrix-synapse"; port = 8008; }) servicePort serviceName serviceUser serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6 isHome;
federationPort = 8448;
whatsappPort = 29318;
@@ -11765,7 +12213,7 @@ in
globals.services.${serviceName} = {
domain = serviceDomain;
- inherit proxyAddress4 proxyAddress6;
+ inherit proxyAddress4 proxyAddress6 isHome;
};
services = {
@@ -12034,7 +12482,7 @@ in
let
inherit (config.repo.secrets.local.nextcloud) adminuser;
inherit (config.swarselsystems) sopsFile;
- inherit (confLib.gen { name = "nextcloud"; port = 80; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
+ inherit (confLib.gen { name = "nextcloud"; port = 80; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6 isHome;
nextcloudVersion = "32";
in
@@ -12053,7 +12501,7 @@ in
globals.services.${serviceName} = {
domain = serviceDomain;
- inherit proxyAddress4 proxyAddress6;
+ inherit proxyAddress4 proxyAddress6 isHome;
};
services = {
@@ -12119,7 +12567,7 @@ in
{ lib, pkgs, config, globals, dns, confLib, ... }:
let
- inherit (confLib.gen { name = "immich"; port = 3001; }) servicePort serviceName serviceUser serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
+ inherit (confLib.gen { name = "immich"; port = 3001; }) servicePort serviceName serviceUser serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6 isHome;
in
{
options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
@@ -12137,7 +12585,7 @@ in
globals.services.${serviceName} = {
domain = serviceDomain;
- inherit proxyAddress4 proxyAddress6;
+ inherit proxyAddress4 proxyAddress6 isHome;
};
services.${serviceName} = {
@@ -12211,7 +12659,7 @@ Also I install Tika and Gotenberg, which are needed to create PDFs out of
{ lib, pkgs, config, dns, globals, confLib, ... }:
let
inherit (config.swarselsystems) sopsFile;
- inherit (confLib.gen { name = "paperless"; port = 28981; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
+ inherit (confLib.gen { name = "paperless"; port = 28981; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6 isHome;
tikaPort = 9998;
gotenbergPort = 3002;
@@ -12238,7 +12686,7 @@ in
globals.services.${serviceName} = {
domain = serviceDomain;
- inherit proxyAddress4 proxyAddress6;
+ inherit proxyAddress4 proxyAddress6 isHome;
};
services = {
@@ -12351,7 +12799,7 @@ in
{ self, pkgs, lib, config, confLib, ... }:
let
- inherit (confLib.gen { name = "transmission"; }) serviceName serviceDomain;
+ inherit (confLib.gen { name = "transmission"; }) serviceName serviceDomain isHome;
lidarrUser = "lidarr";
lidarrGroup = lidarrUser;
@@ -12437,7 +12885,10 @@ in
prowlarr.info = "https://${serviceDomain}/prowlarr";
};
- globals.services.transmission.domain = serviceDomain;
+ globals.services.transmission = {
+ domain = serviceDomain;
+ inherit isHome;
+ };
services = {
radarr = {
@@ -12540,7 +12991,7 @@ in
{ lib, config, globals, dns, confLib, ... }:
let
inherit (config.swarselsystems.syncthing) serviceDomain;
- inherit (confLib.gen { name = "syncthing"; port = 8384; }) servicePort serviceName serviceUser serviceGroup serviceAddress serviceProxy proxyAddress4 proxyAddress6;
+ inherit (confLib.gen { name = "syncthing"; port = 8384; }) servicePort serviceName serviceUser serviceGroup serviceAddress serviceProxy proxyAddress4 proxyAddress6 isHome;
specificServiceName = "${serviceName}-${config.node.name}";
@@ -12597,7 +13048,7 @@ in
globals.services.${specificServiceName} = {
domain = serviceDomain;
- inherit proxyAddress4 proxyAddress6;
+ inherit proxyAddress4 proxyAddress6 isHome;
};
services.${serviceName} = rec {
@@ -12769,7 +13220,7 @@ This section exposes several metrics that I use to check the health of my server
{ lib, config, globals, dns, confLib, ... }:
let
- inherit (confLib.gen { name = "grafana"; port = 3000; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
+ inherit (confLib.gen { name = "grafana"; port = 3000; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6 isHome;
prometheusPort = 9090;
prometheusUser = "prometheus";
@@ -12831,7 +13282,7 @@ in
globals.services.${serviceName} = {
domain = serviceDomain;
- inherit proxyAddress4 proxyAddress6;
+ inherit proxyAddress4 proxyAddress6 isHome;
};
services = {
@@ -13034,7 +13485,7 @@ This is a WIP Jenkins instance. It is used to automatically build a new system w
{ pkgs, lib, config, globals, dns, confLib, ... }:
let
- inherit (confLib.gen { name = "jenkins"; port = 8088; }) servicePort serviceName serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
+ inherit (confLib.gen { name = "jenkins"; port = 8088; }) servicePort serviceName serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6 isHome;
in
{
options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
@@ -13046,7 +13497,7 @@ in
globals.services.${serviceName} = {
domain = serviceDomain;
- inherit proxyAddress4 proxyAddress6;
+ inherit proxyAddress4 proxyAddress6 isHome;
};
services.jenkins = {
@@ -13143,7 +13594,7 @@ FreshRSS claims to support HTTP header auth, but at least it does not work with
{ self, lib, config, globals, dns, confLib, ... }:
let
- inherit (confLib.gen { name = "freshrss"; port = 80; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
+ inherit (confLib.gen { name = "freshrss"; port = 80; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6 isHome;
inherit (config.swarselsystems) sopsFile;
in
@@ -13198,7 +13649,7 @@ in
globals.services.${serviceName} = {
domain = serviceDomain;
- inherit proxyAddress4 proxyAddress6;
+ inherit proxyAddress4 proxyAddress6 isHome;
};
services.${serviceName} =
@@ -13261,7 +13712,7 @@ in
{ lib, config, pkgs, globals, dns, confLib, ... }:
let
inherit (config.swarselsystems) sopsFile;
- inherit (confLib.gen { name = "forgejo"; port = 3004; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
+ inherit (confLib.gen { name = "forgejo"; port = 3004; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6 isHome;
kanidmDomain = globals.services.kanidm.domain;
in
@@ -13288,7 +13739,7 @@ in
globals.services.${serviceName} = {
domain = serviceDomain;
- inherit proxyAddress4 proxyAddress6;
+ inherit proxyAddress4 proxyAddress6 isHome;
};
services.${serviceName} = {
@@ -13429,7 +13880,7 @@ in
{ self, lib, config, globals, dns, confLib, ... }:
let
inherit (config.swarselsystems) sopsFile;
- inherit (confLib.gen { name = "ankisync"; port = 27701; }) servicePort serviceName serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
+ inherit (confLib.gen { name = "ankisync"; port = 27701; }) servicePort serviceName serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6 isHome;
ankiUser = globals.user.name;
in
@@ -13453,7 +13904,7 @@ in
globals.services.${serviceName} = {
domain = serviceDomain;
- inherit proxyAddress4 proxyAddress6;
+ inherit proxyAddress4 proxyAddress6 isHome;
};
services.anki-sync-server = {
@@ -13534,7 +13985,7 @@ kanidm person credential create-reset-token <user>
let
certsSopsFile = self + /secrets/repo/certs.yaml;
inherit (config.swarselsystems) sopsFile;
- inherit (confLib.gen { name = "kanidm"; port = 8300; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
+ inherit (confLib.gen { name = "kanidm"; port = 8300; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6 isHome;
oauth2ProxyDomain = globals.services.oauth2-proxy.domain;
immichDomain = globals.services.immich.domain;
@@ -13594,8 +14045,9 @@ in
globals.services.${serviceName} = {
domain = serviceDomain;
- inherit proxyAddress4 proxyAddress6;
+ inherit proxyAddress4 proxyAddress6 isHome;
};
+ globals.general.idmServer = config.node.name;
environment.persistence."/persist" = lib.mkIf config.swarselsystems.isImpermanence {
files = [
@@ -13949,7 +14401,7 @@ in
{ lib, config, globals, dns, confLib, ... }:
let
- inherit (confLib.gen { name = "oauth2-proxy"; port = 3004; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
+ inherit (confLib.gen { name = "oauth2-proxy"; port = 3004; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6 isHome;
kanidmDomain = globals.services.kanidm.domain;
mainDomain = globals.domains.main;
@@ -14095,7 +14547,7 @@ in
globals.services.${serviceName} = {
domain = serviceDomain;
- inherit proxyAddress4 proxyAddress6;
+ inherit proxyAddress4 proxyAddress6 isHome;
};
services = {
@@ -14185,7 +14637,7 @@ in
{ self, lib, config, globals, dns, confLib, ... }:
let
- inherit (confLib.gen { name = "firefly-iii"; port = 80; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
+ inherit (confLib.gen { name = "firefly-iii"; port = 80; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6 isHome;
nginxGroup = "nginx";
@@ -14223,7 +14675,7 @@ in
globals.services.${serviceName} = {
domain = serviceDomain;
- inherit proxyAddress4 proxyAddress6;
+ inherit proxyAddress4 proxyAddress6 isHome;
};
services = {
@@ -14309,7 +14761,7 @@ in
{ self, lib, config, globals, dns, confLib, ... }:
let
- inherit (confLib.gen { name = "koillection"; port = 2282; dir = "/Vault/data/koillection"; }) servicePort serviceName serviceUser serviceDir serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
+ inherit (confLib.gen { name = "koillection"; port = 2282; dir = "/Vault/data/koillection"; }) servicePort serviceName serviceUser serviceDir serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6 isHome;
serviceDB = "koillection";
postgresUser = config.systemd.services.postgresql.serviceConfig.User; # postgres
@@ -14339,7 +14791,7 @@ in
globals.services.${serviceName} = {
domain = serviceDomain;
- inherit proxyAddress4 proxyAddress6;
+ inherit proxyAddress4 proxyAddress6 isHome;
};
virtualisation.oci-containers.containers = {
@@ -14455,7 +14907,7 @@ in
{ lib, config, globals, dns, confLib, ... }:
let
- inherit (confLib.gen { name = "atuin"; port = 8888; }) servicePort serviceName serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
+ inherit (confLib.gen { name = "atuin"; port = 8888; }) servicePort serviceName serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6 isHome;
in
{
options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
@@ -14469,7 +14921,7 @@ in
globals.services.${serviceName} = {
domain = serviceDomain;
- inherit proxyAddress4 proxyAddress6;
+ inherit proxyAddress4 proxyAddress6 isHome;
};
services.${serviceName} = {
@@ -14519,7 +14971,7 @@ in
{ lib, config, globals, dns, confLib, ... }:
let
- inherit (confLib.gen { name = "radicale"; port = 8000; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
+ inherit (confLib.gen { name = "radicale"; port = 8000; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6 isHome;
# sopsFile = config.node.secretsDir + "/secrets2.yaml";
inherit (config.swarselsystems) sopsFile;
@@ -14556,7 +15008,7 @@ in
globals.services.${serviceName} = {
domain = serviceDomain;
- inherit proxyAddress4 proxyAddress6;
+ inherit proxyAddress4 proxyAddress6 isHome;
};
services.${serviceName} = {
@@ -14650,7 +15102,7 @@ in
{ self, lib, config, pkgs, dns, globals, confLib, ... }:
let
- inherit (confLib.gen { name = "croc"; proxy = config.node.name; }) serviceName serviceDomain proxyAddress4 proxyAddress6;
+ inherit (confLib.gen { name = "croc"; proxy = config.node.name; }) serviceName serviceDomain proxyAddress4 proxyAddress6 isHome;
servicePorts = [
9009
9010
@@ -14694,7 +15146,7 @@ in
globals.services.${serviceName} = {
domain = serviceDomain;
- inherit proxyAddress4 proxyAddress6;
+ inherit proxyAddress4 proxyAddress6 isHome;
};
services.${serviceName} = {
@@ -14732,7 +15184,7 @@ in
{ self, lib, config, dns, globals, confLib, ... }:
let
- inherit (confLib.gen { name = "microbin"; port = 8777; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
+ inherit (confLib.gen { name = "microbin"; port = 8777; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6 isHome;
inherit (config.swarselsystems) sopsFile;
@@ -14784,7 +15236,7 @@ in
globals.services.${serviceName} = {
domain = serviceDomain;
- inherit proxyAddress4 proxyAddress6;
+ inherit proxyAddress4 proxyAddress6 isHome;
};
services.${serviceName} = {
@@ -14876,7 +15328,7 @@ in
{ self, lib, config, dns, globals, confLib, ... }:
let
- inherit (confLib.gen { name = "shlink"; port = 8081; dir = "/var/lib/shlink";}) servicePort serviceName serviceDomain serviceDir serviceAddress serviceProxy proxyAddress4 proxyAddress6;
+ inherit (confLib.gen { name = "shlink"; port = 8081; dir = "/var/lib/shlink";}) servicePort serviceName serviceDomain serviceDir serviceAddress serviceProxy proxyAddress4 proxyAddress6 isHome;
containerRev = "sha256:1a697baca56ab8821783e0ce53eb4fb22e51bb66749ec50581adc0cb6d031d7a";
@@ -14960,7 +15412,7 @@ in
globals.services.${serviceName} = {
domain = serviceDomain;
- inherit proxyAddress4 proxyAddress6;
+ inherit proxyAddress4 proxyAddress6 isHome;
};
nodes.${serviceProxy}.services.nginx = {
@@ -15005,7 +15457,7 @@ Deployment notes:
{ self, lib, config, dns, globals, confLib, ... }:
let
- inherit (confLib.gen { name = "slink"; port = 3000; dir = "/var/lib/slink";}) servicePort serviceName serviceDomain serviceDir serviceAddress serviceProxy proxyAddress4 proxyAddress6;
+ inherit (confLib.gen { name = "slink"; port = 3000; dir = "/var/lib/slink";}) servicePort serviceName serviceDomain serviceDir serviceAddress serviceProxy proxyAddress4 proxyAddress6 isHome;
containerRev = "sha256:98b9442696f0a8cbc92f0447f54fa4bad227af5dcfd6680545fedab2ed28ddd9";
in
@@ -15066,7 +15518,7 @@ in
globals.services.${serviceName} = {
domain = serviceDomain;
- inherit proxyAddress4 proxyAddress6;
+ inherit proxyAddress4 proxyAddress6 isHome;
};
nodes.${serviceProxy}.services.nginx = {
@@ -15110,7 +15562,7 @@ in
{ lib, config, globals, dns, confLib, ... }:
let
- inherit (confLib.gen { name = "snipeit"; port = 80; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
+ inherit (confLib.gen { name = "snipeit"; port = 80; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6 isHome;
# sopsFile = config.node.secretsDir + "/secrets2.yaml";
inherit (config.swarselsystems) sopsFile;
@@ -15136,7 +15588,7 @@ in
globals.services.${serviceName} = {
domain = serviceDomain;
- inherit proxyAddress4 proxyAddress6;
+ inherit proxyAddress4 proxyAddress6 isHome;
};
services.snipe-it = {
@@ -15193,7 +15645,7 @@ in
{ lib, pkgs, config, globals, dns, confLib, ... }:
let
- inherit (confLib.gen { name = "homebox"; port = 7745; }) servicePort serviceName serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
+ inherit (confLib.gen { name = "homebox"; port = 7745; }) servicePort serviceName serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6 isHome;
in
{
options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
@@ -15207,7 +15659,7 @@ in
globals.services.${serviceName} = {
domain = serviceDomain;
- inherit proxyAddress4 proxyAddress6;
+ inherit proxyAddress4 proxyAddress6 isHome;
};
services.${serviceName} = {
@@ -15335,7 +15787,7 @@ let
name = "garage";
port = 3900;
domain = config.repo.secrets.common.services.domains."garage-${config.node.name}";
- }) servicePort serviceName specificServiceName serviceDomain subDomain baseDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6;
+ }) servicePort serviceName specificServiceName serviceDomain subDomain baseDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6 isHome;
cfg = lib.recursiveUpdate config.services.${serviceName} config.swarselsystems.server.${serviceName};
inherit (config.swarselsystems) sopsFile mainUser;
@@ -15434,7 +15886,7 @@ in
globals.services.${specificServiceName} = {
domain = serviceDomain;
- inherit proxyAddress4 proxyAddress6;
+ inherit proxyAddress4 proxyAddress6 isHome;
};
@@ -15719,7 +16171,7 @@ let
in
{
options. swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
- config = lib.mkIf config.swarselmodules.server.${serviceName} {
+ config = lib.mkIf (config.swarselmodules.server.${serviceName} && config.swarselsystems.isCloud) {
nodes.stoicclub.swarselsystems.server.dns.${globals.domains.main}.subdomainRecords = {
"server.${config.node.name}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
@@ -15828,17 +16280,16 @@ in
-
-
-
3.2.3.52. nsd (dns) - site1
-
+
+
3.2.3.51.1. nsd (dns) - site1
+
{ config, globals, dns, proxyAddress4, proxyAddress6, ... }:
with dns.lib.combinators; {
SOA = {
nameServer = "soa";
adminEmail = "admin@${globals.domains.main}"; # this option is not parsed as domain (we cannot just write "admin")
- serial = 2025122204; # update this on changes for secondary dns
+ serial = 2025122401; # update this on changes for secondary dns
};
useOrigin = false;
@@ -15954,13 +16405,14 @@ with dns.lib.combinators; {
+
-
3.2.3.53. Minecraft
+
3.2.3.52. Minecraft
{ lib, config, pkgs, globals, dns, confLib, ... }:
let
- inherit (confLib.gen { name = "minecraft"; port = 25565; dir = "/opt/minecraft"; proxy = config.node.name; }) serviceName servicePort serviceDir serviceDomain proxyAddress4 proxyAddress6;
+ inherit (confLib.gen { name = "minecraft"; port = 25565; dir = "/opt/minecraft"; proxy = config.node.name; }) serviceName servicePort serviceDir serviceDomain proxyAddress4 proxyAddress6 isHome;
inherit (config.swarselsystems) mainUser;
worldName = "${mainUser}craft";
in
@@ -15976,7 +16428,7 @@ in
globals.services.${serviceName} = {
domain = serviceDomain;
- inherit proxyAddress4 proxyAddress6;
+ inherit proxyAddress4 proxyAddress6 isHome;
};
networking.firewall.allowedTCPPorts = [ servicePort ];
@@ -16013,14 +16465,18 @@ in
-
3.2.3.54. Mailserver
+
3.2.3.53. Mailserver
+
+When changing the hashed passwords, dovecot needs to be restarted manually, it will not happen upon rebuild.
+
+
{ lib, config, globals, dns, confLib, ... }:
let
inherit (config.swarselsystems) sopsFile;
- inherit (confLib.gen { name = "mailserver"; dir = "/var/lib/dovecot"; user = "virtualMail"; group = "virtualMail"; port = 443; }) serviceName serviceDir servicePort serviceUser serviceGroup serviceAddress serviceDomain serviceProxy proxyAddress4 proxyAddress6;
- inherit (config.repo.secrets.local.mailserver) user1 alias1_1 alias1_2 alias1_3 alias1_4 user2 alias2_1 alias2_2 user3;
+ inherit (confLib.gen { name = "mailserver"; dir = "/var/lib/dovecot"; user = "virtualMail"; group = "virtualMail"; port = 443; }) serviceName serviceDir servicePort serviceUser serviceGroup serviceAddress serviceDomain serviceProxy proxyAddress4 proxyAddress6 isHome;
+ inherit (config.repo.secrets.local.mailserver) user1 alias1_1 alias1_2 alias1_3 alias1_4 user2 alias2_1 alias2_2 alias2_3 user3;
baseDomain = globals.domains.main;
roundcubeDomain = config.repo.secrets.common.services.domains.roundcube;
@@ -16046,7 +16502,7 @@ in
};
roundcube = {
domain = roundcubeDomain;
- inherit proxyAddress4 proxyAddress6;
+ inherit proxyAddress4 proxyAddress6 isHome;
};
};
@@ -16078,6 +16534,9 @@ in
openFirewall = true;
certificateScheme = "acme";
dmarcReporting.enable = true;
+ enableSubmission = true;
+ enableSubmissionSsl = true;
+ enableImapSsl = true;
loginAccounts = {
"${user1}@${baseDomain}" = {
@@ -16094,6 +16553,7 @@ in
aliases = [
"${alias2_1}@${baseDomain}"
"${alias2_2}@${baseDomain}"
+ "${alias2_3}@${baseDomain}"
];
sendOnly = true;
};
@@ -16162,6 +16622,8 @@ in
proxyPass = "https://${serviceName}";
extraConfig = ''
client_max_body_size 0;
+ proxy_ssl_server_name on;
+ proxy_ssl_name ${roundcubeDomain};
'';
};
};
@@ -16176,7 +16638,7 @@ in
-
3.2.3.55. Attic (nix binary cache)
+
3.2.3.54. Attic (nix binary cache)
Generate the attic server token using openssl genrsa -traditional 4096 | base64 -w0
@@ -16195,7 +16657,7 @@ $ attic cache create hello
{ lib, config, pkgs, globals, dns, confLib, ... }:
let
- inherit (confLib.gen { name = "attic"; port = 8091; }) serviceName serviceDir servicePort serviceAddress serviceDomain serviceProxy proxyAddress4 proxyAddress6;
+ inherit (confLib.gen { name = "attic"; port = 8091; }) serviceName serviceDir servicePort serviceAddress serviceDomain serviceProxy proxyAddress4 proxyAddress6 isHome;
inherit (config.swarselsystems) mainUser isPublic sopsFile;
serviceDB = "atticd";
in
@@ -16211,7 +16673,7 @@ in
globals.services.${serviceName} = {
domain = serviceDomain;
- inherit proxyAddress4 proxyAddress6;
+ inherit proxyAddress4 proxyAddress6 isHome;
};
sops = lib.mkIf (!isPublic) {
@@ -16355,7 +16817,7 @@ in
-
3.2.3.56. Hydra
+
3.2.3.55. Hydra
Need to create user manually:
@@ -16370,7 +16832,7 @@ $ hydra-create-user alice –full-name 'Alice Q. User' \
{ inputs, lib, config, globals, dns, confLib, ... }:
let
- inherit (confLib.gen { name = "hydra"; port = 8002; }) serviceName servicePort serviceUser serviceGroup serviceAddress serviceDomain serviceProxy proxyAddress4 proxyAddress6;
+ inherit (confLib.gen { name = "hydra"; port = 8002; }) serviceName servicePort serviceUser serviceGroup serviceAddress serviceDomain serviceProxy proxyAddress4 proxyAddress6 isHome;
inherit (config.swarselsystems) sopsFile;
in
{
@@ -16385,7 +16847,7 @@ in
globals.services.${serviceName} = {
domain = serviceDomain;
- inherit proxyAddress4 proxyAddress6;
+ inherit proxyAddress4 proxyAddress6 isHome;
};
sops = {
@@ -16505,6 +16967,487 @@ in
+
+
3.2.3.56. Kea DHCP
+
+
+This is the dhcp config that runs on my router.
+
+
+
+
{ lib, config, globals, confLib, ... }:
+let
+ inherit (confLib.gen { name = "kea"; dir = "/var/lib/private/kea"; }) serviceName serviceDir;
+in
+ {
+ options = {
+ swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
+ };
+ config = lib.mkIf config.swarselmodules.server.${serviceName} {
+
+ environment.persistence."/persist".directories = lib.mkIf config.swarselsystems.isImpermanence [
+ { directory = serviceDir; mode = "0700"; }
+ ];
+
+ services.kea.dhcp4 = {
+ enable = true;
+ settings = {
+ lease-database = {
+ name = "/var/lib/kea/dhcp4.leases";
+ persist = true;
+ type = "memfile";
+ };
+ valid-lifetime = 86400;
+ renew-timer = 3600;
+ interfaces-config = {
+ # XXX: BUG: why does this bind other macvtaps?
+ interfaces = map (name: "me-${name}") (builtins.attrNames globals.networks.home-lan.vlans);
+ service-sockets-max-retries = -1;
+ };
+ subnet4 = lib.flip lib.mapAttrsToList globals.networks.home-lan.vlans (
+ vlanName: vlanCfg: {
+ inherit (vlanCfg) id;
+ interface = "me-${vlanName}";
+ subnet = vlanCfg.cidrv4;
+ pools = [
+ {
+ pool = "${lib.net.cidr.host 20 vlanCfg.cidrv4} - ${lib.net.cidr.host (-6) vlanCfg.cidrv4}";
+ }
+ ];
+ option-data =
+ [
+ {
+ name = "routers";
+ data = vlanCfg.hosts.hintbooth.ipv4; # FIXME: how to advertise v6 address also?
+ }
+ ];
+ # Advertise DNS server for VLANS that have internet access
+ # ++
+ # lib.optional
+ # (lib.elem vlanName [
+ # "services"
+ # "home"
+ # "devices"
+ # "guests"
+ # ])
+ # {
+ # name = "domain-name-servers";
+ # data = globals.networks.home-lan.vlans.services.hosts.hintbooth-adguardhome.ipv4;
+ # };
+ reservations = lib.concatLists (
+ lib.forEach (builtins.attrValues vlanCfg.hosts) (
+ hostCfg:
+ lib.optional (hostCfg.mac != null) {
+ hw-address = hostCfg.mac;
+ ip-address = hostCfg.ipv4;
+ }
+ )
+ );
+ }
+ );
+ };
+ };
+
+
+ };
+ }
+
+
+
+
+
+
3.2.3.57. nftables (firewall)
+
+
+This is the dhcp config that runs on my router.
+
+
+
+
{ lib, config, confLib, ... }:
+let
+ inherit (confLib.gen { name = "nftables"; }) serviceName;
+in
+{
+ options = {
+ swarselmodules.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
+ };
+ config = lib.mkIf config.swarselmodules.${serviceName} {
+
+ networking.nftables = {
+ stopRuleset = lib.mkDefault ''
+ table inet filter {
+ chain input {
+ type filter hook input priority filter; policy drop;
+ ct state invalid drop
+ ct state {established, related} accept
+
+ iifname lo accept
+ meta l4proto ipv6-icmp accept
+ meta l4proto icmp accept
+ ip protocol igmp accept
+ tcp dport ${toString (lib.head config.services.openssh.ports)} accept
+ }
+ chain forward {
+ type filter hook forward priority filter; policy drop;
+ }
+ chain output {
+ type filter hook output priority filter; policy accept;
+ }
+ }
+ '';
+
+ firewall = {
+ enable = true;
+ localZoneName = "local";
+ snippets = {
+ nnf-common.enable = false;
+ nnf-conntrack.enable = true;
+ nnf-drop.enable = true;
+ nnf-loopback.enable = true;
+ nnf-ssh.enable = true;
+ };
+
+ rules.untrusted-to-local = {
+ from = [ "untrusted" ];
+ to = [ "local" ];
+
+ inherit (config.networking.firewall)
+ allowedTCPPorts
+ allowedTCPPortRanges
+ allowedUDPPorts
+ allowedUDPPortRanges
+ ;
+ };
+
+ rules.icmp-and-igmp = {
+ after = [
+ "ct"
+ "ssh"
+ ];
+ from = "all";
+ to = [ "local" ];
+ extraLines = [
+ "meta l4proto ipv6-icmp accept"
+ "meta l4proto icmp accept"
+ "ip protocol igmp accept"
+ ];
+ };
+ };
+ };
+
+ };
+}
+
+
+
+
+
+
3.2.3.58. Firezone
+
+
+This is the dhcp config that runs on my router.
+
+
+
+
{ lib, pkgs, config, globals, confLib, dns, nodes, ... }:
+let
+ inherit (confLib.gen { name = "firezone"; dir = "/var/lib/private/firezone"; }) serviceName serviceUser serviceGroup serviceDir serviceAddress serviceDomain proxyAddress4 proxyAddress6 isHome homeProxy webProxy idmServer dnsServer;
+ inherit (config.swarselsystems) sopsFile;
+
+ cfg = config.services.firezone.server;
+
+ homeServices = lib.attrNames (lib.filterAttrs (_: serviceCfg: serviceCfg.isHome) globals.services);
+ homeDomains = map (name: globals.services.${name}.domain) homeServices;
+ allow = group: resource: {
+ "${group}@${resource}" = {
+ inherit group resource;
+ description = "Allow ${group} access to ${resource}";
+ };
+ };
+in
+{
+ options = {
+ swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
+ };
+ config = lib.mkIf config.swarselmodules.server.${serviceName} {
+
+ nodes.${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
+ "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
+ };
+
+ globals.services.${serviceName} = {
+ domain = serviceDomain;
+ inherit proxyAddress4 proxyAddress6 isHome;
+ };
+
+ sops = {
+ secrets = {
+ kanidm-firezone-client = { inherit sopsFile; mode = "0400"; };
+ firezone-relay-token = { inherit sopsFile; mode = "0400"; };
+ firezone-smtp-password = { inherit sopsFile; mode = "0440"; };
+ firezone-adapter-config = { inherit sopsFile; mode = "0440"; };
+ };
+ };
+
+ environment.persistence."/persist".directories = lib.mkIf config.swarselsystems.isImpermanence [
+ { directory = serviceDir; mode = "0700"; }
+ ];
+
+ services.firezone = {
+ server = {
+ enable = true;
+ enableLocalDB = true;
+ settings = {
+ LOG_LEVEL = "debug";
+ # OUTBOUND_EMAIL_ADAPTER = "Elixir.Swoosh.Adapters.SMTP";
+ # OUTBOUND_EMAIL_FROM = config.repo.secrets.local.firezone.mail.from;
+ };
+ settingsSecret = {
+ # OUTBOUND_EMAIL_ADAPTER_OPTS = config.sops.secrets.firezone-adapter-config.path;
+ };
+
+ # smtp.configureManually = true;
+ smtp= {
+ inherit (config.repo.secrets.local.firezone.mail) from username;
+ host = globals.services.mailserver.domain;
+ port = 465;
+ implicitTls = true;
+ passwordFile = config.sops.secrets.firezone-smtp-password.path;
+ };
+
+ provision = {
+ enable = true;
+ accounts.main = {
+ name = "Home";
+ relayGroups.relays.name = "Relays";
+ gatewayGroups.home.name = "Home";
+ actors.admin = {
+ type = "account_admin_user";
+ name = "Admin";
+ email = "admin@${globals.domains.main}";
+ };
+
+ # auth.oidc =
+ # let
+ # client_id = "firezone";
+ # in
+ # {
+ # name = "Kanidm";
+ # adapter = "openid_connect";
+ # adapter_config = {
+ # scope = "openid email profile";
+ # response_type = "code";
+ # inherit client_id;
+ # discovery_document_uri = "https://${globals.services.kanidm.domain}/oauth2/openid/${client_id}/.well-known/openid-configuration";
+ # clientSecretFile = config.sops.secrets.kanidm-firezone-client.path;
+ # };
+ # };
+
+ resources =
+ lib.genAttrs homeDomains
+ (domain: {
+ type = "dns";
+ name = domain;
+ address = domain;
+ gatewayGroups = [ "home" ];
+ filters = [
+ { protocol = "icmp"; }
+ {
+ protocol = "tcp";
+ ports = [
+ 443
+ 80
+ ];
+ }
+ {
+ protocol = "udp";
+ ports = [ 443 ];
+ }
+ ];
+ })
+ // {
+ "home.vlan-services.v4" = {
+ type = "cidr";
+ name = "home.vlan-services.v4";
+ address = globals.networks.home-lan.vlans.services.cidrv4;
+ gatewayGroups = [ "home" ];
+ };
+ "home.vlan-services.v6" = {
+ type = "cidr";
+ name = "home.vlan-services.v6";
+ address = globals.networks.home-lan.vlans.services.cidrv6;
+ gatewayGroups = [ "home" ];
+ };
+ };
+
+ policies =
+ { }
+ // allow "everyone" "home.vlan-services.v4"
+ // allow "everyone" "home.vlan-services.v6"
+ // lib.mergeAttrsList (map (domain: allow "everyone" domain) homeDomains);
+ };
+ };
+
+ domain = {
+ settings.ERLANG_DISTRIBUTION_PORT = 9003;
+ package = pkgs.dev.firezone-server-domain;
+ };
+ api = {
+ externalUrl = "https://${serviceDomain}/api/";
+ port = 8081;
+ package = pkgs.dev.firezone-server-api;
+ };
+ web = {
+ externalUrl = "https://${serviceDomain}/";
+ port = 8080;
+ package = pkgs.dev.firezone-server-web;
+ };
+ };
+
+ # relay = {
+ # enable = true;
+ # port = 3478;
+ # inherit (config.node) name;
+ # apiUrl = "wss://${serviceDomain}/api/";
+ # tokenFile = config.sops.secrets.firezone-relay-token.path;
+ # publicIpv4 = proxyAddress4;
+ # publicIpv6 = proxyAddress6;
+ # openFirewall = true;
+ # package = pkgs.dev.firezone-relay;
+ # };
+ };
+ systemd.services.firezone-initialize =
+ let
+ generateSecrets =
+ let
+ requiredSecrets = lib.filterAttrs (_: v: v == null) cfg.settingsSecret;
+ in
+ ''
+ mkdir -p secrets
+ chmod 700 secrets
+ ''
+ + lib.concatLines (
+ lib.forEach (builtins.attrNames requiredSecrets) (secret: ''
+ if [[ ! -e secrets/${secret} ]]; then
+ echo "Generating ${secret}"
+ # Some secrets like TOKENS_KEY_BASE require a value >=64 bytes.
+ head -c 64 /dev/urandom | base64 -w 0 > secrets/${secret}
+ chmod 600 secrets/${secret}
+ fi
+ '')
+ );
+ loadSecretEnvironment =
+ component:
+ let
+ relevantSecrets = lib.subtractLists (builtins.attrNames cfg.${component}.settings) (
+ builtins.attrNames cfg.settingsSecret
+ );
+ in
+ lib.concatLines (
+ lib.forEach relevantSecrets (
+ secret:
+ ''export ${secret}=$(< ${
+ if cfg.settingsSecret.${secret} == null then
+ "secrets/${secret}"
+ else
+ "\"$CREDENTIALS_DIRECTORY/${secret}\""
+ })''
+ )
+ );
+ in
+ {
+ script = lib.mkForce ''
+ mkdir -p "$TZDATA_DIR"
+
+ # Generate and load secrets
+ ${generateSecrets}
+ ${loadSecretEnvironment "domain"}
+
+ echo "Running migrations"
+ ${lib.getExe cfg.domain.package} eval "Domain.Release.migrate(manual: true)"
+ '';
+ };
+
+
+ nodes = {
+ ${homeProxy} =
+ let
+ nodeCfg = nodes.${homeProxy}.config;
+ in
+ {
+ sops.secrets.firezone-gateway-token = { inherit sopsFile; mode = "0400"; };
+ services.firezone.gateway = {
+ enable = true;
+ inherit (nodeCfg.node) name;
+ apiUrl = "wss://${globals.services.firezone.domain}/api/";
+ tokenFile = nodeCfg.sops.secrets.firezone-gateway-token.path;
+ package = pkgs.dev.firezone-gateway;
+ };
+ };
+ ${idmServer} =
+ let
+ nodeCfg = nodes.${idmServer}.config;
+ in
+ {
+ sops.secrets.kanidm-firezone = { inherit (nodeCfg.swarselsystems) sopsFile; owner = "kanidm"; group = "kanidm"; mode = "0440"; };
+ services.kanidm.provision = {
+ groups."firezone.access" = { };
+ systems.oauth2.firezone = {
+ displayName = "Firezone VPN";
+ # NOTE: state: both uuids are runtime values
+ originUrl = [
+ "https://${globals.services.firezone.domain}/50e16678-6e95-49e2-b59e-d70d0e658843/sign_in/providers/fc8afaa3-ce60-4073-9cae-81dec9453a2d/handle_callback"
+ "https://${globals.services.firezone.domain}/50e16678-6e95-49e2-b59e-d70d0e658843/settings/identity_providers/openid_connect/fc8afaa3-ce60-4073-9cae-81dec9453a2d/handle_callback"
+ ];
+ originLanding = "https://${globals.services.firezone.domain}/";
+ basicSecretFile = nodeCfg.sops.secrets.kanidm-firezone.path;
+ preferShortUsername = true;
+ scopeMaps."firezone.access" = [
+ "openid"
+ "email"
+ "profile"
+ ];
+ };
+
+ };
+ };
+ ${webProxy} = {
+ services.nginx = {
+ upstreams = {
+ ${serviceName} = {
+ servers."127.0.0.1:${toString config.services.firezone.server.web.port}" = { };
+ };
+ "${serviceName}-api" = {
+ servers."${serviceAddress}:${toString config.services.firezone.server.api.port}" = { };
+ };
+ };
+ virtualHosts = {
+ ${serviceDomain} = {
+ useACMEHost = globals.domains.main;
+ forceSSL = true;
+ acmeRoot = null;
+ locations."/" = {
+ # The trailing slash is important to strip the location prefix from the request
+ proxyPass = "http://${serviceName}/";
+ proxyWebsockets = true;
+ };
+ locations."/api/" = {
+ # The trailing slash is important to strip the location prefix from the request
+ proxyPass = "http://${serviceName}-api/";
+ proxyWebsockets = true;
+ };
+ };
+ };
+ };
+ };
+ };
+
+ };
+}
+
+
+
+
3.2.4. Darwin
@@ -16521,30 +17464,32 @@ This section sets up all the imports that are used in the home-manager section.
-
{ self, lib, config, outputs, globals, ... }:
+{ self, lib, config, outputs, globals, withHomeManager, ... }:
let
macUser = globals.user.work;
in
-{
+ {
imports = [
];
options.swarselmodules.optional.darwin = lib.mkEnableOption "optional darwin settings";
- config = lib.mkIf config.swarselmodules.optional.darwin {
- nix.settings.experimental-features = "nix-command flakes";
- nixpkgs = {
- hostPlatform = "x86_64-darwin";
- overlays = [ outputs.overlays.default ];
- config = {
- allowUnfree = true;
+ config = lib.mkIf config.swarselmodules.optional.darwin
+ {
+ nix.settings.experimental-features = "nix-command flakes";
+ nixpkgs = {
+ hostPlatform = "x86_64-darwin";
+ overlays = [ outputs.overlays.default ];
+ config = {
+ allowUnfree = true;
+ };
};
- };
+ system.stateVersion = 4;
+ } // lib.optionalAttrs withHomeManager {
home-manager.users."${macUser}".imports = [
"${self}/modules/home/darwin"
];
- system.stateVersion = 4;
};
}
@@ -16572,7 +17517,8 @@ TODO: evaluate whether I should keep using this structure.
-
{ lib, ... }:
+# @ future me: dont panic, this file is not read in by readNix
+{ lib, ... }:
let
importNames = lib.swarselsystems.readNix "modules/nixos/optional";
in
@@ -16634,16 +17580,10 @@ This opens a few gaming ports and installs the steam configuration suite for gam
-
{ self, pkgs, config, ... }:
+{ self, lib, pkgs, config, withHomeManager, ... }:
{
config = {
- home-manager.users."${config.swarselsystems.mainUser}" = {
- imports = [
- "${self}/modules/home/optional/gaming.nix"
- ];
- };
-
programs.steam = {
enable = true;
package = pkgs.steam;
@@ -16677,6 +17617,12 @@ This opens a few gaming ports and installs the steam configuration suite for gam
# ];
# };
# };
+ } // lib.optionalAttrs withHomeManager {
+ home-manager.users."${config.swarselsystems.mainUser}" = {
+ imports = [
+ "${self}/modules/home/optional/gaming.nix"
+ ];
+ };
};
}
@@ -16785,15 +17731,10 @@ This holds configuration that is specific to framework laptops.
-
{ self, config, ... }:
+{ self, lib, config, withHomeManager, ... }:
{
config = {
- home-manager.users."${config.swarselsystems.mainUser}" = {
- imports = [
- "${self}/modules/home/optional/framework.nix"
- ];
- };
services = {
fwupd = {
@@ -16816,6 +17757,12 @@ This holds configuration that is specific to framework laptops.
defaultStrategy = "lazy";
};
};
+ } // lib.optionalAttrs withHomeManager {
+ home-manager.users."${config.swarselsystems.mainUser}" = {
+ imports = [
+ "${self}/modules/home/optional/framework.nix"
+ ];
+ };
};
}
@@ -16922,7 +17869,7 @@ When setting up a new machine:
- vpn gateway is found in `nixosConfig.repo.secrets.local.work.vpnGateway`
-
{ self, lib, pkgs, config, ... }:
+{ self, lib, pkgs, config, withHomeManager, ... }:
let
inherit (config.swarselsystems) mainUser homeDir;
iwd = config.networking.networkmanager.wifi.backend == "iwd";
@@ -16942,12 +17889,6 @@ in
};
config = {
- home-manager.users."${config.swarselsystems.mainUser}" = {
- imports = [
- "${self}/modules/home/optional/work.nix"
- ];
- };
-
sops =
let
secretNames = [
@@ -17122,7 +18063,7 @@ in
openssh = {
enable = true;
extraConfig = ''
- '';
+ '';
};
syncthing = {
@@ -17160,6 +18101,13 @@ in
# ];
# };
# };
+ } // lib.optionalAttrs withHomeManager {
+
+ home-manager.users."${config.swarselsystems.mainUser}" = {
+ imports = [
+ "${self}/modules/home/optional/work.nix"
+ ];
+ };
};
}
@@ -17171,9 +18119,9 @@ in
3.2.5.11. Uni
-
{ self, config, ... }:
+{ self, config, withHomeManager, ... }:
{
- config = {
+ config = {} // lib.optionalAttrs withHomeManager {
home-manager.users."${config.swarselsystems.mainUser}" = {
imports = [
@@ -17220,14 +18168,33 @@ Some standard options that should be set vor every microvm guest. We set the def
-
_:
+{ self, inputs, ... }:
{
- # imports = [
- # inputs.microvm.nixosModules.microvm
- # ];
+ imports = [
+ inputs.disko.nixosModules.disko
+ inputs.home-manager.nixosModules.home-manager
+ inputs.impermanence.nixosModules.impermanence
+ inputs.lanzaboote.nixosModules.lanzaboote
+ inputs.microvm.nixosModules.host
+ inputs.microvm.nixosModules.microvm
+ inputs.nix-index-database.nixosModules.nix-index
+ inputs.nix-minecraft.nixosModules.minecraft-servers
+ inputs.nix-topology.nixosModules.default
+ inputs.nswitch-rcm-nix.nixosModules.nswitch-rcm
+ inputs.simple-nixos-mailserver.nixosModules.default
+ inputs.sops.nixosModules.sops
+ inputs.stylix.nixosModules.stylix
+ inputs.swarsel-nix.nixosModules.default
+ inputs.nixos-nftables-firewall.nixosModules.default
- config =
- { };
+ (inputs.nixos-extra-modules + "/modules/interface-naming.nix")
+
+ "${self}/modules/shared/meta.nix"
+ ];
+
+ config = {
+ system.stateVersion = "23.05";
+ };
}
@@ -17297,10 +18264,151 @@ Some standard options that should be set vor every microvm guest. We set the def
-
-
3.2.5.15. nix-topology node config
+
+
3.2.5.15. systemd-networkd (vlans/microvms)
+This sets up the networking framework that is needed for a server that hosts microvms.
+
+
+
+The general idea is as follows:
+
+
+- A host has
n physical interfaces, which bind to the br bridge. Also bound to the bridge is the veth interfaces that the vlans are applied to. This makes it so that the macvlan interfaces still get an IP even if the physical interfaces have no carrier.
+- For each VLAN defined in globals we create a VLAN here - we also create a macvlan interface for the hosts which is bound to the respective VLAN interface; also binding to that VLAN interface are the macvtap devices that are being created by the microvm module.
+
+- normally, a guest using macvtap is not reachable by the host unless using a switch that supports hairpin-mode. However, consumers of the same VLAN can still communicate, which is realized using the macvlan interface.
+- even then, the kernel will only route requests when the underlying interface is up. In the case that no physical ports are used, this means that the bridge interface would effectively not work (even when administratively set to UP using
activationPolicy) - the aforementioned veth takes care of that problem.
+
+
+
+
+
{ lib, config, globals, ... }:
+{
+
+ systemd.network = {
+ wait-online.anyInterface = true;
+ netdevs = {
+ "10-veth" = {
+ netdevConfig = {
+ Kind = "veth";
+ Name = "veth-br";
+ };
+ peerConfig = {
+ Name = "veth-int";
+ };
+ };
+ "20-br" = {
+ netdevConfig = {
+ Kind = "bridge";
+ Name = "br";
+ };
+ };
+ } // lib.flip lib.concatMapAttrs globals.networks.home-lan.vlans (
+ vlanName: vlanCfg: {
+ "30-vlan-${vlanName}" = {
+ netdevConfig = {
+ Kind = "vlan";
+ Name = "vlan-${vlanName}";
+ };
+ vlanConfig.Id = vlanCfg.id;
+ };
+ "40-me-${vlanName}" = {
+ netdevConfig = {
+ Name = "me-${vlanName}";
+ Kind = "macvlan";
+ };
+ extraConfig = ''
+ [MACVLAN]
+ Mode=bridge
+ '';
+ };
+ }
+ );
+ networks = {
+ "40-br" = {
+ matchConfig.Name = "br";
+ bridgeConfig = { };
+ linkConfig = {
+ ActivationPolicy = "always-up";
+ RequiredForOnline = "no";
+ };
+ networkConfig = {
+ ConfigureWithoutCarrier = true;
+ LinkLocalAddressing = "no";
+ };
+ };
+ "15-veth-br" = {
+ matchConfig.Name = "veth-br";
+
+ linkConfig = {
+ RequiredForOnline = "no";
+ };
+
+ networkConfig = {
+ Bridge = "br";
+ };
+ };
+ "15-veth-int" = {
+ matchConfig.Name = "veth-int";
+
+ linkConfig = {
+ ActivationPolicy = "always-up";
+ RequiredForOnline = "no";
+ };
+
+ networkConfig = {
+ ConfigureWithoutCarrier = true;
+ LinkLocalAddressing = "no";
+ };
+
+ vlan = map (name: "vlan-${name}") (builtins.attrNames globals.networks.home-lan.vlans);
+ };
+ "90-macvtap-ignore" = {
+ matchConfig.Kind = "macvtap";
+ linkConfig.ActivationPolicy = "manual";
+ linkConfig.Unmanaged = "yes";
+ };
+ } // lib.flip lib.concatMapAttrs globals.networks.home-lan.vlans (
+ vlanName: vlanCfg: {
+ "30-vlan-${vlanName}" = {
+ matchConfig.Name = "vlan-${vlanName}";
+ networkConfig.LinkLocalAddressing = "no";
+ networkConfig.MACVLAN = "me-${vlanName}";
+ linkConfig.RequiredForOnline = "no";
+ };
+ "40-me-${vlanName}" = {
+ address = [
+ vlanCfg.hosts.${config.node.name}.cidrv4
+ vlanCfg.hosts.${config.node.name}.cidrv6
+ ];
+ matchConfig.Name = "me-${vlanName}";
+ networkConfig = {
+ IPv4Forwarding = "yes";
+ IPv6PrivacyExtensions = "yes";
+ IPv6SendRA = true;
+ IPv6AcceptRA = false;
+ };
+ ipv6Prefixes = [
+ { Prefix = vlanCfg.cidrv6; }
+ ];
+ linkConfig.RequiredForOnline = "routable";
+ };
+ }
+ );
+ };
+
+}
+
+
+
+
+
+
+
3.2.5.16. nix-topology node config
+
+
Hold standard options for nix-topology per config
@@ -17333,7 +18441,8 @@ The general structure here is the same as in the
-{ lib, ... }:
+ # @ future me: dont panic, this file is not read in by readNix
+{ lib, ... }:
let
importNames = lib.swarselsystems.readNix "modules/home";
in
@@ -17692,7 +18801,7 @@ This holds packages that I can use as provided, or with small modifications (as
nix-visualize
nix-init
nix-inspect
- nixpkgs-review
+ (nixpkgs-review.override { nix = config.nix.package; })
manix
# shellscripts
@@ -21725,8 +22834,8 @@ Sets up a systemd user service for anki that does not stall the shutdown process
-
-
3.3.2.32.13. TODO attic store push service
+
+
3.3.2.32.13. TODO attic store push service
Normally, I want to push all nix build artifacts to my main cache automatically, which is realized here. Note that authentication to the cache must be done manually once on client nodes. TODO: fix that
@@ -24261,9 +25370,9 @@ TODO: check which of these can be replaced but builtin functions.
type = lib.types.bool;
default = config.swarselsystems.isLaptop;
};
- withHomeManager = lib.mkOption {
+ isMicroVM = lib.mkOption {
type = lib.types.bool;
- default = true;
+ default = false;
};
isSwap = lib.mkOption {
type = lib.types.bool;
@@ -24609,6 +25718,11 @@ In short, the options defined here are passed to the modules systems using 3.4.4. Config Library (confLib)
-
{ config, lib, globals, nixosConfig ? null, ... }:
+{ self, config, lib, globals, inputs, outputs, minimal, nixosConfig ? null, ... }:
{
_module.args = {
confLib = rec {
@@ -24670,7 +25784,43 @@ In short, the options defined here are passed to the modules systems using 2cf03a3 refactor: package and module generation. That commit can be checked out in order to see a simpler version of achieving the same thing.
-
-
-
3.4.6. Packages (flake)
-
+
+
3.4.5.1. Packages (flake)
+
{ self, lib, pkgs, ... }:
let
@@ -24710,9 +25859,9 @@ mkPackages packageNames pkgs
-
-
3.4.6.1. pass-fuzzel
-
+
+
3.4.5.1.1. pass-fuzzel
+
This app allows me, in conjunction with my Yubikey, to quickly enter passwords when the need arises. Normal and TOTP passwords are supported, and they can either be printed directly or copied to the clipboard.
@@ -24784,9 +25933,9 @@ writeShellApplication {
-
-
3.4.6.2. quickpass
-
+
+
3.4.5.1.2. quickpass
+
shopt -s nullglob globstar
@@ -24815,9 +25964,9 @@ writeShellApplication {
-
-
3.4.6.3. cura5
-
+
+
3.4.5.1.3. cura5
+
The version of cura used to be quite outdated in nixpkgs. I am fetching a newer AppImage here and use that instead.
@@ -24858,9 +26007,9 @@ writeScriptBin "cura" ''
-
-
3.4.6.4. hm-specialisation
-
+
+
3.4.5.1.4. hm-specialisation
+
This script allows for quick git home-manager specialisation switching.
@@ -24884,9 +26033,9 @@ writeShellApplication {
-
-
3.4.6.5. cdw
-
+
+
3.4.5.1.5. cdw
+
This script allows for quick git worktree switching.
@@ -24908,9 +26057,9 @@ writeShellApplication {
-
-
3.4.6.6. cdb
-
+
+
3.4.5.1.6. cdb
+
This script allows for quick git branch switching.
@@ -24930,9 +26079,9 @@ writeShellApplication {
-
-
3.4.6.7. prstatus
-
+
+
3.4.5.1.7. prstatus
+
This script allows for quick checking of nixpkgs PR statuses.
@@ -24952,9 +26101,9 @@ writeShellApplication {
-
-
3.4.6.8. bak
-
+
+
3.4.5.1.8. bak
+
This script lets me quickly backup files by appending .bak to the filename.
@@ -24975,9 +26124,9 @@ writeShellApplication {
-
-
3.4.6.9. timer
-
+
+
3.4.5.1.9. timer
+
This app starts a configuratble timer and uses TTS to say something once the timer runs out.
@@ -24998,9 +26147,9 @@ writeShellApplication {
-
-
3.4.6.10. e
-
+
+
3.4.5.1.10. e
+
This is a shorthand for calling emacsclient mostly. Also, it hides the kittyterm scratchpad window that I sometimes use for calling a command quickly, in case it is on the screen. After emacs closes, the kittyterm window is then shown again if it was visible earlier.
@@ -25044,9 +26193,9 @@ writeShellApplication {
-
-
3.4.6.11. command-not-found
-
+
+
3.4.5.1.11. command-not-found
+
The normal command-not-found.sh uses the outdated nix-shell commands as suggestions. This version supplies me with the more modern nixpkgs#<name> version.
@@ -25090,9 +26239,9 @@ command_not_found_handler() {
-
-
3.4.6.12. swarselcheck
-
+
+
3.4.5.1.12. swarselcheck
+
This app checks for different apps that I keep around in the scratchpad for quick viewing and hiding (messengers and music players mostly) and then behaves like the kittyterm hider that I described in e.
@@ -25175,9 +26324,9 @@ writeShellApplication {
-
-
3.4.6.13. swarselcheck-niri
-
+
+
3.4.5.1.13. swarselcheck-niri
+
while :; do
case ${1:-} in
@@ -25230,9 +26379,9 @@ writeShellApplication {
-
-
3.4.6.14. swarselzellij
-
+
+
3.4.5.1.14. swarselzellij
+
# KITTIES=$(($(pgrep -P 1 kitty | wc -l) - 1))
@@ -25257,9 +26406,9 @@ writeShellApplication {
-
-
3.4.6.15. waybarupdate
-
+
+
3.4.5.1.15. waybarupdate
+
This scripts checks if there are uncommited changes in either my dotfile repo, my university repo, or my passfile repo. In that case a warning will be shown in waybar.
@@ -25304,9 +26453,9 @@ writeShellApplication {
-
-
3.4.6.16. opacitytoggle
-
+
+
3.4.5.1.16. opacitytoggle
+
This app quickly toggles between 5% and 0% transparency.
@@ -25331,9 +26480,9 @@ writeShellApplication {
-
-
3.4.6.17. fs-diff
-
+
+
3.4.5.1.17. fs-diff
+
This utility is used to compare the current state of the root directory with the blanket state that is stored in /root-blank (the snapshot that is restored on each reboot of an impermanence machine). Using this, I can find files that I will lose once I reboot - if there are important files in that list, I can then easily add them to the persist options.
@@ -25372,9 +26521,9 @@ writeShellApplication {
-
-
3.4.6.18. github-notifications
-
+
+
3.4.5.1.18. github-notifications
+
This utility checks if there are updated packages in nixpkgs-unstable. It does so by fully building the most recent configuration, which I do not love, but it has its merits once I am willing to switch to the newer version.
@@ -25398,9 +26547,9 @@ writeShellApplication {
-
-
3.4.6.19. kanshare
-
+
+
3.4.5.1.19. kanshare
+
This utility checks if there are updated packages in nixpkgs-unstable. It does so by fully building the most recent configuration, which I do not love, but it has its merits once I am willing to switch to the newer version.
@@ -25422,9 +26571,9 @@ writeShellApplication {
-
-
3.4.6.20. swarsel-bootstrap
-
+
+
3.4.5.1.20. swarsel-bootstrap
+
This program sets up a new NixOS host remotely. It also takes care of secret management on the new host.
@@ -25839,9 +26988,9 @@ writeShellApplication {
-
-
3.4.6.21. swarsel-rebuild
-
+
+
3.4.5.1.21. swarsel-rebuild
+
set -eo pipefail
@@ -25969,9 +27118,9 @@ writeShellApplication {
-
-
3.4.6.22. swarsel-install
-
+
+
3.4.5.1.22. swarsel-install
+
Autoformatting always puts the EOF with indentation, which makes shfmt check fail. When editing this block, unindent them manually.
@@ -26182,9 +27331,9 @@ writeShellApplication {
-
-
3.4.6.23. swarsel-postinstall
-
+
+
3.4.5.1.23. swarsel-postinstall
+
set -eo pipefail
@@ -26274,9 +27423,9 @@ writeShellApplication {
-
-
3.4.6.24. t2ts
-
+
+
3.4.5.1.24. t2ts
+
{ name, writeShellApplication, ... }:
@@ -26292,9 +27441,9 @@ writeShellApplication {
-
-
3.4.6.25. ts2t
-
+
+
3.4.5.1.25. ts2t
+
{ name, writeShellApplication, ... }:
@@ -26310,9 +27459,9 @@ writeShellApplication {
-
-
3.4.6.26. vershell
-
+
+
3.4.5.1.26. vershell
+
{ name, writeShellApplication, ... }:
@@ -26328,9 +27477,9 @@ writeShellApplication {
-
-
3.4.6.27. eontimer
-
+
+
3.4.5.1.27. eontimer
+
{ lib
, python3
@@ -26432,9 +27581,9 @@ python3.pkgs.buildPythonApplication rec {
-
-
3.4.6.28. project
-
+
+
3.4.5.1.28. project
+
set -euo pipefail
@@ -26456,9 +27605,9 @@ writeShellApplication {
-
-
3.4.6.29. fhs
-
+
+
3.4.5.1.29. fhs
+
{ name, pkgs, ... }:
let
@@ -26475,9 +27624,9 @@ pkgs.buildFHSEnv (base // {
-
-
3.4.6.30. swarsel-displaypower
-
+
+
3.4.5.1.30. swarsel-displaypower
+
A crude script to power on all displays that might be attached. Needed because sometimes displays do not awake from sleep.
@@ -26500,9 +27649,9 @@ writeShellApplication {
-
-
3.4.6.31. swarsel-mgba
-
+
+
3.4.5.1.31. swarsel-mgba
+
AppImage version of mgba in which the lua scripting works.
@@ -26534,9 +27683,9 @@ appimageTools.wrapType2 {
-
-
3.4.6.32. swarsel-deploy
-
+
+
3.4.5.1.32. swarsel-deploy
+
# heavily inspired from https://github.com/oddlama/nix-config/blob/d42cbde676001a7ad8a3cace156e050933a4dcc3/pkgs/deploy.nix
{ name, bc, nix-output-monitor, writeShellApplication, ... }:
@@ -26666,9 +27815,9 @@ writeShellApplication {
-
-
3.4.6.33. swarsel-build
-
+
+
3.4.5.1.33. swarsel-build
+
{ name, nix-output-monitor, writeShellApplication, ... }:
writeShellApplication {
@@ -26690,9 +27839,9 @@ writeShellApplication {
-
-
3.4.6.34. swarsel-instantiate
-
+
+
3.4.5.1.34. swarsel-instantiate
+
This is a convenience function that calls nix-instantiate with a number of flags that I need in order to evaluate nix expressions in org-src blocks.
@@ -26711,9 +27860,9 @@ writeShellApplication {
-
-
3.4.6.35. sshrm
-
+
+
3.4.5.1.35. sshrm
+
This programs simply runs ssh-keygen on the last host that I tried to ssh into. I need this frequently when working with cloud-init usually.
@@ -26744,9 +27893,9 @@ writeShellApplication {
-
-
3.4.6.36. endme
-
+
+
3.4.5.1.36. endme
+
Sometimes my DE crashes after putting it to suspend - to be precise, it happens when I put it into suspend when I have multiple screens plugged in. I have never taken the time to debug the issue, but instead just switch to a different TTY and then use this script to kill the hanging session.
@@ -26766,9 +27915,9 @@ writeShellApplication {
-
-
3.4.6.37. git-replace
-
+
+
3.4.5.1.37. git-replace
+
This script allows for quick git replace of a string.
@@ -26845,11 +27994,11 @@ writeShellApplication {
-
-
3.4.7. Packages (config)
-
+
+
3.4.5.2. Packages (config)
+
-
{ self, homeConfig, lib, pkgs, config, ... }:
+{ self, lib, pkgs, config, homeConfig, ... }:
let
mkPackages = names: pkgs: builtins.listToAttrs (map
(name: {
@@ -26863,9 +28012,9 @@ mkPackages packageNames pkgs
-
-
3.4.7.1. cdr
-
+
+
3.4.5.2.1. cdr
+
{ name, homeConfig, writeShellApplication, fzf, ... }:
@@ -26886,9 +28035,9 @@ writeShellApplication {
-
-
3.4.7.2. swarsel-gens
-
+
+
3.4.5.2.2. swarsel-gens
+
This script quickly lists all nix generatinos on the system
@@ -26909,9 +28058,9 @@ writeShellApplication {
-
-
3.4.7.3. swarsel-switch
-
+
+
3.4.5.2.3. swarsel-switch
+
This script quickly switches to another nix generation.
@@ -26934,6 +28083,7 @@ writeShellApplication {
+
3.5. Profiles
@@ -26995,6 +28145,7 @@ in
lowBattery = lib.mkDefault false;
network = lib.mkDefault true;
networkDevices = lib.mkDefault true;
+ nftables = lib.mkDefault true;
nix-ld = lib.mkDefault true;
nvd = lib.mkDefault true;
packages = lib.mkDefault true;
@@ -27058,6 +28209,7 @@ in
autologin = lib.mkDefault true;
boot = lib.mkDefault true;
btrfs = lib.mkDefault true;
+ nftables = lib.mkDefault true;
server = {
ssh = lib.mkDefault true;
@@ -27122,6 +28274,7 @@ in
lowBattery = lib.mkForce true;
lanzaboote = lib.mkForce true;
autologin = lib.mkForce true;
+ nftables = lib.mkDefault true;
};
};
@@ -27152,6 +28305,7 @@ in
btrfs = lib.mkDefault true;
sops = lib.mkDefault true;
boot = lib.mkDefault true;
+ nftables = lib.mkDefault true;
server = {
general = lib.mkDefault true;
network = lib.mkDefault true;
@@ -27159,18 +28313,55 @@ in
packages = lib.mkDefault true;
ssh = lib.mkDefault true;
attic-setup = lib.mkDefault true;
+ dns-hostrecord = lib.mkDefault true;
};
};
};
}
+
+
+
+
+
+
3.5.1.5. MicroVM
+
+
+
{ lib, config, ... }:
+{
+ options.swarselprofiles.microvm = lib.mkEnableOption "is this a server";
+ config = lib.mkIf config.swarselprofiles.microvm {
+ swarselsystems = {
+ isLinux = true;
+ isNixos = true;
+ };
+ swarselmodules = {
+ general = lib.mkDefault true;
+ pii = lib.mkDefault true;
+ xserver = lib.mkDefault true;
+ time = lib.mkDefault true;
+ users = lib.mkDefault true;
+ impermanence = lib.mkDefault true;
+ btrfs = lib.mkDefault true;
+ sops = lib.mkDefault true;
+ nftables = lib.mkDefault true;
+ server = {
+ general = lib.mkDefault true;
+ packages = lib.mkDefault true;
+ ssh = lib.mkDefault true;
+ };
+ };
+ };
+
+}
+
-
3.5.1.5. Router
+
3.5.1.6. Router
{ lib, config, ... }:
@@ -27178,10 +28369,12 @@ in
options.swarselprofiles.router = lib.mkEnableOption "enable the router profile";
config = lib.mkIf config.swarselprofiles.router {
swarselmodules = {
- server = {
- router = lib.mkDefault true;
- };
+ nftables = lib.mkDefault true;
+ server = {
+ router = lib.mkDefault true;
+ kea = lib.mkDefault true;
};
+ };
};
}
@@ -32170,12 +33363,347 @@ window#waybar.hidden {
padding: 0 3px;
}
+
+
+
+
+
+
6.5. Doc Page style.css
+
+
+This is the stylesheet used by waybar.
+
+
+
+
+html, body {
+ margin: 0;
+ padding: 0;
+ background-color: #1d252c;
+ color: #b7c5d3;
+ font-family: "Inter", "Fira Sans", system-ui, sans-serif;
+ line-height: 1.6;
+ overflow-x: hidden; /* prevent horizontal scroll from small overflows */
+}
+
+body {
+ display: flex;
+}
+
+#table-of-contents {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 280px;
+ height: 100vh;
+ overflow-y: auto;
+ padding: 1.2rem 1rem;
+ background-color: #232b32;
+ border-right: 1px solid #2f3b45;
+ font-size: 0.9rem;
+}
+
+#table-of-contents h2 {
+ display: none;
+}
+
+#text-table-of-contents ul {
+ list-style: none;
+ padding-left: 0;
+}
+
+#text-table-of-contents li {
+ margin: 0.2rem 0;
+ position: relative;
+}
+
+.toc-entry {
+ display: inline-flex;
+ align-items: center;
+}
+
+#text-table-of-contents a {
+ color: #b7c5d3;
+ text-decoration: none;
+}
+
+#text-table-of-contents a:hover {
+ color: #5ec4ff;
+}
+
+#text-table-of-contents ul ul {
+ padding-left: 1rem;
+ border-left: 1px solid #2f3b45;
+}
+
+#content {
+ margin-left: 300px;
+ margin-right: 320px;
+ padding: 2rem 3rem;
+ max-width: 1200px;
+ width: calc(100vw - 620px);
+ box-sizing: border-box;
+ transition: margin 0.3s ease, padding 0.3s ease, width 0.3s ease, max-width 0.3s ease;
+}
+
+#content.pinned-hidden {
+ margin-right: 0;
+ width: calc(100vw - 300px);
+}
+
+h1, h2, h3, h4, h5 {
+ color: #70e1e8;
+ font-weight: 500;
+ margin-top: 2.2rem;
+}
+
+h1 {
+ font-size: 2rem;
+}
+
+h2 {
+ font-size: 1.6rem;
+}
+
+h3 {
+ font-size: 1.3rem;
+}
+
+
+a {
+ color: #5ec4ff;
+}
+
+a:hover {
+ text-decoration: underline;
+}
+
+pre, code {
+ font-family: "Fira Code", monospace;
+ background-color: #232b32;
+ color: #b7c5d3;
+}
+
+pre {
+ padding: 1rem;
+ overflow-x: auto;
+ border: 1px solid #2f3b45;
+ border-radius: 4px;
+ max-width: 100%;
+ box-sizing: border-box;
+}
+
+code {
+ padding: 0.15rem 0.3rem;
+ border-radius: 3px;
+}
+
+table {
+ border-collapse: collapse;
+ max-width: 100%;
+}
+
+th, td {
+ border: 1px solid #2f3b45;
+ padding: 0.5rem 0.8rem;
+}
+
+th {
+ background-color: #232b32;
+ color: #70e1e8;
+}
+
+blockquote {
+ border-left: 3px solid #5ec4ff;
+ margin-left: 0;
+ padding-left: 1rem;
+ color: #718ca1;
+}
+
+#pinned-panel {
+ position: fixed;
+ top: 0;
+ right: 0;
+ width: 280px;
+ height: 100vh;
+ overflow-y: auto;
+ padding: 1.2rem 1rem;
+ padding-bottom: 5rem;
+ background-color: #232b32;
+ border-left: 1px solid #2f3b45;
+ font-size: 0.9rem;
+ box-sizing: border-box;
+ transition: transform 0.3s ease;
+}
+
+#pinned-panel.hidden {
+ transform: translateX(100%);
+}
+
+#pinned-panel-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 0.5rem;
+}
+
+#pinned-panel h2 {
+ margin: 0;
+ font-size: 1rem;
+ color: #70e1e8;
+ font-weight: 500;
+}
+
+#toggle-pinned-btn {
+ background: none;
+ border: none;
+ color: #718ca1;
+ cursor: pointer;
+ font-size: 1.2rem;
+ padding: 0;
+ line-height: 1;
+}
+
+#toggle-pinned-btn:hover {
+ color: #5ec4ff;
+}
+
+#pinned-list {
+ list-style: none;
+ padding-left: 0;
+}
+
+#pinned-list li {
+ margin: 0.5rem 0;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+#pinned-list a {
+ color: #b7c5d3;
+ text-decoration: none;
+ flex: 1;
+}
+
+#pinned-list a:hover {
+ color: #5ec4ff;
+}
+
+.pin-remove {
+ background: none;
+ border: none;
+ color: #718ca1;
+ cursor: pointer;
+ font-size: 0.9rem;
+ padding: 0 0.3rem;
+}
+
+.pin-remove:hover {
+ color: #ff6b6b;
+}
+
+.toc-pin-btn {
+ opacity: 0;
+ visibility: hidden;
+ transition: opacity 0.2s, visibility 0.2s;
+ cursor: pointer;
+ margin-left: 0.4rem;
+ font-size: 0.85rem;
+ color: #718ca1;
+ background: none;
+ border: none;
+ padding: 0;
+}
+
+.toc-pin-btn:hover {
+ color: #5ec4ff;
+}
+
+#text-table-of-contents .toc-entry:hover .toc-pin-btn {
+ opacity: 1;
+ visibility: visible;
+}
+
+#show-pinned-btn {
+ position: fixed;
+ top: 4.5rem;
+ right: 1rem;
+ background-color: #232b32;
+ border: 1px solid #2f3b45;
+ color: #b7c5d3;
+ cursor: pointer;
+ padding: 0.5rem 0.8rem;
+ font-size: 0.9rem;
+ border-radius: 4px;
+ display: none;
+ z-index: 1000;
+}
+
+#show-pinned-btn:hover {
+ background-color: #2f3b45;
+ color: #5ec4ff;
+}
+
+#show-pinned-btn.visible {
+ display: block;
+}
+
+@media (max-width: 1600px) {
+ #content {
+ max-width: 100%;
+ }
+}
+
+@media (max-width: 1300px) {
+ #pinned-panel {
+ display: none !important;
+ }
+
+ #show-pinned-btn {
+ display: none !important;
+ }
+
+ #content,
+ #content.pinned-hidden {
+ margin-right: 0;
+ width: calc(100vw - 300px);
+ max-width: 100%;
+ padding: 1.8rem 2.2rem;
+ }
+}
+
+@media (max-width: 1000px) {
+ #table-of-contents {
+ display: none;
+ }
+
+ #content {
+ margin-left: 0;
+ margin-right: 0;
+ width: 100vw;
+ max-width: 100%;
+ padding: 1.5rem 1.25rem;
+ }
+}
+
+@media (max-width: 700px) {
+ #content {
+ padding: 1.2rem 1rem;
+ }
+}
+
+.darkmode-layer, .darkmode-toggle {
+ z-index: 500;
+}
+
+
-
6.5. justfile
+
6.6. justfile
This file defines a few workflows that I often need to run when working on my configuration. This works similar to make, but is geared towards general tasks and as such requires no extra handling (as long as there are no dependencies involved) or .PHONY recipes.
@@ -32223,7 +33751,7 @@ bootstrap DEST CONFIG ARCH="x86_64-linux" NODISKODEPS="":
-
6.6. aspell.conf
+
6.7. aspell.conf
dict-dir /run/current-system/sw/lib/aspell
@@ -32232,7 +33760,7 @@ bootstrap DEST CONFIG ARCH="x86_64-linux" NODISKODEPS="":
-
6.7. nix-plugins.patch
+
6.8. nix-plugins.patch
diff --git a/extra-builtins.cc b/extra-builtins.cc
@@ -32261,7 +33789,7 @@ index 3a0f90e..bb10f8b 100644
-
6.8. Zellij layout swarsel.kdl.nix
+
6.9. Zellij layout swarsel.kdl.nix
{ config, pkgs }:
@@ -32429,7 +33957,7 @@ in
-
6.9. Zellij config.kdl.nix
+
6.10. Zellij config.kdl.nix
{ config }:
@@ -32779,7 +34307,7 @@ in
-
6.10. Vieb config
+
6.11. Vieb config
" Options
@@ -32984,7 +34512,7 @@ set searchwords+=hm~https://home-manager-options.extranix.com/?query=%s
-
6.11. swayidle
+
6.12. swayidle
timeout 300 'swaylock -f --screenshots --clock --effect-blur 7x5 --effect-vignette 0.5:0.5 --fade-in 0.2'
@@ -32995,7 +34523,7 @@ before-sleep 'swaylock -f --screenshots --clock --effect-blur 7x5 --effect-vigne
-
6.12. stylix color scheme
+
6.13. stylix color scheme
# scheme: "better-contrast"
@@ -33056,7 +34584,7 @@ base0F: "3c0044" #3c0044"
-
6.13. .gitmessage
+
6.14. .gitmessage
The double source block is intended here to circumvent a org-babel convenience where the first n empty lines of each source block are not taken into the final file. For the .gitmessage I want an empty newline to type into, so this is what I use to achieve that.
@@ -33082,7 +34610,7 @@ The double source block is intended here to circumvent a org-babel convenience w
-
6.14. userChrome.css
+
6.15. userChrome.css
/* Source file https://github.com/MrOtherGuy/firefox-csshacks/tree/master/chrome/autohide_toolbox.css made available under Mozilla Public License v. 2.0
@@ -33211,7 +34739,7 @@ See the above repository for updates as well as full license text. */
-
6.15. Default Flake Template
+
6.16. Default Flake Template
{
@@ -33249,7 +34777,7 @@ See the above repository for updates as well as full license text. */
-
6.16. C++ Flake Template
+
6.17. C++ Flake Template
# heavily inspired by https://github.com/nulladmin1/nix-flake-templates/blob/main/cpp-cmake/flake.nix
@@ -33319,7 +34847,7 @@ See the above repository for updates as well as full license text. */
-
6.17. Go Flake Template
+
6.18. Go Flake Template
# heavily inspired by https://github.com/nulladmin1/nix-flake-templates/blob/main/go-nix/flake.nix
@@ -33379,7 +34907,7 @@ See the above repository for updates as well as full license text. */
-
6.18. LaTeX Flake Template
+
6.19. LaTeX Flake Template
# This template is based on https://github.com/Leixb/latex-template/tree/master
@@ -33465,7 +34993,7 @@ See the above repository for updates as well as full license text. */
-
6.19. Python Flake Template
+
6.20. Python Flake Template
# based on https://github.com/pyproject-nix/uv2nix/tree/master/templates/hello-world
@@ -33672,7 +35200,7 @@ See the above repository for updates as well as full license text. */
-
6.20. Rust Flake Template
+
6.21. Rust Flake Template
# heavily inspired by https://github.com/nulladmin1/nix-flake-templates/blob/main/rust-fenix-naersk/flake.nix
@@ -33750,7 +35278,7 @@ See the above repository for updates as well as full license text. */
-
6.21. GitHub Readme
+
6.22. GitHub Readme
Here lies defined the readme for GitHub and Forgejo:
@@ -34092,8 +35620,8 @@ Here lies defined the readme for GitHub and Forgejo:
This sections explains commonly used functions in nix (both builtins as well as in the nixpkgs library).
-
-
7.1. Concepts
+
+
7.1. Concepts
@@ -34133,8 +35661,8 @@ It only took the latter b set, even though the b2 valu
-
-
7.2. Builtin functions
+
+
7.2. Builtin functions
The following functions are only base functionality of nix, and not exported to nixpkgs. When using them we need to make sure that the nix version in use is matching the expected function.
@@ -34158,8 +35686,8 @@ The following functions are only base functionality of nix, and not exported to
-
-
7.3. Builtin functions exported to nixpkgs
+
+
7.3. Builtin functions exported to nixpkgs
These functions exist in nix, but are exported to nixpkgs to make sure they use a nix version that works in the used nixpgks. Most of the times I should prefer to use the nixpkgs version of these.
@@ -34467,8 +35995,8 @@ abo
-
-
7.4. Functions in nixpgks
+
+
7.4. Functions in nixpgks
These functions only exist in nixpkgs and cannot be used in generic nix code.
@@ -34668,16 +36196,8 @@ Note that the string cannot be preceded by 0 - lib.toInt "01" would
-
-
7.4.11. nixpkgs.lib.mkOption
-
-
-
Author: Leon Schwarzäugl
-
Created: 2025-12-23 Di 03:19
-
Validate
-
diff --git a/style.css b/style.css
new file mode 100644
index 0000000..5f472f2
--- /dev/null
+++ b/style.css
@@ -0,0 +1,320 @@
+html, body {
+ margin: 0;
+ padding: 0;
+ background-color: #1d252c;
+ color: #b7c5d3;
+ font-family: "Inter", "Fira Sans", system-ui, sans-serif;
+ line-height: 1.6;
+ overflow-x: hidden; /* prevent horizontal scroll from small overflows */
+}
+
+body {
+ display: flex;
+}
+
+#table-of-contents {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 280px;
+ height: 100vh;
+ overflow-y: auto;
+ padding: 1.2rem 1rem;
+ background-color: #232b32;
+ border-right: 1px solid #2f3b45;
+ font-size: 0.9rem;
+}
+
+#table-of-contents h2 {
+ display: none;
+}
+
+#text-table-of-contents ul {
+ list-style: none;
+ padding-left: 0;
+}
+
+#text-table-of-contents li {
+ margin: 0.2rem 0;
+ position: relative;
+}
+
+.toc-entry {
+ display: inline-flex;
+ align-items: center;
+}
+
+#text-table-of-contents a {
+ color: #b7c5d3;
+ text-decoration: none;
+}
+
+#text-table-of-contents a:hover {
+ color: #5ec4ff;
+}
+
+#text-table-of-contents ul ul {
+ padding-left: 1rem;
+ border-left: 1px solid #2f3b45;
+}
+
+#content {
+ margin-left: 300px;
+ margin-right: 320px;
+ padding: 2rem 3rem;
+ max-width: 1200px;
+ width: calc(100vw - 620px);
+ box-sizing: border-box;
+ transition: margin 0.3s ease, padding 0.3s ease, width 0.3s ease, max-width 0.3s ease;
+}
+
+#content.pinned-hidden {
+ margin-right: 0;
+ width: calc(100vw - 300px);
+}
+
+h1, h2, h3, h4, h5 {
+ color: #70e1e8;
+ font-weight: 500;
+ margin-top: 2.2rem;
+}
+
+h1 {
+ font-size: 2rem;
+}
+
+h2 {
+ font-size: 1.6rem;
+}
+
+h3 {
+ font-size: 1.3rem;
+}
+
+
+a {
+ color: #5ec4ff;
+}
+
+a:hover {
+ text-decoration: underline;
+}
+
+pre, code {
+ font-family: "Fira Code", monospace;
+ background-color: #232b32;
+ color: #b7c5d3;
+}
+
+pre {
+ padding: 1rem;
+ overflow-x: auto;
+ border: 1px solid #2f3b45;
+ border-radius: 4px;
+ max-width: 100%;
+ box-sizing: border-box;
+}
+
+code {
+ padding: 0.15rem 0.3rem;
+ border-radius: 3px;
+}
+
+table {
+ border-collapse: collapse;
+ max-width: 100%;
+}
+
+th, td {
+ border: 1px solid #2f3b45;
+ padding: 0.5rem 0.8rem;
+}
+
+th {
+ background-color: #232b32;
+ color: #70e1e8;
+}
+
+blockquote {
+ border-left: 3px solid #5ec4ff;
+ margin-left: 0;
+ padding-left: 1rem;
+ color: #718ca1;
+}
+
+#pinned-panel {
+ position: fixed;
+ top: 0;
+ right: 0;
+ width: 280px;
+ height: 100vh;
+ overflow-y: auto;
+ padding: 1.2rem 1rem;
+ padding-bottom: 5rem;
+ background-color: #232b32;
+ border-left: 1px solid #2f3b45;
+ font-size: 0.9rem;
+ box-sizing: border-box;
+ transition: transform 0.3s ease;
+}
+
+#pinned-panel.hidden {
+ transform: translateX(100%);
+}
+
+#pinned-panel-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 0.5rem;
+}
+
+#pinned-panel h2 {
+ margin: 0;
+ font-size: 1rem;
+ color: #70e1e8;
+ font-weight: 500;
+}
+
+#toggle-pinned-btn {
+ background: none;
+ border: none;
+ color: #718ca1;
+ cursor: pointer;
+ font-size: 1.2rem;
+ padding: 0;
+ line-height: 1;
+}
+
+#toggle-pinned-btn:hover {
+ color: #5ec4ff;
+}
+
+#pinned-list {
+ list-style: none;
+ padding-left: 0;
+}
+
+#pinned-list li {
+ margin: 0.5rem 0;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+#pinned-list a {
+ color: #b7c5d3;
+ text-decoration: none;
+ flex: 1;
+}
+
+#pinned-list a:hover {
+ color: #5ec4ff;
+}
+
+.pin-remove {
+ background: none;
+ border: none;
+ color: #718ca1;
+ cursor: pointer;
+ font-size: 0.9rem;
+ padding: 0 0.3rem;
+}
+
+.pin-remove:hover {
+ color: #ff6b6b;
+}
+
+.toc-pin-btn {
+ opacity: 0;
+ visibility: hidden;
+ transition: opacity 0.2s, visibility 0.2s;
+ cursor: pointer;
+ margin-left: 0.4rem;
+ font-size: 0.85rem;
+ color: #718ca1;
+ background: none;
+ border: none;
+ padding: 0;
+}
+
+.toc-pin-btn:hover {
+ color: #5ec4ff;
+}
+
+#text-table-of-contents .toc-entry:hover .toc-pin-btn {
+ opacity: 1;
+ visibility: visible;
+}
+
+#show-pinned-btn {
+ position: fixed;
+ top: 4.5rem;
+ right: 1rem;
+ background-color: #232b32;
+ border: 1px solid #2f3b45;
+ color: #b7c5d3;
+ cursor: pointer;
+ padding: 0.5rem 0.8rem;
+ font-size: 0.9rem;
+ border-radius: 4px;
+ display: none;
+ z-index: 1000;
+}
+
+#show-pinned-btn:hover {
+ background-color: #2f3b45;
+ color: #5ec4ff;
+}
+
+#show-pinned-btn.visible {
+ display: block;
+}
+
+@media (max-width: 1600px) {
+ #content {
+ max-width: 100%;
+ }
+}
+
+@media (max-width: 1300px) {
+ #pinned-panel {
+ display: none !important;
+ }
+
+ #show-pinned-btn {
+ display: none !important;
+ }
+
+ #content,
+ #content.pinned-hidden {
+ margin-right: 0;
+ width: calc(100vw - 300px);
+ max-width: 100%;
+ padding: 1.8rem 2.2rem;
+ }
+}
+
+@media (max-width: 1000px) {
+ #table-of-contents {
+ display: none;
+ }
+
+ #content {
+ margin-left: 0;
+ margin-right: 0;
+ width: 100vw;
+ max-width: 100%;
+ padding: 1.5rem 1.25rem;
+ }
+}
+
+@media (max-width: 700px) {
+ #content {
+ padding: 1.2rem 1rem;
+ }
+}
+
+.darkmode-layer, .darkmode-toggle {
+ z-index: 500;
+}