update
Some checks failed
ci/woodpecker/push/build-cache Pipeline failed

This commit is contained in:
Lucy Hochkamp 2025-10-23 16:20:45 +02:00
parent 33ee2f5760
commit 0147729915
No known key found for this signature in database
14 changed files with 245 additions and 176 deletions

60
flake.lock generated
View file

@ -222,11 +222,11 @@
"rust-overlay": "rust-overlay"
},
"locked": {
"lastModified": 1760323106,
"narHash": "sha256-HqVZwIwpDviDB1daJY/pPzkMKAC+dj5y0rDWEJbuKsE=",
"lastModified": 1761141169,
"narHash": "sha256-5IZjbTvP5dNTD8CbEYlNbicdGcbCN9SC9ksMm2ZEXH0=",
"owner": "helix-editor",
"repo": "helix",
"rev": "10c6a100c6e93b0dc175bf2f8b5a1afd66aebe2a",
"rev": "d79cce4e4bfc24dd204f1b294c899ed73f7e9453",
"type": "github"
},
"original": {
@ -242,11 +242,11 @@
]
},
"locked": {
"lastModified": 1760312644,
"narHash": "sha256-U9SkK45314urw9P7MmjhEgiQwwD/BTj+T3HTuz1JU1Q=",
"lastModified": 1761191301,
"narHash": "sha256-xsRL2Oyb4YRZZ1Tu4WzR2uFg1n931bH+PfLdFcqtLg8=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "e121f3773fa596ecaba5b22e518936a632d72a90",
"rev": "4958aafe7b237dc1e857fb0c916efff72075048f",
"type": "github"
},
"original": {
@ -422,11 +422,11 @@
"rust-overlay": "rust-overlay_3"
},
"locked": {
"lastModified": 1759395653,
"narHash": "sha256-sv9J1z6CrTPf9lRJLyCN90fZVdQz7LFeX7pIlInH8BQ=",
"lastModified": 1760940149,
"narHash": "sha256-KbM47vD6E0cx+v4jYQZ8mD5N186AKm2CQlyh34TW58U=",
"owner": "YaLTeR",
"repo": "niri",
"rev": "ba6e5e082a79901dc89b0d49c5da1b769d652aec",
"rev": "b3245b81a6ed8edfaf5388a74d2e0a23c24941e5",
"type": "github"
},
"original": {
@ -463,11 +463,11 @@
]
},
"locked": {
"lastModified": 1760241904,
"narHash": "sha256-OD7QnaGEVNdukYEbJbUNWPsvnDrpbZOZxVIk6Pt9Jhw=",
"lastModified": 1760846226,
"narHash": "sha256-xmU8kAsRprJiTGBTaGrwmjBP3AMA9ltlrxHKFuy5JWc=",
"owner": "nix-community",
"repo": "nix-index-database",
"rev": "c9f5ea45f25652ec2f771f9426ccacb21cbbaeaa",
"rev": "5024e1901239a76b7bf94a4cd27f3507e639d49e",
"type": "github"
},
"original": {
@ -478,11 +478,11 @@
},
"nixos-hardware": {
"locked": {
"lastModified": 1760106635,
"narHash": "sha256-2GoxVaKWTHBxRoeUYSjv0AfSOx4qw5CWSFz2b+VolKU=",
"lastModified": 1760958188,
"narHash": "sha256-2m1S4jl+GEDtlt2QqeHil8Ny456dcGSKJAM7q3j/BFU=",
"owner": "NixOS",
"repo": "nixos-hardware",
"rev": "9ed85f8afebf2b7478f25db0a98d0e782c0ed903",
"rev": "d6645c340ef7d821602fd2cd199e8d1eed10afbc",
"type": "github"
},
"original": {
@ -494,11 +494,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1760038930,
"narHash": "sha256-Oncbh0UmHjSlxO7ErQDM3KM0A5/Znfofj2BSzlHLeVw=",
"lastModified": 1761114652,
"narHash": "sha256-f/QCJM/YhrV/lavyCVz8iU3rlZun6d+dAiC3H+CDle4=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "0b4defa2584313f3b781240b29d61f6f9f7e0df3",
"rev": "01f116e4df6a15f4ccdffb1bcd41096869fb385c",
"type": "github"
},
"original": {
@ -525,11 +525,11 @@
},
"nixpkgs-master": {
"locked": {
"lastModified": 1760353201,
"narHash": "sha256-lApR6u9s3ymKIAXofVPS+eo/y6HO8OrUp8Hl0S30tOE=",
"lastModified": 1761228883,
"narHash": "sha256-8jKkT4Yc8I/PnDczaD9diDcJkckwP7WAstQcYbMSo4s=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "d559772cb55d806536aef3cf4ba3f7ce25fe4be9",
"rev": "0cfbb4d10f6e813e6e9750fbf5396747cf3b6212",
"type": "github"
},
"original": {
@ -767,11 +767,11 @@
]
},
"locked": {
"lastModified": 1760240450,
"narHash": "sha256-sa9bS9jSyc4vH0jSWrUsPGdqtMvDwmkLg971ntWOo2U=",
"lastModified": 1760998189,
"narHash": "sha256-ee2e1/AeGL5X8oy/HXsZQvZnae6XfEVdstGopKucYLY=",
"owner": "Mic92",
"repo": "sops-nix",
"rev": "41fd1f7570c89f645ee0ada0be4e2d3c4b169549",
"rev": "5a7d18b5c55642df5c432aadb757140edfeb70b3",
"type": "github"
},
"original": {
@ -881,11 +881,11 @@
"rust-overlay": "rust-overlay_5"
},
"locked": {
"lastModified": 1759707084,
"narHash": "sha256-0pkftKs6/LReNvxw7DVTN2AJEheZVgyeK0Aarbagi70=",
"lastModified": 1761173223,
"narHash": "sha256-FumZh+fPRaKXkl9Y1uTh5KV7Io/AyOZso+UkqLhLArs=",
"owner": "Supreeeme",
"repo": "xwayland-satellite",
"rev": "a9188e70bd748118b4d56a529871b9de5adb9988",
"rev": "bf745144acda1343934e9a094cf9458a54d57889",
"type": "github"
},
"original": {
@ -902,11 +902,11 @@
]
},
"locked": {
"lastModified": 1760329437,
"narHash": "sha256-TbTTbn2pr0urylodXUi0r9sUB/AjvaZuLclG4b0wLp8=",
"lastModified": 1761180075,
"narHash": "sha256-V4WLeUQ4gCGZiVihlXWBOZ/1FNcL0jM4zgTY1haJLvY=",
"owner": "0xc000022070",
"repo": "zen-browser-flake",
"rev": "df8f0729adfcb72b1e6bb2751f92dec0f54283c3",
"rev": "771a2604606905d8c0ffe3b818dc2cc5bd1405d8",
"type": "github"
},
"original": {

170
flake.nix
View file

@ -12,6 +12,8 @@
sops-nix.url = "github:Mic92/sops-nix";
sops-nix.inputs.nixpkgs.follows = "nixpkgs";
impermanence.url = "github:nix-community/impermanence";
# colmena.url = "github:zhaofengli/colmena";
# colmena.inputs.nixpkgs.follows = "nixpkgs";
# software
lanzaboote = {
@ -37,7 +39,7 @@
mtxclient.flake = false;
nix-ci.url = "git+https://git.xyno.systems/xyno/nix-ci";
nix-ci.inputs.nixpkgs.follows = "nixpkgs";
nix-index-database.url = "github:nix-community/nix-index-database";
nix-index-database.inputs.nixpkgs.follows = "nixpkgs";
@ -62,6 +64,7 @@
self,
nixpkgs,
nixpkgs-master,
# colmena,
...
}:
let
@ -102,71 +105,110 @@
inputs.nix-index-database.nixosModules.nix-index
]
++ (import ./modules/module-list.nix);
in
{
overlays.default =
final: prev:
(
{
unstable = import nixpkgs-master {
system = prev.system;
config.allowUnfree = true;
};
}
// (import ./overlays inputs final prev)
);
nixosConfigurations = lib.xyno.loadInstances ./instances (modules);
devShells."x86_64-linux".default =
let
pkgs = genPkgs "x86_64-linux";
in
pkgs.mkShell {
packages = [
pkgs.nixfmt-rfc-style
pkgs.nil
pkgs.sops
(pkgs.runCommand "nix-config-bin" { } ''
mkdir -p $out/bin
cp ${./bin}/* $out/bin
'')
];
SOPS_CONFIG = (pkgs.callPackage ./sops.nix { instanceConfigs = lib.xyno.getDirs ./instances; });
};
hydraJobs.systems = lib.foldl' lib.recursiveUpdate { } [
(builtins.mapAttrs (
host: config:
lib.foldl' lib.recursiveUpdate { } ([
{
inherit (config.config.system.build) toplevel;
kernel = config.config.boot.kernelPackages.kernel;
}
])
) self.nixosConfigurations)
systems = [
"x86_64-linux"
"aarch64-linux"
];
hydraJobs.fods = {
caddy = self.nixosConfigurations.ds9.config.services.caddy.package;
};
packages."x86_64-linux" =
forEachSystem = f: (map (x: f x) systems);
importConfigs =
n:
map (x: {
${x} = {
networking.hostName = x;
imports = modules ++ [ (./instances/${x}) ];
_module.args.otherNodes = lib.filterAttrs (n: v: n != "meta" && n != x) inputs.self.colmena;
};
}) n;
in
lib.foldl' lib.recursiveUpdate { } (
[
{
colmena = (
lib.foldl' lib.recursiveUpdate
{
meta = {
specialArgs = { inherit inputs; };
nixpkgs = genPkgs "x86_64-linux";
};
deployment.privilegeEscalationCommand = [
"run0"
"--unit=colmena-apply"
];
}
(importConfigs [
"ds9"
"picard"
"theseus"
])
);
overlays.default =
final: prev:
(
{
unstable = import nixpkgs-master {
system = prev.system;
config.allowUnfree = true;
};
}
// (import ./overlays inputs final prev)
);
hydraJobs.systems = lib.foldl' lib.recursiveUpdate { } [
(builtins.mapAttrs (
host: config:
lib.foldl' lib.recursiveUpdate { } ([
{
inherit (config.config.system.build) toplevel;
kernel = config.config.boot.kernelPackages.kernel;
}
])
) (lib.filterAttrs (n: v: n != "meta") self.colmena))
];
hydraJobs.fods = {
caddy = self.nixosConfigurations.ds9.config.services.caddy.package;
};
}
]
++ (forEachSystem (
system:
let
pkgs = genPkgs "x86_64-linux";
pkgs = genPkgs system;
in
{
nix = pkgs.unstable.lixPackageSets.latest.lix;
inherit (pkgs) nix-fast-build attic-client jq nix-ci;
};
checks."x86_64-linux"."nixos" =
let
pkgs = genPkgs "x86_64-linux";
in
pkgs.testers.runNixOSTest {
imports = (import ./modules/test-list.nix);
node.specialArgs = { inherit inputs; };
extraBaseModules.imports = modules;
extraBaseModules.services.openssh.enable = true;
node.pkgsReadOnly = false;
};
};
devShells.${system}.default = pkgs.mkShell {
packages = [
pkgs.nixfmt-rfc-style
pkgs.nil
pkgs.sops
(pkgs.runCommand "nix-config-bin" { } ''
mkdir -p $out/bin
cp ${./bin}/* $out/bin
'')
pkgs.colmena
]
++ (lib.attrValues self.packages.${system});
SOPS_CONFIG = (pkgs.callPackage ./sops.nix { instanceConfigs = lib.xyno.getDirs ./instances; });
};
packages.${system} = {
nix = pkgs.unstable.lixPackageSets.latest.lix;
inherit (pkgs)
nix-fast-build
attic-client
jq
nix-ci
;
};
checks.${system}."nixos" = pkgs.testers.runNixOSTest {
imports = (import ./modules/test-list.nix);
node.specialArgs = { inherit inputs; };
extraBaseModules.imports = modules;
extraBaseModules.services.openssh.enable = true;
node.pkgsReadOnly = false;
};
}
))
);
}

View file

@ -53,17 +53,11 @@ in
install_url = moz "german_dictionary_de_de_for_sp";
};
"uBlock0@raymondhill.net" = {
default_area = "menupanel";
default_area = "navbar";
install_url = moz "ublock-origin";
installation_mode = "force_installed";
private_browsing = true;
};
"uMatrix@raymondhill.net" = {
default_area = "menupanel";
install_url = moz "umatrix";
installation_mode = "force_installed";
private_browsing = true;
};
"vimium-c@gdh1995.cn" = {
default_area = "navbar";
install_url = moz "vimium-c";
@ -367,6 +361,8 @@ in
];
"user-filters" =
''marketplace.visualstudio.com##+js(rpnt, script, /"(DisableVSCodeDownloadButtonEnabled|Microsoft\\.VisualStudio\\.Services\\.Gallery\\.DisableVSCodeDownloadButton)":true/, "$1":false)'';
"hostnameSwitchesString" =
"no-large-media: behind-the-scene false\nno-remote-fonts: * true\nno-csp-reports: * true";
};
};

View file

@ -1,12 +1,11 @@
{
sopsKey = "fada7e7be28e186e463ad745a38d17f36849d8a7";
modules = [ ./configuration.nix ];
hostName = "ds9";
publicHostname = "ds9.hailsatan.eu";
prometheusServer = true;
wg = {
pubKey = "aZvSeAhKG3B5I2My5IqQoSlntMzbCHM6OU92WEScohc=";
# server = true;
# v4 = "10.13.12.1";
imports = [ ./configuration.nix ];
xyno.services.monitoring.prometheusServer = true;
xyno.meta = {
sopsKey = "fada7e7be28e186e463ad745a38d17f36849d8a7";
};
xyno.services.wireguard.pubKey = "aZvSeAhKG3B5I2My5IqQoSlntMzbCHM6OU92WEScohc=";
deployment = {
targetHost = "ds9.hailsatan.eu";
};
}

View file

@ -1,10 +1,8 @@
{
modules = [ ./configuration.nix ];
sopsKey = "b730b2bf54eb792a14bfd3e68c14c08894376c5f";
hostName = "picard";
publicHostname = "xyno.space";
# prometheusServer = true;
wg = {
imports = [ ./configuration.nix ];
xyno.meta.sopsKey = "b730b2bf54eb792a14bfd3e68c14c08894376c5f";
deployment.targetHost = "xyno.space";
xyno.services.wireguard = {
pubKey = "7JcdTbWfsyGWhJM1Rk9Y4xZVLPHcTmoG/Ne/AFCYKFs=";
server = true;
v4 = "10.13.12.1";

View file

@ -1,8 +1,11 @@
{
modules = [ ./configuration.nix ];
hostName = "theseus";
sopsKey = "4019fd893bba15618c2f93a38ef418ce360bc418";
wg = {
pubKey = "";
imports = [ ./configuration.nix ];
deployment = {
targetHost = null;
allowLocalDeployment = true;
};
xyno.meta.sopsKey = "4019fd893bba15618c2f93a38ef418ce360bc418";
xyno.services.wireguard = {
# pubKey = "";
};
}

View file

@ -333,6 +333,9 @@ in
Mod+Shift+P { power-off-monitors; }
Super+Backslash { focus-workspace "scratchpad"; }
}
hotkey-overlay {
skip-at-startup
}
layout {
// center-focused-column "always"
gaps 8
@ -349,9 +352,10 @@ in
tab-indicator {
hide-when-single-tab
position "top"
position "bottom"
place-within-column
width 8
width 12
length total-proportion=0.8
gap 8
}
}

View file

@ -58,21 +58,23 @@ let
# It would be ideal to determine _when_ the current event ends, and set the
# timeout accordinly. That would require parsing khal's output a bit more.
while true; do
(inotifywait \
--event modify \
--event create \
--event delete \
--event close_write \
--event moved_to \
--event move \
--monitor \
--timeout 120 \
--recursive \
"$HOME/.calendars" 2> /dev/null) || true | \
while read -r _; do
# (inotifywait \
# --event modify \
# --event create \
# --event delete \
# --event close_write \
# --event moved_to \
# --event move \
# --monitor \
# --timeout 120 \
# --recursive \
# "$HOME/.calendars" 2> /dev/null) || true | \
# while read -r _; do
# TODO: fix inotify stuff
render
sleep 30
# timeout 3 cat || true # debounce for 3s, https://stackoverflow.com/a/69945839
done
# done
done
'';

View file

@ -28,6 +28,7 @@
./services/monitoring.nix
./services/wireguard.nix
./system/impermanence.nix
./system/meta.nix
./system/user.nix
./user-services/khal.nix
./user-services/syncthing.nix

View file

@ -25,7 +25,6 @@ in
]; # theseus
environment.etc."msmtprc".enable = false;
sops.defaultSopsFile = ../../secrets/common.yaml;
sops.secrets = lib.mkMerge (
[
{

View file

@ -2,18 +2,16 @@
pkgs,
lib,
config,
instanceConfig,
instanceConfigs,
# inputs,
otherNodes,
...
}:
with lib;
let
cfg = config.xyno.services.monitoring;
firstInstanceWithPromServer = (builtins.head (
builtins.filter (x: x ? prometheusServer && x.prometheusServer) (attrValues instanceConfigs)
)).hostName;
firstInstanceWithPromServer = if cfg.prometheusServer then config.networking.hostName else (builtins.head (
attrValues (filterAttrs (n: v: v.config.xyno.services.monitoring.prometheusServer) (otherNodes))
)).config.networking.hostName;
vmBasicAuthUsername = "xyno-monitoring";
in
{
@ -24,6 +22,10 @@ in
default = "http://${firstInstanceWithPromServer}.${config.xyno.services.wireguard.monHostsDomain}:8428/api/v1/write";
description = "where prometheus metrics should be pushed to";
};
options.xyno.services.monitoring.prometheusServer = mkOption {
type = types.bool;
default = false;
};
options.xyno.services.monitoring.exporters = mkOption {
type = types.attrsOf (types.either types.int types.str);
description = "names of exporters and their ports (to open fw and generate prometheus config)";
@ -64,7 +66,7 @@ in
};
})
(mkIf (cfg.enable && instanceConfig ? prometheusServer && instanceConfig.prometheusServer) {
(mkIf (cfg.enable && cfg.prometheusServer) {
xyno.impermanence.directories = [ "/var/lib/${config.services.victoriametrics.stateDir}" ];
sops.secrets."victoriametrics/basicAuthPassword" = {
reloadUnits = [ "victoriametrics.service" ];

View file

@ -2,14 +2,13 @@
pkgs,
lib,
config,
instanceConfigs,
instanceConfig,
otherNodes,
...
}:
with lib;
let
wgServer = instanceConfig ? wg.server && instanceConfig.wg.server;
cfg = config.xyno.services.wireguard;
wgServer = cfg.server;
ula = cfg.ula;
ulaPrefix = "${ula}:1337"; # /64 for normal vpn
monitoringUlaPrefix = "${ula}:2337"; # /64 for monitoring
@ -25,51 +24,50 @@ let
in
"${prefix}:${localPart}";
# peers list for networkd
filteredConfigs = builtins.filter (x: x.hostName != config.networking.hostName) (
attrValues instanceConfigs
);
wgPeersLists = map (
wgPeersLists = attrValues (mapAttrs (
c:
let
hasV4 = c.xyno.services.wireguard.v4 && cfg.v4;
isServer = c.xyno.services.wireguard.server;
publicHostname = c.deployment.targetHost;
pubKey = c.xyno.services.wireguard.pubKey;
in
(
(optional (c ? publicHostname) {
(optional (publicHostname != null) {
# if peer is publicly on the internet
AllowedIPs =
(optionals (c ? wg.server && c.wg.server) [
# is server
(optionals (isServer) [
"::/0"
])
++ (optionals (c ? wg.server && c.wg.server && c ? wg.v4 && instanceConfig ? wg.v4) [
# both client and server have a v4
++ (optionals (isServer && hasV4) [
"0.0.0.0/0"
])
++ (optionals (!c ? wg.server || !c.wg.server) [
# is not server
"${genUlaForHost ulaPrefix c.hostName}/128" # if a host is reachable but shouldn't play server, send only to the hosts ip
++ (optionals (!isServer) [
"${genUlaForHost ulaPrefix c.networking.hostName}/128" # if a host is reachable but shouldn't play server, send only to the hosts ip
])
++ (optionals ((!c ? wg.server || !c.wg.server) && c ? wg.v4 && instanceConfig ? wg.v4) [
# no server, no ipv4 yay
++ (optionals ((!isServer) && hasV4) [
"${c.wg.v4}/32"
]);
RouteTable = 1000;
Endpoint = "${c.publicHostname}:51820";
Endpoint = "${publicHostname}:51820";
PersistentKeepalive = 25;
PublicKey = c.wg.pubKey;
PublicKey = pubKey;
PresharedKeyFile = config.sops.secrets."wg/psk".path;
})
++ (optional ((!c ? publicHostname) && wgServer && (c ? wg.pubKey)) {
++ (optional ((publicHostname == null) && wgServer && (pubKey != null)) {
# if this is the server and the peer isn't reachable on the internet
AllowedIPs = [
"${genUlaForHost ulaPrefix c.hostName}/128"
"${genUlaForHost monitoringUlaPrefix c.hostName}/128"
]
++ (optionals (c ? wg.v4 && instanceConfig ? wg.v4) [
++ (optionals (hasV4) [
"${c.wg.v4}/32"
]);
PublicKey = c.wg.pubKey;
PublicKey = pubKey;
PresharedKeyFile = config.sops.secrets."wg/psk".path;
})
)
) filteredConfigs;
) otherNodes);
wgPeers = flatten wgPeersLists;
in
{
@ -94,18 +92,34 @@ in
type = types.str;
default = genUlaForHost monitoringUlaPrefix config.networking.hostName;
};
options.xyno.services.wireguard.pubKey = mkOption {
type = types.nullOr types.str;
default = null;
};
options.xyno.services.wireguard.server = mkOption {
type = types.bool;
default = false;
};
options.xyno.services.wireguard.v4 = mkOption {
type = types.nullOr types.str;
default = null;
};
config = mkIf cfg.enable {
# TODO: add a all traffic through this network
networking.hosts =
(mapAttrs' (
n: v: nameValuePair (genUlaForHost ulaPrefix v.hostName) [ "${v.hostName}.${cfg.hostsDomain}" ]
) instanceConfigs)
n: v:
nameValuePair (genUlaForHost ulaPrefix v.networking.hostName) [
"${v.networking.hostName}.${cfg.hostsDomain}"
]
) otherNodes)
// (mapAttrs' (
n: v:
nameValuePair (genUlaForHost monitoringUlaPrefix v.hostName) [
"${v.hostName}.${cfg.monHostsDomain}"
nameValuePair (genUlaForHost monitoringUlaPrefix v.networking.hostName) [
"${v.networking.hostName}.${cfg.monHostsDomain}"
]
) instanceConfigs);
) otherNodes);
networking.firewall.allowedUDPPorts = optional wgServer 51820;
networking.firewall.interfaces."wg0".allowedUDPPorts = optional wgServer 53;
systemd.network.netdevs."99-wg0" = {
@ -126,15 +140,15 @@ in
matchConfig.Name = "wg0";
networkConfig = {
Description = "xyno wireguard";
IPMasquerade = mkIf (instanceConfig ? wg.server && instanceConfig.wg.server) "both";
IPv4Forwarding = (instanceConfig ? wg.server && instanceConfig.wg.server);
IPv6Forwarding = (instanceConfig ? wg.server && instanceConfig.wg.server);
IPMasquerade = mkIf wgServer "both";
IPv4Forwarding = wgServer;
IPv6Forwarding = wgServer;
};
address = [
"${(genUlaForHost ulaPrefix config.networking.hostName)}/64"
"${(genUlaForHost monitoringUlaPrefix config.networking.hostName)}/64"
]
++ (optionals (instanceConfig ? wg.v4) [ "${instanceConfig.wg.v4}/24" ]);
++ (optionals (cfg.v4) [ "${cfg.v4}/24" ]);
};
systemd.network.networks."51-wg0-all-traffic" = {
matchConfig.Name = "wg0";

8
modules/system/meta.nix Normal file
View file

@ -0,0 +1,8 @@
{lib,...}: with lib;{
options.xyno.meta = {
sopsKey = mkOption { type = types.text; };
};
config = {
sops.defaultSopsFile = ../../secrets/common.yaml;
};
}

View file

@ -17,6 +17,7 @@ in
config = lib.mkIf cfg.enable {
environment.homeBinInPath = true;
nix.settings.trusted-users = [cfg.name];
users.groups.plugdev = {};
users.users.${cfg.name} = {
openssh.authorizedKeys.keys = ["ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAID/oMAi5jyQsNohfhcSH2ItisTpBGB0WtYTVxJYKKqhj"]; # theseus
isNormalUser = true;