aboutsummaryrefslogtreecommitdiff
path: root/infra/libkookie
diff options
context:
space:
mode:
authorMx Kookie <kookie@spacekookie.de>2020-12-25 17:55:09 +0100
committerMx Kookie <kookie@spacekookie.de>2020-12-25 17:56:00 +0100
commit2757a4e9d5cd44b1d0ef6f9faf4e00f2d332ea4a (patch)
tree6f7faf572776ca9e13b04908d3fe85662355a1f5 /infra/libkookie
parent2550dbda72172ffa298e359f0151d9a2c597dae4 (diff)
libkookie: gaia: import previous configuration
Diffstat (limited to 'infra/libkookie')
-rw-r--r--infra/libkookie/configuration/server/acme/gaia.nix30
-rw-r--r--infra/libkookie/configuration/server/datacore/default.nix11
-rw-r--r--infra/libkookie/configuration/server/ferm2/gaia.nix64
-rw-r--r--infra/libkookie/configuration/server/jellyfin/default.nix45
-rw-r--r--infra/libkookie/configuration/server/nextcloud/default.nix44
-rw-r--r--infra/libkookie/configuration/server/openssh/default.nix18
-rw-r--r--infra/libkookie/configuration/server/syncthing/default.nix21
-rw-r--r--infra/libkookie/configuration/server/wireguard/gaia.nix14
-rw-r--r--infra/libkookie/modules/default.nix1
-rw-r--r--infra/libkookie/modules/harness/lib.nix6
-rw-r--r--infra/libkookie/modules/server/default.nix7
-rw-r--r--infra/libkookie/modules/server/ferm2/default.nix226
-rw-r--r--infra/libkookie/roots/gaia.nix136
13 files changed, 623 insertions, 0 deletions
diff --git a/infra/libkookie/configuration/server/acme/gaia.nix b/infra/libkookie/configuration/server/acme/gaia.nix
new file mode 100644
index 000000000000..96d25c1162aa
--- /dev/null
+++ b/infra/libkookie/configuration/server/acme/gaia.nix
@@ -0,0 +1,30 @@
+{ config, ... }:
+
+{
+ # HACK (doesn't work): solution to failing ACME services due to
+ # failing DNS // See: https://github.com/NixOS/nixpkgs/issues/106862
+ systemd.services."acme-fixperms".wants = [ "bind.service" ];
+ systemd.services."acme-fixperms".after = [ "bind.service" ];
+
+ security.acme.acceptTerms = true;
+ security.acme.certs."alarei.kookie.space" = {
+ email = "letsencrypt@spacekookie.de";
+ webroot = "/var/lib/acme/acme-challenge";
+ extraDomainNames = [
+ "kookiejar.tech"
+ "media.kookiejar.tech"
+ "media.alarei.kookie.space"
+ "sync.kookiejar.tech"
+ "sync.alarei.kookie.space"
+ "cloud.kookiejar.tech"
+ "could.alarei.kookie.space"
+ "music.kookiejar.tech"
+ "music.alarei.kookie.space"
+ ];
+ group = "nginx";
+ };
+
+ users.users.nginx.extraGroups = [ "core" ];
+
+ services.nginx.clientMaxBodySize = "2048M";
+}
diff --git a/infra/libkookie/configuration/server/datacore/default.nix b/infra/libkookie/configuration/server/datacore/default.nix
new file mode 100644
index 000000000000..34b1e671e8c4
--- /dev/null
+++ b/infra/libkookie/configuration/server/datacore/default.nix
@@ -0,0 +1,11 @@
+/** A special module to handle the datacore zfs storage
+ *
+ * Sets up special archive modes for ZFS and tools to manage the
+ * encrypted data sets.
+ *
+ */
+{ config, ... }:
+
+{
+ users.groups.core = {};
+}
diff --git a/infra/libkookie/configuration/server/ferm2/gaia.nix b/infra/libkookie/configuration/server/ferm2/gaia.nix
new file mode 100644
index 000000000000..2fa6ad5fe63c
--- /dev/null
+++ b/infra/libkookie/configuration/server/ferm2/gaia.nix
@@ -0,0 +1,64 @@
+/** Custom ferm2 configuration on gaia
+ *
+ * This set of configuration options is required to make the wireguard
+ * uplink to osmos.pbb.dev work. It does so by tagging all packets
+ * coming in over a particular interface (public-ip) with a mark, and
+ * then sorts replies to these connections into a special firewall
+ * table to send them out over this link again as well.
+ *
+ * This module assumes that wireguard is enabled and configured
+ */
+
+{ config, ... }:
+
+{
+ # Main firewall configuration
+ services.ferm2 = {
+ enable = true;
+ extraConfig = ''
+ table mangle {
+ chain PREROUTING {
+ # Mark all connections coming in from public-ip with mark 1312
+ interface public-ip CONNMARK set-mark 1312;
+ }
+
+ chain OUTPUT {
+ # Mark all packets that are responses to incoming public-ip
+ # connetions with mark 1312 (we can filter this in the fw later)
+ CONNMARK restore-mark;
+ }
+ }
+ '';
+ };
+
+ # Additional ip commands to configure the firewall
+ #
+ # FIXME: create a firewall module that wraps around this
+ networking.localCommands = ''
+ set -x
+ ip -6 rule flush
+ ip -4 rule flush
+ ip -6 rule add lookup main prio 32000
+ ip -4 rule add lookup main prio 32000
+
+ # Take packets with fwmark and sort it into 1312 table
+ ip -6 rule add from all fwmark 1312 lookup 1312 pref 9000
+ ip -4 rule add from all fwmark 1312 lookup 1312 pref 9000
+ '';
+
+ networking.wireguard.interfaces."public-ip" = {
+ ips = [ "2a0f:4ac0::18" "195.39.247.18" ];
+ privateKeyFile = "/var/lib/wireguard/keys/milan.private";
+ allowedIPsAsRoutes = true;
+ table = "1312";
+ postSetup = "ip link set dev public-ip mtu 1500";
+ peers = [
+ { publicKey = "kih/GnR4Bov/DM/7Rd21wK+PFQRUNH6sywVuNKkUAkk=";
+ allowedIPs = [ "0.0.0.0/0" "::/0" ];
+ # TODO: Currently telecom ipv6 handling is broken
+ # endpoint = "2a01:581:1:9::1:51820";
+ endpoint = "62.176.250.82:51820";
+ persistentKeepalive = 25; }
+ ];
+ };
+}
diff --git a/infra/libkookie/configuration/server/jellyfin/default.nix b/infra/libkookie/configuration/server/jellyfin/default.nix
new file mode 100644
index 000000000000..b1ad60a98bb7
--- /dev/null
+++ b/infra/libkookie/configuration/server/jellyfin/default.nix
@@ -0,0 +1,45 @@
+{ config, lib, ... }:
+
+{
+ # Default port should be 8096
+ services.jellyfin = {
+ enable = true;
+ group = "core";
+ };
+
+ # Required for chromecast stuff...
+ networking.firewall.allowedTCPPorts = [ 8096 ];
+
+ # Give jellyfin "core" group
+ users.users.jellyfin.extraGroups = [ "core" ];
+
+ # Enable nginx if not already
+ services.nginx.enable = true;
+ services.nginx.virtualHosts."media.kookiejar.tech" = {
+ serverAliases = [ "media.alarei.kookie.space" "kookiejar.tech" ];
+ useACMEHost = "alarei.kookie.space";
+ forceSSL = true;
+ locations."/" = {
+ proxyPass = "http://127.0.0.1:8096";
+ };
+
+ locations."/socket" = {
+ proxyPass = "http://127.0.0.1:8096";
+ extraConfig = ''
+ # global proxy conf
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_set_header X-Forwarded-Host $host:$server_port;
+ proxy_set_header X-Forwarded-Port $server_port;
+
+ # websocket support
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection $connection_upgrade;
+ '';
+ };
+ };
+
+}
diff --git a/infra/libkookie/configuration/server/nextcloud/default.nix b/infra/libkookie/configuration/server/nextcloud/default.nix
new file mode 100644
index 000000000000..545046916599
--- /dev/null
+++ b/infra/libkookie/configuration/server/nextcloud/default.nix
@@ -0,0 +1,44 @@
+{ config, lib, pkgs, ... }:
+
+{
+ services.nginx.enable = true;
+ services.nginx.virtualHosts."cloud.kookiejar.tech" = {
+ serverAliases = [ "cloud.alarei.kookie.space"];
+ useACMEHost = "alarei.kookie.space";
+ forceSSL = true;
+ };
+
+ # Give nextcloud "core" group
+ users.users.nextcloud.extraGroups = [ "core" ];
+
+ # Enable nextcloud and php settings
+ services.phpfpm.phpPackage = pkgs.php73;
+ services.nextcloud = {
+ enable = true;
+ package = pkgs.nextcloud19;
+ hostName = "cloud.kookiejar.tech";
+ https = true;
+ autoUpdateApps.enable = true;
+ config = {
+ dbtype = "pgsql";
+ dbuser = "nextcloud";
+ dbhost = "/run/postgresql";
+ dbname = "nextcloud";
+ adminpassFile = "/var/lib/nextcloud.admin.pw";
+ adminuser = "spacekookie";
+ };
+ home = "/datacore/cloud";
+ };
+
+ # Setup postgres (currently only used by nextcloud)
+ services.postgresql = {
+ enable = true;
+ ensureDatabases = [ "nextcloud" ];
+ ensureUsers = [
+ { name = "nextcloud";
+ ensurePermissions."DATABASE nextcloud" = "ALL PRIVILEGES";
+ }
+ ];
+ };
+
+}
diff --git a/infra/libkookie/configuration/server/openssh/default.nix b/infra/libkookie/configuration/server/openssh/default.nix
new file mode 100644
index 000000000000..df15b7128b6d
--- /dev/null
+++ b/infra/libkookie/configuration/server/openssh/default.nix
@@ -0,0 +1,18 @@
+{ config, ... }:
+
+{
+ services.openssh = {
+ enable = true;
+ permitRootLogin = "prohibit-password";
+ passwordAuthentication = false;
+
+ # Required for root
+ extraConfig = ''
+ Match Address 127.0.0.1
+ PermitRootLogin yes
+ '';
+ };
+
+ # Also enable mosh because /shrug
+ programs.mosh.enable = true;
+}
diff --git a/infra/libkookie/configuration/server/syncthing/default.nix b/infra/libkookie/configuration/server/syncthing/default.nix
new file mode 100644
index 000000000000..10287d88fa42
--- /dev/null
+++ b/infra/libkookie/configuration/server/syncthing/default.nix
@@ -0,0 +1,21 @@
+{ config, lib, ... }:
+
+{
+ services.syncthing = {
+ enable = true;
+ user = "spacekookie";
+ group = "core";
+ openDefaultPorts = true;
+ guiAddress = "0.0.0.0:8384";
+ };
+
+ services.nginx.enable = true;
+ services.nginx.virtualHosts."sync.kookiejar.tech" = {
+ serverAliases = [ "sync.alarei.kookie.space" ];
+ useACMEHost = "alarei.kookie.space";
+ forceSSL = true;
+ locations."/" = {
+ proxyPass = "http://127.0.0.1:8384";
+ };
+ };
+}
diff --git a/infra/libkookie/configuration/server/wireguard/gaia.nix b/infra/libkookie/configuration/server/wireguard/gaia.nix
new file mode 100644
index 000000000000..0f3768fa9bbe
--- /dev/null
+++ b/infra/libkookie/configuration/server/wireguard/gaia.nix
@@ -0,0 +1,14 @@
+{ config, ... }:
+
+{
+ networking.wireguard.interfaces."intranet" = {
+ ips = [ "10.13.12.2" ];
+ privateKeyFile = "/var/lib/wireguard/keys/private";
+ peers = [
+ { publicKey = "ugHG/NOqM/9hde9EmWpu7XsCpjT3WQbjLK99IGHtdjQ=";
+ allowedIPs = [ "10.13.12.0/24" "10.172.171.0/24" ];
+ endpoint = "hyperion.kookie.space:51820";
+ persistentKeepalive = 25; }
+ ];
+ };
+}
diff --git a/infra/libkookie/modules/default.nix b/infra/libkookie/modules/default.nix
index 227d6e83aa69..c7a2ba3ba5ca 100644
--- a/infra/libkookie/modules/default.nix
+++ b/infra/libkookie/modules/default.nix
@@ -7,6 +7,7 @@
# Add modules based on use-case
./workstation
+ ./server
./base
];
}
diff --git a/infra/libkookie/modules/harness/lib.nix b/infra/libkookie/modules/harness/lib.nix
index d4da08a8de48..842f02adfd36 100644
--- a/infra/libkookie/modules/harness/lib.nix
+++ b/infra/libkookie/modules/harness/lib.nix
@@ -15,4 +15,10 @@ in
# Load a simple path with the standard set of arguments
load = path: (import path) args;
+
+ # Patch an attribute set with access to the original set
+ #
+ # This function wraps around lib.recursiveUpdate to make it slighly
+ # less cumbersome to work with in one-liners.
+ patchAttrs = attrs: f: (lib.recursiveUpdate attrs (f attrs));
}
diff --git a/infra/libkookie/modules/server/default.nix b/infra/libkookie/modules/server/default.nix
new file mode 100644
index 000000000000..27ee9a21737a
--- /dev/null
+++ b/infra/libkookie/modules/server/default.nix
@@ -0,0 +1,7 @@
+{ config, ... }:
+
+{
+ imports = [
+ ./ferm2
+ ];
+}
diff --git a/infra/libkookie/modules/server/ferm2/default.nix b/infra/libkookie/modules/server/ferm2/default.nix
new file mode 100644
index 000000000000..8eecec68c0a1
--- /dev/null
+++ b/infra/libkookie/modules/server/ferm2/default.nix
@@ -0,0 +1,226 @@
+/** Taken from git.petabyte.dev
+ *
+ * https://git.petabyte.dev/petabyteboy/nixfiles/raw/branch/master/modules/ferm2/default.nix
+ *
+ * TODO: split the config block into its own file (core.nix) like
+ */
+{ lib, config, ... }:
+
+let
+ fwcfg = config.networking.firewall;
+ cfg = config.services.ferm2;
+in {
+ options = with lib; {
+ services.ferm2 = {
+ enable = mkEnableOption "Ferm easy rule making";
+ extraConfig = mkOption {
+ type = types.lines;
+ default = "";
+ };
+ extraConfig6 = mkOption {
+ type = types.lines;
+ default = "";
+ };
+ extraConfig4 = mkOption {
+ type = types.lines;
+ default = "";
+ };
+ extraInput = mkOption {
+ type = types.lines;
+ default = "";
+ };
+ extraInput6 = mkOption {
+ type = types.lines;
+ default = "";
+ };
+ extraInput4 = mkOption {
+ type = types.lines;
+ default = "";
+ };
+ extraOutput = mkOption {
+ type = types.lines;
+ default = "";
+ };
+ extraOutput6 = mkOption {
+ type = types.lines;
+ default = "";
+ };
+ extraOutput4 = mkOption {
+ type = types.lines;
+ default = "";
+ };
+ extraForward = mkOption {
+ type = types.lines;
+ default = "";
+ };
+ extraForward6 = mkOption {
+ type = types.lines;
+ default = "";
+ };
+ extraForward4 = mkOption {
+ type = types.lines;
+ default = "";
+ };
+ inputPolicy = mkOption {
+ type = types.str;
+ default = "DROP";
+ };
+ outputPolicy = mkOption {
+ type = types.str;
+ default = "ACCEPT";
+ };
+ forwardPolicy = mkOption {
+ type = types.str;
+ default = "ACCEPT";
+ };
+ };
+ };
+
+ config = lib.mkIf cfg.enable {
+ networking.firewall.enable = false;
+ services.ferm.enable = true;
+ services.ferm.config = ''
+ domain ip6 {
+ table filter {
+ chain INPUT {
+ policy ${cfg.inputPolicy};
+
+ proto ipv6-icmp icmpv6-type redirect DROP;
+ proto ipv6-icmp icmpv6-type 139 DROP;
+ proto ipv6-icmp ACCEPT;
+
+ mod state state INVALID DROP;
+ mod state state (ESTABLISHED RELATED) ACCEPT;
+
+ interface (lo ${
+ lib.concatStringsSep " " fwcfg.trustedInterfaces
+ }) ACCEPT;
+
+ proto tcp dport (${
+ lib.concatStringsSep " " (map toString fwcfg.allowedTCPPorts)
+ } ${
+ lib.concatStringsSep " "
+ (map (range: "${toString range.from}:${toString range.to}")
+ fwcfg.allowedTCPPortRanges)
+ }) ACCEPT;
+ proto udp dport (${
+ lib.concatStringsSep " " (map toString fwcfg.allowedUDPPorts)
+ } ${
+ lib.concatStringsSep " "
+ (map (range: "${toString range.from}:${toString range.to}")
+ fwcfg.allowedUDPPortRanges)
+ }) ACCEPT;
+
+ ${
+ lib.concatStringsSep "\n" (lib.mapAttrsToList (name: config: ''
+ interface ${name} proto udp dport (${
+ lib.concatStringsSep " " (map toString config.allowedUDPPorts)
+ } ${
+ lib.concatStringsSep " "
+ (map (range: "${toString range.from}:${toString range.to}")
+ config.allowedUDPPortRanges)
+ }) ACCEPT;
+ interface ${name} proto tcp dport (${
+ lib.concatStringsSep " " (map toString config.allowedTCPPorts)
+ } ${
+ lib.concatStringsSep " "
+ (map (range: "${toString range.from}:${toString range.to}")
+ config.allowedTCPPortRanges)
+ }) ACCEPT;
+ '') fwcfg.interfaces)
+ }
+
+ proto udp dport 546 daddr fe80::/64 ACCEPT;
+
+ ${cfg.extraInput}
+ ${cfg.extraInput6}
+ }
+ chain OUTPUT {
+ policy ${cfg.outputPolicy};
+
+ ${cfg.extraOutput}
+ ${cfg.extraOutput6}
+ }
+ chain FORWARD {
+ policy ${cfg.forwardPolicy};
+
+ ${cfg.extraForward}
+ ${cfg.extraForward6}
+ }
+ }
+
+ ${cfg.extraConfig}
+ ${cfg.extraConfig6}
+ }
+
+ domain ip {
+ table filter {
+ chain INPUT {
+ policy ${cfg.inputPolicy};
+
+ proto icmp icmp-type echo-request ACCEPT;
+
+ mod state state INVALID DROP;
+ mod state state (ESTABLISHED RELATED) ACCEPT;
+
+ interface (lo ${
+ lib.concatStringsSep " " fwcfg.trustedInterfaces
+ }) ACCEPT;
+
+ proto tcp dport (${
+ lib.concatStringsSep " " (map toString fwcfg.allowedTCPPorts)
+ } ${
+ lib.concatStringsSep " "
+ (map (range: "${toString range.from}:${toString range.to}")
+ fwcfg.allowedTCPPortRanges)
+ }) ACCEPT;
+ proto udp dport (${
+ lib.concatStringsSep " " (map toString fwcfg.allowedUDPPorts)
+ } ${
+ lib.concatStringsSep " "
+ (map (range: "${toString range.from}:${toString range.to}")
+ fwcfg.allowedUDPPortRanges)
+ }) ACCEPT;
+
+ ${
+ lib.concatStringsSep "\n" (lib.mapAttrsToList (name: config: ''
+ interface ${name} proto udp dport (${
+ lib.concatStringsSep " " (map toString config.allowedUDPPorts)
+ } ${
+ lib.concatStringsSep " "
+ (map (range: "${toString range.from}:${toString range.to}")
+ config.allowedUDPPortRanges)
+ }) ACCEPT;
+ interface ${name} proto tcp dport (${
+ lib.concatStringsSep " " (map toString config.allowedTCPPorts)
+ } ${
+ lib.concatStringsSep " "
+ (map (range: "${toString range.from}:${toString range.to}")
+ config.allowedTCPPortRanges)
+ }) ACCEPT;
+ '') fwcfg.interfaces)
+ }
+
+ ${cfg.extraInput}
+ ${cfg.extraInput4}
+ }
+ chain OUTPUT {
+ policy ${cfg.outputPolicy};
+
+ ${cfg.extraOutput}
+ ${cfg.extraOutput4}
+ }
+ chain FORWARD {
+ policy ${cfg.forwardPolicy};
+
+ ${cfg.extraForward}
+ ${cfg.extraForward4}
+ }
+ }
+
+ ${cfg.extraConfig}
+ ${cfg.extraConfig4}
+ }
+ '';
+ };
+}
diff --git a/infra/libkookie/roots/gaia.nix b/infra/libkookie/roots/gaia.nix
new file mode 100644
index 000000000000..37b18fedd0a5
--- /dev/null
+++ b/infra/libkookie/roots/gaia.nix
@@ -0,0 +1,136 @@
+/* TOP LEVEL DEVICE CONFIGURATION FOR
+ *
+ * gaia (data storage node)
+ *
+ *
+ * This file is part of LIBKOOKIE, a collection of nix expressions.
+ * LIBKOOKIE is licensed under the GPL-3.0 (or later) -- see LICENSE
+ */
+
+{ lib, config, pkgs, ... } @ args:
+
+let klib = (import <modules/harness/lib.nix>) args;
+in
+{
+ ###################################################################
+ # libkookie configuration
+ #
+ #
+ #
+
+
+ imports = with klib; [
+ # Load base modules required to bootstrap libkookie
+ <home-manager/nixos> <modules> <configuration/nix>
+
+ # BUILD A BETTER LOADER GOD DAMN IT
+ <configuration/server/acme/gaia.nix>
+ <configuration/server/datacore>
+ <configuration/server/ferm2/gaia.nix>
+ <configuration/server/syncthing>
+ <configuration/server/jellyfin>
+ <configuration/server/nextcloud>
+ <configuration/server/openssh>
+ <configuration/server/syncthing>
+ <configuration/server/wireguard/gaia.nix>
+ ];
+
+ # TODO: build a klib function to patch cfg here
+ libkookie.activeUsers = with klib; [
+ (patchAttrs(load <configuration/users/spacekookie>) (a: { cfg.extraGroups = a.cfg.extraGroups ++ [ "core" ]; }))
+ (patchAttrs(load <configuration/users/qyliss>) ({ ... }: { cfg.extraGroups = [ "core" ]; }))
+ ];
+
+ # Enable fish shell handling on the system
+ libkookie.base.fish.enable = true;
+
+
+ #
+ #
+ #
+ #
+ ###################################################################
+
+ ###################################################################
+ # NixOS base system options
+ #
+ #
+ #
+
+
+ boot.cleanTmpDir = true;
+ boot.tmpOnTmpfs = true;
+ boot.supportedFilesystems = [ "zfs" "exfat" ];
+
+ boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "usb_storage" "usbhid" "sd_mod" ];
+ boot.initrd.kernelModules = [ ];
+ boot.kernelModules = [ "kvm-amd" ];
+ boot.extraModulePackages = [ ];
+ boot.loader.grub.device = "/dev/sdg";
+
+ fileSystems."/" =
+ { device = "zroot";
+ fsType = "zfs";
+ };
+
+ fileSystems."/boot" =
+ { device = "/dev/disk/by-uuid/e5b36b2d-bdc7-4963-9a60-c2e1611a9676";
+ fsType = "ext4";
+ };
+
+ swapDevices = [ ];
+ nix.maxJobs = 4;
+
+ networking = {
+ defaultGateway = "10.7.1.1";
+ nameservers = [ "10.7.1.2" "1.1.1.1" ];
+ interfaces.eno1 = {
+ ipv4.addresses = [ { address = "10.7.1.3"; prefixLength = 24; } ];
+ };
+ hostName = "gaia";
+ hostId = "59405489";
+ dhcpcd.enable = false;
+
+ firewall.allowedTCPPorts = [ 80 443 ];
+ nat = {
+ enable = true;
+ internalInterfaces = ["ve-+"];
+ externalInterface = "eno1";
+ };
+ };
+
+ time.timeZone = "Europe/Berlin";
+ programs.mtr.enable = true;
+
+ # Torrenting container
+ # containers.trnsmssn =
+ # { autoStart = true;
+ # privateNetwork = true;
+ # hostAddress = "10.7.1.3";
+ # localAddress = "10.7.1.13";
+ # config = { config, pkgs, ... }:
+ # { services.mullvad.enable = true;
+ # services.transmission = { enable = true; };
+ # environment.systemPackages = with pkgs; [ transmission openvpn ];
+ # };
+ # };
+
+ users.users."spacekookie".hashedPassword = "$6$rounds=1000000$Nnlc.bdBdGIVXtL$Ndb0WoOT.xl3eV2ba4jHe0ajbrGfVSf.RoS2hdaU8hvV8.UHBAZbDtLtXLqQ59Q6eUfjui3YIY6XWUGxAZNYF.";
+
+ # users.users."spacekookie" = {
+ # hashedPassword =
+ # openssh.authorizedKeys.keys = [
+ # "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBALMtai+K3wBvpSf9ntuBH1GNte7quhIA4/ZWKlvF0A" # uwu
+ # "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBdIsXiaE3YLuqekTg8Xq65n1GUX5IQc8/FKMrbCsCWY" # tempest
+
+ # "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEMN1iwhQinXxg9H+wJn34EawgzdrrdfBzT0N0wy8yz9 spacekookie@alarei"
+ # "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICPQ7alBckvMjRL/Tp38dSkZDTR/cLHRcJPwhP5+/fdM"
+ # ];
+ # };
+
+ # This is pinned here because nextcloud/postgres is being unstable
+ # at version 18. In the future you might wanna look at upgrading
+ # again, but for now, just be happily one major version behind!
+ system.stateVersion = "20.09";
+}
+