diff --git a/hosts/dandelion/variables.nix b/hosts/dandelion/variables.nix new file mode 100644 index 0000000..241d088 --- /dev/null +++ b/hosts/dandelion/variables.nix @@ -0,0 +1,17 @@ +{ + lib, + config, + ... +}: let + inherit (lib) mkOption types; + inherit (config.liv) variables; +in { + options.liv.variables.dandelion = { + thisMachine = mkOption { + default = "dandelion.srv.${variables.primaryDomain}"; + type = types.str; + readOnly = true; + description = "Domain of this specific machine"; + }; + }; +} diff --git a/hosts/lily/default.nix b/hosts/lily/default.nix new file mode 100644 index 0000000..b6d57ce --- /dev/null +++ b/hosts/lily/default.nix @@ -0,0 +1,265 @@ +{ + lib, + pkgs, + config, + ... +}: +let + externalInterface = "wan0"; + # networks = config.homelab.networks.local; + # internalInterfaces = lib.mapAttrsToList (_: val: val.interface) networks; + # internalIPs = lib.mapAttrsToList ( + # _: val: lib.strings.removeSuffix ".1" val.cidr + ".0/24" + # ) networks; + commonDhcpOptions = [ + { + name = "domain-name-servers"; + data = "9.9.9.9"; + } + { + name = "time-servers"; + data = "172.16.1.1"; + } + { + name = "domain-name"; + data = "beeping.local"; + } + { + name = "domain-search"; + data = "beeping.local"; + } + ]; +in +{ + imports = [ + ./hardware-configuration.nix + ./variables.nix + ./dns.nix + ./wireguard.nix + ./../../modules/core/default.router.nix + ./../../modules/services/lily.nix + ]; + + liv = { + server.enable = true; + router.enable = true; + }; + + boot = { + loader.grub = { + enable = true; + device = "/dev/sda"; + useOSProber = true; + }; + kernel = { + sysctl = { + # Forward both IPv4 and IPv6 on all interfaces + "net.ipv4.conf.all.forwarding" = true; + "net.ipv6.conf.all.forwarding" = false; + + # By default, do not automatically configure any IPv6 addresses. + # "net.ipv6.conf.all.accept_ra" = 0; + # "net.ipv6.conf.all.autoconf" = 0; + # "net.ipv6.conf.all.use_tempaddr" = 0; + + # Allow IPv6 autoconfiguration and tempory address use on WAN. + "net.ipv6.conf.${externalInterface}.accept_ra" = 2; + "net.ipv6.conf.${externalInterface}.autoconf" = 1; + }; + }; + }; + + # label network interfaces + services.udev.extraRules = '' + SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="00:25:90:47:67:6e", ATTR{type}=="1", NAME="wan0" + SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="00:25:90:47:67:6f", ATTR{type}=="1", NAME="lan0" + SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="00:25:90:63:0f:80", ATTR{type}=="1", NAME="lan1" + SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="00:25:90:63:0f:81", ATTR{type}=="1", NAME="lan2" + ''; + + networking = { + nameservers = [ + "9.9.9.9" + "149.112.112.112" + ]; + interfaces = { + wan0.useDHCP = true; + lan0.useDHCP = false; + lan1.useDHCP = false; + lan2.useDHCP = false; + }; + + firewall = { + enable = false; + allowPing = true; + + # allow ssh on *all* interfaces, even wan. + allowedTCPPorts = lib.mkForce [ 22 ]; + allowedUDPPorts = lib.mkForce [ 22 ]; + + # interface-specific rules + interfaces = { + "lan0" = { + allowedTCPPorts = [ + 22 + 53 + ]; + allowedUDPPorts = [ + 22 + 53 + ]; + }; + }; + }; + + # <100 is trusted; =>100 is untrusted. + vlans = { + lan = { + id = 1; + interface = "lan1"; + }; + servers = { + id = 10; + interface = "lan1"; + }; + management = { + id = 21; + interface = "lan1"; + }; + iot = { + id = 100; + interface = "lan1"; + }; + guest = { + id = 110; + interface = "lan1"; + }; + }; + }; + + services = { + kea.dhcp4 = { + enable = true; + settings = { + lease-database = { + name = "/var/lib/kea/dhcp4.leases"; + persist = true; + type = "memfile"; + }; + interfaces-config = { + interfaces = [ + "lan" + "servers" + "management" + "iot" + "guest" + ]; + }; + option-data = [ + { + name = "domain-name-servers"; + data = ""; + always-send = true; + } + { + name = "routers"; + data = ""; + } + { + name = "domain-name"; + data = "beeping.local"; + } + ]; + + rebind-timer = 2000; + renew-timer = 1000; + valid-lifetime = 43200; + + # option domain-name-servers 9.9.9.9, 149.112.112.112; + # TODO: these should be dynamically generated based on ${config.networking.vlans} + subnet4 = [ + ({ + id = 1; + interface = "lan"; + subnet = "172.16.1.0/24"; + pools = [ { pool = "172.16.1.50 - 172.16.1.254"; } ]; + option-data = [ + { + name = "routers"; + data = "172.16.1.1"; + } + ] ++ commonDhcpOptions; + }) + ({ + id = 10; + interface = "servers"; + subnet = "172.16.10.0/24"; + pools = [ { pool = "172.16.10.50 - 172.16.10.254"; } ]; + option-data = [ + { + name = "routers"; + data = "172.16.10.1"; + } + ] ++ commonDhcpOptions; + }) + ({ + id = 21; + interface = "management"; + subnet = "172.16.21.0/24"; + pools = [ { pool = "172.16.21.50 - 172.16.21.254"; } ]; + option-data = [ + { + name = "routers"; + data = "172.16.21.1"; + } + ] ++ commonDhcpOptions; + }) + ({ + id = 100; + interface = "iot"; + subnet = "172.16.100.0/24"; + pools = [ { pool = "172.16.100.50 - 172.16.100.254"; } ]; + option-data = [ + { + name = "routers"; + data = "172.16.100.1"; + } + ] ++ commonDhcpOptions; + }) + ({ + id = 110; + interface = "guest"; + subnet = "172.16.110.0/24"; + pools = [ { pool = "172.16.110.50 - 172.16.110.254"; } ]; + option-data = [ + { + name = "routers"; + data = "172.16.110.1"; + } + ] ++ commonDhcpOptions; + }) + ]; + }; + }; + avahi = { + enable = true; + reflector = true; + interfaces = [ + "lan" + "iot" + ]; + }; + }; + + networking.hostName = "lily"; + + time.timeZone = "Europe/Amsterdam"; + + environment.systemPackages = with pkgs; [ + kitty.terminfo + tcpdump + dnsutils + bind + ethtool + ]; +} diff --git a/hosts/lily/dns.nix b/hosts/lily/dns.nix new file mode 100644 index 0000000..e92df27 --- /dev/null +++ b/hosts/lily/dns.nix @@ -0,0 +1,31 @@ +{ lib, config, ... }: +{ + services = { + dnsmasq = { + enable = false; # try some other options first + settings = { + cache-size = 10000; # Specifies the size of the DNS query cache. It will store up to n cached DNS queries to improve response times for frequently accessed domains. + server = [ + "9.9.9.9" + "149.112.112.112" + ]; + domain-needed = true; # Ensures that DNS queries are only forwarded for domains that are not found in the local configuration. + bogus-priv = true; # Blocks DNS queries for private IP address ranges to prevent accidental exposure of private resources. + no-resolv = true; # Prevents dnsmasq from using /etc/resolv.conf for DNS server configuration. + + # configure DHCP server; get leases by running: `cat /var/lib/dnsmasq/dnsmasq.leases` + dhcp-range = [ "br-lan,172.16.10.50,172.16.10.254,24h" ]; + interface = "br-lan"; + dhcp-host = "172.16.10.1"; + + # local sets the local domain name to "n". Combinded with expand-hosts = true, it will add a .local suffix to any local defined name when trying to resolve it. + local = "/local/"; + domain = "local"; + expand-hosts = true; + + no-hosts = true; # Prevents the use of /etc/hosts. This ensures that the local hosts file is not used to override DNS resolution. + address = "/booping.local/172.16.10.1"; + }; + }; + }; +} diff --git a/hosts/lily/hardware-configuration.nix b/hosts/lily/hardware-configuration.nix new file mode 100644 index 0000000..b0c372b --- /dev/null +++ b/hosts/lily/hardware-configuration.nix @@ -0,0 +1,37 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ config, lib, pkgs, modulesPath, ... }: + +{ + imports = + [ (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot.initrd.availableKernelModules = [ "xhci_pci" "ehci_pci" "ahci" "usbhid" "usb_storage" "sd_mod" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ "kvm-intel" ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = + { device = "/dev/disk/by-uuid/75447a73-848e-4b34-a1b3-d5b7a8e804ee"; + fsType = "ext4"; + }; + + swapDevices = + [ { device = "/dev/disk/by-uuid/d4552527-c7c6-4047-929b-aeb3500299e3"; } + ]; + + # Enables DHCP on each ethernet and wireless interface. In case of scripted networking + # (the default) this is the recommended approach. When using systemd-networkd it's + # still possible to use this option, but it's recommended to use it in conjunction + # with explicit per-interface declarations with `networking.interfaces..useDHCP`. + networking.useDHCP = lib.mkDefault true; + # networking.interfaces.eno1.useDHCP = lib.mkDefault true; + # networking.interfaces.eno2.useDHCP = lib.mkDefault true; + # networking.interfaces.enp1s0f0.useDHCP = lib.mkDefault true; + # networking.interfaces.enp1s0f1.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/hosts/lily/variables.nix b/hosts/lily/variables.nix new file mode 100644 index 0000000..00f986e --- /dev/null +++ b/hosts/lily/variables.nix @@ -0,0 +1,19 @@ +{ + lib, + config, + ... +}: +let + inherit (lib) mkOption types; + inherit (config.liv) variables; +in +{ + options.liv.variables.lily = { + thisMachine = mkOption { + default = "lily.srv.${variables.primaryDomain}"; + type = types.str; + readOnly = true; + description = "Domain of this specific machine"; + }; + }; +} diff --git a/hosts/lily/wireguard.nix b/hosts/lily/wireguard.nix new file mode 100644 index 0000000..0db3279 --- /dev/null +++ b/hosts/lily/wireguard.nix @@ -0,0 +1,3 @@ +{ + +} diff --git a/hosts/violet/backups.nix b/hosts/violet/backups.nix new file mode 100644 index 0000000..d8183e5 --- /dev/null +++ b/hosts/violet/backups.nix @@ -0,0 +1,54 @@ +let + borgbackupMonitor = + { + config, + pkgs, + lib, + ... + }: + with lib; + { + key = "borgbackupMonitor"; + _file = "borgbackupMonitor"; + config.systemd.services = + { + "notify-problems@" = { + enable = true; + serviceConfig.User = "liv"; + environment.SERVICE = "%i"; + script = '' + ${pkgs.curl}/bin/curl -d "$SERVICE FAILED! - service $SERVICE on host $(hostname) failed, run journalctl -u $SERVICE for details." + ''; + }; + } + // flip mapAttrs' config.services.borgbackup.jobs ( + name: value: + nameValuePair "borgbackup-job-${name}" { + unitConfig.OnFailure = "notify-problems@%i.service"; + } + ); + + # optional, but this actually forces backup after boot in case laptop was powered off during scheduled event + # for example, if you scheduled backups daily, your laptop should be powered on at 00:00 + config.systemd.timers = flip mapAttrs' config.services.borgbackup.jobs ( + name: value: + nameValuePair "borgbackup-job-${name}" { + timerConfig.Persistent = true; + } + ); + }; + +in +{ + imports = [ borgbackupMonitor ]; + services = { + borgbackup.jobs.liv-violet = { + paths = "/home/liv"; + encryption.mode = "none"; + environment.BORG_RSH = "ssh -i /home/liv/.ssh/id_ed25519"; + repo = "ssh://liv@100.115.178.50:9123/spinners/rootvol/backups/hosts/violet"; + compression = "auto,zstd"; + startAt = "daily"; + }; + }; +}