1
1
Fork 1
mirror of https://github.com/oddlama/nix-config.git synced 2025-10-10 23:00:39 +02:00

feat: configure homeassistant and esphome on new machine

This commit is contained in:
oddlama 2025-01-26 01:43:01 +01:00
parent 0ff0828ca9
commit 3d37e2959f
No known key found for this signature in database
GPG key ID: 14EFE510775FE39A
52 changed files with 403 additions and 672 deletions

106
flake.lock generated
View file

@ -36,11 +36,11 @@
"treefmt-nix": "treefmt-nix"
},
"locked": {
"lastModified": 1737124467,
"narHash": "sha256-askwM5GDYo4xy/UARNXUvn7lKERyNp31BcES/t4Ki2Y=",
"lastModified": 1737808592,
"narHash": "sha256-zSr8rSnaDlsifQhKW6kLKr+zZj0h9jbx/DQ8V7PENhM=",
"owner": "oddlama",
"repo": "agenix-rekey",
"rev": "27c5fc5b763321054832d0c96a9259d849b2f58a",
"rev": "a1dcdd27ff12a24f0d3ac1fe016ed08e1a89291f",
"type": "github"
},
"original": {
@ -663,12 +663,12 @@
},
"flake-compat_9": {
"locked": {
"lastModified": 1696426674,
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
"revCount": 57,
"lastModified": 1733328505,
"narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=",
"rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec",
"revCount": 69,
"type": "tarball",
"url": "https://api.flakehub.com/f/pinned/edolstra/flake-compat/1.0.1/018afb31-abd1-7bff-a5e4-cff7e18efb7a/source.tar.gz"
"url": "https://api.flakehub.com/f/pinned/edolstra/flake-compat/1.1.0/01948eb7-9cba-704f-bbf3-3fa956735b52/source.tar.gz"
},
"original": {
"type": "tarball",
@ -968,11 +968,11 @@
]
},
"locked": {
"lastModified": 1737043064,
"narHash": "sha256-I/OuxGwXwRi5gnFPsyCvVR+IfFstA+QXEpHu1hvsgD8=",
"lastModified": 1737465171,
"narHash": "sha256-R10v2hoJRLq8jcL4syVFag7nIGE7m13qO48wRIukWNg=",
"owner": "cachix",
"repo": "git-hooks.nix",
"rev": "94ee657f6032d913fe0ef49adaa743804635b0bb",
"rev": "9364dc02281ce2d37a1f55b6e51f7c0f65a75f17",
"type": "github"
},
"original": {
@ -1250,11 +1250,11 @@
]
},
"locked": {
"lastModified": 1737299337,
"narHash": "sha256-0NBrY2A7buujKmeCbieopOMSbLxTu8TFcTLqAbTnQDw=",
"lastModified": 1737762889,
"narHash": "sha256-5HGG09bh/Yx0JA8wtBMAzt0HMCL1bYZ93x4IqzVExio=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "f8ef4541bb8a54a8b52f19b52912119e689529b3",
"rev": "daf04c5950b676f47a794300657f1d3d14c1a120",
"type": "github"
},
"original": {
@ -1271,11 +1271,11 @@
]
},
"locked": {
"lastModified": 1737075266,
"narHash": "sha256-u1gk5I1an975FOAMMdS6oBKnSIsZza5ZKhaeBZAskVo=",
"lastModified": 1737762889,
"narHash": "sha256-5HGG09bh/Yx0JA8wtBMAzt0HMCL1bYZ93x4IqzVExio=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "12851ae7467bad8ef422b20806ab4d6d81e12d29",
"rev": "daf04c5950b676f47a794300657f1d3d14c1a120",
"type": "github"
},
"original": {
@ -1311,11 +1311,11 @@
},
"impermanence": {
"locked": {
"lastModified": 1736688610,
"narHash": "sha256-1Zl9xahw399UiZSJ9Vxs1W4WRFjO1SsNdVZQD4nghz0=",
"lastModified": 1737831083,
"narHash": "sha256-LJggUHbpyeDvNagTUrdhe/pRVp4pnS6wVKALS782gRI=",
"owner": "nix-community",
"repo": "impermanence",
"rev": "c64bed13b562fc3bb454b48773d4155023ac31b7",
"rev": "4b3e914cdf97a5b536a889e939fb2fd2b043a170",
"type": "github"
},
"original": {
@ -1364,11 +1364,11 @@
"rust-overlay": "rust-overlay_3"
},
"locked": {
"lastModified": 1737299073,
"narHash": "sha256-hOydnO9trHDo3qURqLSDdmE/pHNWDzlhkmyZ/gcBX2s=",
"lastModified": 1737639419,
"narHash": "sha256-AEEDktApTEZ5PZXNDkry2YV2k6t0dTgLPEmAZbnigXU=",
"owner": "nix-community",
"repo": "lanzaboote",
"rev": "64d20cb2afaad8b73f4e38de41d27fb30a782bb5",
"rev": "a65905a09e2c43ff63be8c0e86a93712361f871e",
"type": "github"
},
"original": {
@ -1506,11 +1506,11 @@
]
},
"locked": {
"lastModified": 1736819234,
"narHash": "sha256-deQVtIH4UJueELJqluAICUtX7OosD9paTP+5FgbiSwI=",
"lastModified": 1737504076,
"narHash": "sha256-/B4XJnzYU/6K1ZZOBIgsa3K4pqDJrnC2579c44c+4rI=",
"owner": "lnl7",
"repo": "nix-darwin",
"rev": "bd921223ba7cdac346477d7ea5204d6f4736fcc6",
"rev": "65cc1fa8e36ceff067daf6cfb142331f02f524d3",
"type": "github"
},
"original": {
@ -1588,11 +1588,11 @@
"pre-commit-hooks": "pre-commit-hooks_5"
},
"locked": {
"lastModified": 1735860340,
"narHash": "sha256-8bgRXOHpLmgUHmg6CKFnm6LJzIdInDzE6wO+OotedCI=",
"lastModified": 1737813840,
"narHash": "sha256-XuaDHWeUGsCTvGb+61ztE/6kFPC70ZU2LtBnJvRf2ag=",
"owner": "oddlama",
"repo": "nixos-extra-modules",
"rev": "2502ff50abc8e29606824ac4e67d4a5279b1cb0d",
"rev": "0660c722cf4b703214022a7ca5fbda8a5fe428ee",
"type": "github"
},
"original": {
@ -1624,11 +1624,11 @@
},
"nixos-hardware": {
"locked": {
"lastModified": 1737359802,
"narHash": "sha256-utplyRM6pqnN940gfaLFBb9oUCSzkan86IvmkhsVlN8=",
"lastModified": 1737751639,
"narHash": "sha256-ZEbOJ9iT72iwqXsiEMbEa8wWjyFvRA9Ugx8utmYbpz4=",
"owner": "NixOS",
"repo": "nixos-hardware",
"rev": "61c79181e77ef774ab0468b28a24bc2647d498d6",
"rev": "dfad538f751a5aa5d4436d9781ab27a6128ec9d4",
"type": "github"
},
"original": {
@ -1660,11 +1660,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1737062831,
"narHash": "sha256-Tbk1MZbtV2s5aG+iM99U8FqwxU/YNArMcWAv6clcsBc=",
"lastModified": 1737746512,
"narHash": "sha256-nU6AezEX4EuahTO1YopzueAXfjFfmCHylYEFCagduHU=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "5df43628fdf08d642be8ba5b3625a6c70731c19c",
"rev": "825479c345a7f806485b7f00dbe3abb50641b083",
"type": "github"
},
"original": {
@ -1845,11 +1845,11 @@
"treefmt-nix": "treefmt-nix_4"
},
"locked": {
"lastModified": 1737384599,
"narHash": "sha256-oTmfKi+q5Lxa/zbqxraV/pRbomDASC5SdcBPu+ehP58=",
"lastModified": 1737832569,
"narHash": "sha256-VkK73VRVgvSQOPw9qx9HzvbulvUM9Ae4nNd3xNP+pkI=",
"owner": "nix-community",
"repo": "nixvim",
"rev": "780d3eec7209c7a08a585f5b680ed359ed68e62c",
"rev": "d7df58321110d3b0e12a829bbd110db31ccd34b1",
"type": "github"
},
"original": {
@ -1868,11 +1868,11 @@
]
},
"locked": {
"lastModified": 1735854821,
"narHash": "sha256-Iv59gMDZajNfezTO0Fw6LHE7uKAShxbvMidmZREit7c=",
"lastModified": 1737372689,
"narHash": "sha256-nH3zK2ki0fd5o5qvbGHxukE4qnOLJa1uCzoDObG5vrE=",
"owner": "NuschtOS",
"repo": "search",
"rev": "836908e3bddd837ae0f13e215dd48767aee355f0",
"rev": "570cc17bbc25650eb7d69e4fcda8cfd2f1656922",
"type": "github"
},
"original": {
@ -2087,11 +2087,11 @@
]
},
"locked": {
"lastModified": 1737301351,
"narHash": "sha256-2UNmLCKORvdBRhPGI8Vx0b6l7M8/QBey/nHLIxOl4jE=",
"lastModified": 1737465171,
"narHash": "sha256-R10v2hoJRLq8jcL4syVFag7nIGE7m13qO48wRIukWNg=",
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"rev": "15a87cedeb67e3dbc8d2f7b9831990dffcf4e69f",
"rev": "9364dc02281ce2d37a1f55b6e51f7c0f65a75f17",
"type": "github"
},
"original": {
@ -2407,11 +2407,11 @@
"tinted-zed": "tinted-zed"
},
"locked": {
"lastModified": 1737207873,
"narHash": "sha256-XTCuMv753lpm8DvdVf9q2mH3rhlfsKrCUYbaADPC/bA=",
"lastModified": 1737833281,
"narHash": "sha256-+hCZqNMvcjGinYinsITX+kJvqkEqcWheaNX5WGGcRow=",
"owner": "danth",
"repo": "stylix",
"rev": "51ad2cec11e773a949bdbec88bed2524f098f49a",
"rev": "7c1c3259283f2da9c3d15c9096e7b8864f82bd4c",
"type": "github"
},
"original": {
@ -2699,11 +2699,11 @@
]
},
"locked": {
"lastModified": 1737054102,
"narHash": "sha256-saLiCRQ5RtdTnznT/fja7GxcYRAzeY3k8S+IF/2s/2A=",
"lastModified": 1737483750,
"narHash": "sha256-5An1wq5U8sNycOBBg3nsDDgpwBmR9liOpDGlhliA6Xo=",
"owner": "numtide",
"repo": "treefmt-nix",
"rev": "97871d416166803134ba64597a1006f3f670fbde",
"rev": "f2cc121df15418d028a59c9737d38e3a90fbaf8f",
"type": "github"
},
"original": {
@ -2719,11 +2719,11 @@
]
},
"locked": {
"lastModified": 1737103437,
"narHash": "sha256-uPNWcYbhY2fjY3HOfRCR5jsfzdzemhfxLSxwjXYXqNc=",
"lastModified": 1737483750,
"narHash": "sha256-5An1wq5U8sNycOBBg3nsDDgpwBmR9liOpDGlhliA6Xo=",
"owner": "numtide",
"repo": "treefmt-nix",
"rev": "d1ed3b385f8130e392870cfb1dbfaff8a63a1899",
"rev": "f2cc121df15418d028a59c9737d38e3a90fbaf8f",
"type": "github"
},
"original": {

View file

@ -44,6 +44,7 @@ in
id = 4;
inherit (nodes.ward-web-proxy.config.lib.microvm.interfaces.vlan-services) mac;
};
hosts.sausebiene.id = 5;
hosts.sire-samba = {
id = 10;
inherit (nodes.sire-samba.config.lib.microvm.interfaces.vlan-services) mac;
@ -55,6 +56,7 @@ in
cidrv6 = "fd10::/64";
hosts.ward.id = 1;
hosts.sire.id = 2;
hosts.sausebiene.id = 5;
};
devices = {
id = 20;
@ -62,6 +64,7 @@ in
cidrv6 = "fd20::/64";
hosts.ward.id = 1;
hosts.sire.id = 2;
hosts.sausebiene.id = 5;
hosts.scanner-ads-4300n = {
id = 23;
mac = globals.macs.scanner-ads-4300n;
@ -85,6 +88,7 @@ in
cidrv4 = "192.168.30.0/24";
cidrv6 = "fd30::/64";
hosts.ward.id = 1;
hosts.sausebiene.id = 5;
};
guests = {
id = 50;

View file

@ -19,6 +19,10 @@
./fs.nix
./net.nix
./esphome.nix
./home-assistant.nix
./mosquitto.nix
];
topology.self.hardware.info = "Intel N100, 16GB RAM";

View file

@ -0,0 +1,59 @@
{
config,
globals,
...
}:
let
esphomeDomain = "esphome.${globals.domains.personal}";
in
{
wireguard.proxy-home.firewallRuleForNode.ward-web-proxy.allowedTCPPorts = [
config.services.esphome.port
];
environment.persistence."/persist".directories = [
{
directory = "/var/lib/private/esphome";
mode = "0700";
}
];
globals.services.esphome.domain = esphomeDomain;
# globals.monitoring.http.esphome = {
# url = "https://${esphomeDomain}";
# expectedBodyRegex = "esphome";
# network = "internet";
# };
topology.self.services.esphome.info = "https://${esphomeDomain}";
services.esphome = {
enable = true;
address = "0.0.0.0";
port = 3001;
};
nodes.ward-web-proxy = {
services.nginx = {
upstreams."esphome" = {
servers."${config.wireguard.proxy-home.ipv4}:${toString config.services.esphome.port}" = { };
extraConfig = ''
zone esphome 64k;
keepalive 2;
'';
};
virtualHosts.${esphomeDomain} = {
forceSSL = true;
useACMEWildcardHost = true;
locations."/" = {
proxyPass = "http://esphome";
proxyWebsockets = true;
};
extraConfig = ''
allow ${globals.net.home-lan.vlans.home.cidrv4};
allow ${globals.net.home-lan.vlans.home.cidrv6};
deny all;
'';
};
};
};
}

View file

@ -7,7 +7,7 @@
...
}:
let
homeDomain = "home.${globals.domains.me}";
homeassistantDomain = "home.${globals.domains.personal}";
fritzboxDomain = "fritzbox.${globals.domains.me}";
in
{
@ -24,11 +24,17 @@ in
}
];
topology.self.services.home-assistant.info = "https://${homeDomain}";
globals.services.home-assistant.domain = homeassistantDomain;
# globals.monitoring.http.homeassistant = {
# url = "https://${homeasisstantDomain}";
# expectedBodyRegex = "homeassistant";
# network = "internet";
# };
topology.self.services.home-assistant.info = "https://${homeassistantDomain}";
services.home-assistant = {
enable = true;
extraComponents = [
"default_config"
"radio_browser"
"met"
"esphome"
@ -38,8 +44,27 @@ in
"matter"
#"zha"
"mqtt"
"ollama"
];
customLovelaceModules =
let
mods = pkgs.home-assistant-custom-lovelace-modules;
in
[
mods.bubble-card
mods.weather-card
mods.mini-graph-card
mods.card-mod
mods.mushroom
mods.multiple-entity-row
mods.button-card
mods.weather-chart-card
mods.hourly-weather
];
config = {
default_config = { };
http = {
server_host = [ "0.0.0.0" ];
server_port = 8123;
@ -56,56 +81,37 @@ in
time_zone = "Europe/Berlin";
unit_system = "metric";
#external_url = "https://";
packages = {
manual = "!include manual.yaml";
};
packages.manual = "!include manual.yaml";
};
#### only selected components from default_config ####
assist_pipeline = { };
backup = { };
bluetooth = { };
config = { };
#cloud = {};
#conversation = {};
dhcp = { };
energy = { };
history = { };
homeassistant_alerts = { };
logbook = { };
#media_source = {};
mobile_app = { };
my = { };
ssdp = { };
stream = { };
sun = { };
#usb = {};
webhook = { };
zeroconf = { };
### Components not from default_config
lovelace.mode = "yaml";
frontend = {
#themes = "!include_dir_merge_named themes";
themes = "!include_dir_merge_named themes";
};
"automation ui" = "!include automations.yaml";
# influxdb = {
# api_version = 2;
# host = globals.services.influxdb.domain;
# port = "443";
# max_retries = 10;
# ssl = true;
# verify_ssl = true;
# token = "!secret influxdb_token";
# organization = "home";
# bucket = "home_assistant";
# };
influxdb = {
api_version = 2;
host = globals.services.influxdb.domain;
port = "443";
max_retries = 10;
ssl = true;
verify_ssl = true;
token = "!secret influxdb_token";
organization = "home";
bucket = "home_assistant";
};
};
extraPackages =
python3Packages: with python3Packages; [
psycopg2
gtts
fritzconnection
adguardhome
zlib-ng
pymodbus
];
};
@ -138,20 +144,20 @@ in
group = "hass";
};
nodes.sire-influxdb = {
# Mirror the original secret on the influx host
age.secrets."hass-influxdb-token-${config.node.name}" = {
inherit (config.age.secrets.hass-influxdb-token) rekeyFile;
mode = "440";
group = "influxdb2";
};
services.influxdb2.provision.organizations.home.auths."home-assistant (${config.node.name})" = {
readBuckets = [ "home_assistant" ];
writeBuckets = [ "home_assistant" ];
tokenFile = nodes.sire-influxdb.config.age.secrets."hass-influxdb-token-${config.node.name}".path;
};
};
# nodes.sire-influxdb = {
# # Mirror the original secret on the influx host
# age.secrets."hass-influxdb-token-${config.node.name}" = {
# inherit (config.age.secrets.hass-influxdb-token) rekeyFile;
# mode = "440";
# group = "influxdb2";
# };
#
# services.influxdb2.provision.organizations.home.auths."home-assistant (${config.node.name})" = {
# readBuckets = [ "home_assistant" ];
# writeBuckets = [ "home_assistant" ];
# tokenFile = nodes.sire-influxdb.config.age.secrets."hass-influxdb-token-${config.node.name}".path;
# };
# };
# Connect to fritzbox via https proxy (to ensure valid cert)
networking.hosts.${globals.net.home-lan.vlans.services.hosts.ward-web-proxy.ipv4} = [
@ -168,7 +174,7 @@ in
keepalive 2;
'';
};
virtualHosts.${homeDomain} = {
virtualHosts.${homeassistantDomain} = {
forceSSL = true;
useACMEWildcardHost = true;
locations."/" = {

View file

@ -0,0 +1,42 @@
{ config, ... }:
{
age.secrets.mosquitto-pw-home-assistant = {
mode = "440";
owner = "hass";
group = "mosquitto";
generator.script = "alnum";
};
services.mosquitto = {
enable = true;
persistence = true;
listeners = [
{
acl = [ "pattern readwrite #" ];
users = {
# zigbee2mqtt = {
# passwordFile = config.age.secrets.mosquitto-pw-zigbee2mqtt.path;
# acl = [ "readwrite #" ];
# };
home_assistant = {
passwordFile = config.age.secrets.mosquitto-pw-home-assistant.path;
acl = [ "readwrite #" ];
};
};
settings.allow_anonymous = false;
}
];
};
networking.nftables.firewall.rules = {
# Allow devices and iot VLANs to access the MQTT server
access-mqtt = {
from = [
"vlan-devices"
"vlan-iot"
];
to = [ "local" ];
allowedTCPPorts = [ 1883 ];
};
};
}

View file

@ -1,42 +1,110 @@
{
config,
globals,
lib,
...
}:
let
localVlans = lib.genAttrs [ "services" "home" "devices" "iot" ] (
x: globals.net.home-lan.vlans.${x}
);
in
{
networking.hostId = config.repo.secrets.local.networking.hostId;
# FIXME: aaaaaaaaa
# globals.monitoring.ping.sausebiene = {
# hostv4 = lib.net.cidr.ip globals.net.home-lan.vlans.services.hosts.sausebiene.cidrv4;
# hostv6 = lib.net.cidr.ip globals.net.home-lan.vlans.services.hosts.sausebiene.cidrv6;
# network = "home-lan.vlans.services";
# };
globals.monitoring.ping.sausebiene = {
hostv4 = lib.net.cidr.ip globals.net.home-lan.vlans.services.hosts.sausebiene.cidrv4;
hostv6 = lib.net.cidr.ip globals.net.home-lan.vlans.services.hosts.sausebiene.cidrv6;
network = "home-lan.vlans.services";
};
boot.initrd.availableKernelModules = [ "8021q" ];
boot.initrd.systemd.network = {
enable = true;
netdevs."30-vlan-services" = {
netdevConfig = {
Kind = "vlan";
Name = "vlan-services";
};
vlanConfig.Id = globals.net.home-lan.vlans.services.id;
};
networks = {
inherit (config.systemd.network.networks) "10-lan";
"10-lan" = {
matchConfig.Name = "lan";
networkConfig.LinkLocalAddressing = "no";
linkConfig.RequiredForOnline = "carrier";
vlan = [ "vlan-services" ];
};
"30-vlan-services" = {
address = [
globals.net.home-lan.vlans.services.hosts.sausebiene.cidrv4
globals.net.home-lan.vlans.services.hosts.sausebiene.cidrv6
];
gateway = [ globals.net.home-lan.vlans.services.hosts.ward.ipv4 ];
matchConfig.Name = "vlan-services";
networkConfig = {
IPv6PrivacyExtensions = "yes";
MulticastDNS = true;
};
linkConfig.RequiredForOnline = "routable";
};
};
};
systemd.network.networks = {
"10-lan" = {
address = [ "192.168.1.17/24" ];
gateway = [ "192.168.1.1" ];
matchConfig.MACAddress = config.repo.secrets.local.networking.interfaces.lan.mac;
networkConfig = {
IPv6PrivacyExtensions = "yes";
MulticastDNS = true;
systemd.network.netdevs = lib.flip lib.concatMapAttrs localVlans (
vlanName: vlanCfg: {
# Add an interface for each VLAN
"30-vlan-${vlanName}" = {
netdevConfig = {
Kind = "vlan";
Name = "vlan-${vlanName}";
};
vlanConfig.Id = vlanCfg.id;
};
linkConfig.RequiredForOnline = "routable";
};
};
}
);
systemd.network.networks =
{
"10-lan" = {
matchConfig.Name = "lan";
# This interface should only be used from attached vlans.
# So don't acquire a link local address and only wait for
# this interface to gain a carrier.
networkConfig.LinkLocalAddressing = "no";
linkConfig.RequiredForOnline = "carrier";
vlan = map (name: "vlan-${name}") (builtins.attrNames localVlans);
};
}
// lib.flip lib.concatMapAttrs localVlans (
vlanName: vlanCfg: {
"30-vlan-${vlanName}" = {
address = [
vlanCfg.hosts.sausebiene.cidrv4
vlanCfg.hosts.sausebiene.cidrv6
];
gateway = [ vlanCfg.hosts.ward.ipv4 ];
matchConfig.Name = "vlan-${vlanName}";
networkConfig = {
IPv6PrivacyExtensions = "yes";
MulticastDNS = true;
};
linkConfig.RequiredForOnline = "routable";
};
}
);
networking.nftables.firewall = {
zones.untrusted.interfaces = [ "lan" ];
zones =
{
untrusted.interfaces = [ "vlan-services" ];
}
// lib.flip lib.concatMapAttrs localVlans (
vlanName: _: {
"vlan-${vlanName}".interfaces = [ "vlan-${vlanName}" ];
}
);
};
# Allow accessing influx
wireguard.proxy-sentinel.client.via = "sentinel";
wireguard.proxy-home.client.via = "ward";
}

View file

@ -1 +1 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIC+ziFZSELVG9MmbkMDE9xwKHlm4lnr2uHtVNXk+rTu
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINBDwxSNMyY1EF+xQP+hQ/d/mfK6PapwUWiuDtvealr0

View file

@ -4,7 +4,7 @@
enable = true;
package = pkgs.postgresql_16_jit;
# Doesn't work with plausible, since it wants to connect as the postgres
# Doesn't work with plausible, since it wants to connect as the postgres user
# for some (probably unecessary) reason.
#
# authentication = lib.mkForce ''

Binary file not shown.

View file

@ -108,8 +108,9 @@ in
globals.services.influxdb.domain
globals.services.loki.domain
globals.services.paperless.domain
"home.${globals.domains.me}"
"fritzbox.${globals.domains.me}"
globals.services.esphome.domain
globals.services.home-assistant.domain
"fritzbox.${globals.domains.personal}"
];
filters = [
{

View file

@ -5,7 +5,7 @@
}:
let
inherit (config.repo.secrets.local) acme;
fritzboxDomain = "fritzbox.${globals.domains.me}";
fritzboxDomain = "fritzbox.${globals.domains.personal}";
in
{
microvm.mem = 1024 * 4; # Need more /tmp space so nginx can store intermediary files

View file

@ -1,11 +1,10 @@
age-encryption.org/v1
-> X25519 NIQfcq9fdcwAm3/7bqVw9XKuHxH6r2r7Lbqjjr/u+2w
Cfz/aTYCh4gNWo+dOzDKXNBaAlt0W/aqTb30ho/i5nM
-> piv-p256 xqSe8Q Al+FYiIKhA9B31HjuxCNE65MfYWKIxO+ZefbPsDWljxu
+K47WX1YQpRkvIzR4ALVucSj21YIv9WUluEQ62ccEWk
-> a"CCg7E9-grease ~ &+9|O
fuXdG2v+8S2Bti9ifpvRPfRZfh9ioXzOuYXcPkyPynbQPy2isAksKx83FgQeRoID
VHH/CKTjy/qFCDec9MXX2i9GCWWrva1n2tfOXl9kh2IZ1Zl2te2rsA
--- Tg/N4zk19YF7LCLd9wb95nyQJs0B59SHO4nh76xif0c
ÄíNÑõ9Þ�}òõ¸–wÁÿ2Û Q/çzbC—AuŸÇ{O&âÎiR­ïž,E 1šúë9=Ñ”�íÏÓ‡òM C¨ñìÞñÉæî±pæF:9�=È"‡¼[Èß–6»ò­ŸÁ§‚&}ú3E&%º²ýYŽA´í))¸Ä´Í‡mïË
_³o¯V@U*½Q1ÄȈ_L²
-> X25519 NeZ/7R8+CU7toGb1FkB7QwVloo1McdlWTuCxjN/sK38
WPiUyA6EZgPSu3quzi7X+7kCcye96TT1bTd0VmxrYLg
-> piv-p256 xqSe8Q AiXv0jbX7EQwvBec7xW0GG8dTN1c+bKc+pTyDI/g/srU
l1EaAd6JJYVR5HzJCZqDySb/LyD19sqc7gxR0mKoRjk
-> bO76-grease
HwGf1RlEpc/KEI3vmJwMRSTsZOlukX6hWN4K5VVuuDWh+wxyPD9Sm7cwlzV9p2tZ
XheXpkX3mFHB/ayZL+i48Qo1Fzeti3ZjNMolKBKKRWLqUAGEEVAvJg
--- aEo4S/06W/U+PLhGzF1Ff6f4O3GIqcrH2X+To428ShE
cÍ Ł{Â`V”yŞ�žÍMßÔxň„÷K.łUi”§Oü–Ě,÷)cŽ0f4úéęě�JÔ;gÇ}'ljÝëŰÝNó2oŻ˙vŐÎ ­ß—Ő^ó$0ß°7őáČv Ő¬ˇŐ8p\ěčąäÓ©|äK<rzą*‘Ev.ĂëúD:´)äč~ ő‘9ć- $S‰E>v-Ł }śU>f7b÷Ź�ß°dç7LńŢ»)ÎsÍŔ�ěŁ1GĐď‘�•±qƉîd0G·LÉ�çŹPŢ@ŃĆy*oü

View file

@ -1,61 +0,0 @@
{
config,
globals,
lib,
nodes,
...
}:
let
sentinelCfg = nodes.sentinel.config;
wardWebProxyCfg = nodes.ward-web-proxy.config;
in
{
imports = [
../../config
../../config/hardware/odroid-n2plus.nix
../../config/hardware/physical.nix
../../config/optional/zfs.nix
#./esphome.nix
./fs.nix
./home-assistant.nix
./hostapd.nix
#./mosquitto.nix
./kea.nix
./net.nix
#./zigbee2mqtt.nix
];
topology.self.name = "🥔zackbiene"; # yes this is 2x U+2009, don't ask (satori 🤬).
topology.self.hardware.image = ../../topology/images/odroid-n2plus.png;
topology.self.hardware.info = "O-Droid N2+";
nixpkgs.hostPlatform = "aarch64-linux";
boot.mode = "efi";
meta.promtail = {
enable = true;
proxy = "sentinel";
};
# Connect safely via wireguard to skip http authentication
networking.hosts.${
if config.wireguard ? proxy-home then
wardWebProxyCfg.wireguard.proxy-home.ipv4
else
sentinelCfg.wireguard.proxy-sentinel.ipv4
} = [ globals.services.influxdb.domain ];
meta.telegraf = {
enable = true;
influxdb2 = {
inherit (globals.services.influxdb) domain;
organization = "machines";
bucket = "telegraf";
node = "sire-influxdb";
};
};
# Fails if there are no SMART devices
services.smartd.enable = lib.mkForce false;
}

View file

@ -1,57 +0,0 @@
{
config,
nodes,
...
}:
let
sentinelCfg = nodes.sentinel.config;
esphomeDomain = "esphome.${sentinelCfg.repo.secrets.global.domains.personal}";
in
{
environment.persistence."/persist".directories = [
{
directory = "/var/lib/private/esphome";
mode = "0700";
}
];
topology.self.services.esphome.info = "https://${esphomeDomain}";
services.esphome = {
enable = true;
enableUnixSocket = true;
#allowedDevices = lib.mkForce ["/dev/serial/by-id/usb-Silicon_Labs_CP2102_USB_to_UART_Bridge_Controller_0001-if00-port0"];
# TODO instead deny the zigbee device
};
#security.acme.certs."home.${personalDomain}".extraDomainNames = [
# "esphome.home.${personalDomain}"
#];
systemd.services.nginx = {
serviceConfig.SupplementaryGroups = [ "esphome" ];
requires = [ "esphome.service" ];
};
services.nginx = {
upstreams."esphome" = {
servers."unix:/run/esphome/esphome.sock" = { };
extraConfig = ''
zone esphome 64k;
keepalive 2;
'';
};
virtualHosts."${esphomeDomain}" = {
forceSSL = true;
#enableACME = true;
sslCertificate = config.age.secrets."selfcert.crt".path;
sslCertificateKey = config.age.secrets."selfcert.key".path;
locations."/" = {
proxyPass = "http://esphome";
proxyWebsockets = true;
};
# TODO dynamic definitions for the "local" network, IPv6
extraConfig = ''
deny all;
'';
};
};
}

View file

@ -1,29 +0,0 @@
{
config,
lib,
...
}:
let
inherit (config.repo.secrets.local) disks;
in
{
disko.devices = {
disk = {
mmc = {
type = "disk";
device = "/dev/disk/by-id/${disks.mmc}";
content = {
type = "gpt";
partitions = {
efi = lib.disko.gpt.partEfi "1G";
swap = lib.disko.gpt.partSwap "8G";
rpool = lib.disko.gpt.partLuksZfs disks.mmc "rpool" "100%";
};
};
};
};
zpool = {
rpool = lib.disko.zfs.mkZpool { datasets = lib.disko.zfs.impermanenceZfsDatasets; };
};
};
}

View file

@ -1,43 +0,0 @@
{ config, ... }:
{
# Associates a mandatory and unique password to each client
# TODO: autogenerate? via secret generators and derived secrets?
age.secrets.wifi-clients.rekeyFile = ./secrets/wifi-clients.age;
hardware.wirelessRegulatoryDatabase = true;
services.hostapd = {
enable = true;
radios.wlan1 = {
band = "2g";
countryCode = "DE";
channel = 13; # Automatic Channel Selection (ACS) is unfortunately not implemented for mt7612u.
wifi4.capabilities = [
"LDPC"
"HT40+"
"HT40-"
"GF"
"SHORT-GI-20"
"SHORT-GI-40"
"TX-STBC"
"RX-STBC1"
];
networks.wlan1 = {
inherit (config.repo.secrets.local.hostapd) ssid;
macAcl = "allow";
apIsolate = true;
authentication = {
saePasswordsFile = config.age.secrets.wifi-clients.path;
saeAddToMacAllow = true;
enableRecommendedPairwiseCiphers = true;
};
bssid = "00:c0:ca:b1:4f:9f";
};
#networks.wlan1-2 = {
# inherit (config.repo.secrets.local.hostapd) ssid;
# authentication.mode = "none";
# bssid = "02:c0:ca:b1:4f:9f";
#};
};
};
}

View file

@ -1,54 +0,0 @@
{
lib,
utils,
...
}:
let
inherit (lib) net;
iotCidrv4 = "10.0.90.0/24"; # FIXME: make all subnet allocations accessible via global.net or smth
in
{
environment.persistence."/persist".directories = [
{
directory = "/var/lib/private/kea";
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 = {
interfaces = [ "wlan1" ];
service-sockets-max-retries = -1;
};
subnet4 = [
{
id = 1;
interface = "wlan1";
subnet = iotCidrv4;
pools = [
{ pool = "${net.cidr.host 20 iotCidrv4} - ${net.cidr.host (-6) iotCidrv4}"; }
];
option-data = [
{
name = "routers";
data = net.cidr.host 1 iotCidrv4;
}
];
}
];
};
};
systemd.services.kea-dhcp4-server.after = [
"sys-subsystem-net-devices-${utils.escapeSystemdPath "wlan1"}.device"
];
}

View file

@ -1,36 +0,0 @@
{ config, ... }:
{
age.secrets.mosquitto-pw-zigbee2mqtt = {
rekeyFile = ./secrets/mosquitto-pw-zigbee2mqtt.age;
mode = "440";
owner = "zigbee2mqtt";
group = "mosquitto";
};
age.secrets.mosquitto-pw-home_assistant = {
rekeyFile = ./secrets/mosquitto-pw-home_assistant.age;
mode = "440";
owner = "hass";
group = "mosquitto";
};
services.mosquitto = {
enable = true;
persistence = true;
listeners = [
{
acl = [ "pattern readwrite #" ];
users = {
zigbee2mqtt = {
passwordFile = config.age.secrets.mosquitto-pw-zigbee2mqtt.path;
acl = [ "readwrite #" ];
};
home_assistant = {
passwordFile = config.age.secrets.mosquitto-pw-home_assistant.path;
acl = [ "readwrite #" ];
};
};
settings.allow_anonymous = false;
}
];
};
}

View file

@ -1,94 +0,0 @@
{
config,
globals,
lib,
...
}:
let
iotCidrv4 = "10.90.0.0/24";
iotCidrv6 = "fd00:90::/64";
in
{
networking.hostId = config.repo.secrets.local.networking.hostId;
globals.monitoring.ping.zackbiene = {
hostv4 = "zackbiene.local";
hostv6 = "zackbiene.local";
network = "home-lan.vlans.services";
};
wireguard.proxy-home.client.via = "ward";
boot.initrd.systemd.network = {
enable = true;
networks = {
inherit (config.systemd.network.networks) "10-lan1";
};
};
systemd.network.networks = {
"10-lan1" = {
DHCP = "yes";
dhcpV4Config.UseDNS = false;
dhcpV6Config.UseDNS = false;
ipv6AcceptRAConfig.UseDNS = false;
matchConfig.MACAddress = config.repo.secrets.local.networking.interfaces.lan1.mac;
networkConfig = {
IPv6PrivacyExtensions = "yes";
MulticastDNS = true;
};
linkConfig.RequiredForOnline = "routable";
};
"10-wlan1" = {
address = [
(lib.net.cidr.hostCidr 1 iotCidrv4)
(lib.net.cidr.hostCidr 1 iotCidrv6)
];
matchConfig.MACAddress = config.repo.secrets.local.networking.interfaces.wlan1.mac;
networkConfig = {
IPv4Forwarding = "yes";
IPv6PrivacyExtensions = "yes";
IPv6SendRA = true;
MulticastDNS = true;
};
# Announce a static prefix
ipv6Prefixes = [
{ Prefix = iotCidrv6; }
];
linkConfig.RequiredForOnline = "no";
};
};
networking.nftables.firewall = {
snippets.nnf-icmp.ipv6Types = [
"mld-listener-query"
"nd-router-solicit"
];
zones = {
untrusted.interfaces = [ "lan1" ];
lan-interface.interfaces = [ "lan1" ];
lan = {
parent = "lan-interface";
ipv4Addresses = [ globals.net.home-lan.vlans.services.cidrv4 ];
ipv6Addresses = [ globals.net.home-lan.vlans.services.cidrv6 ];
};
iot.interfaces = [ "wlan1" ];
};
rules = {
masquerade-iot = {
from = [ "lan" ];
to = [ "iot" ];
masquerade = true;
};
outbound = {
from = [ "lan" ];
to = [ "iot" ];
late = true; # Only accept after any rejects have been processed
verdict = "accept";
};
};
};
}

View file

@ -1 +0,0 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILaKQa+gcGMvtm9d1LM11lvsXRtE3Tvo+o40nG+eXYgo

View file

@ -1,11 +0,0 @@
age-encryption.org/v1
-> X25519 tE4e6O7Qv5OeZYC9hPYaN7SdCDq1Nl9rYBkGfKHo2XM
b7c3Hwfvm8GmRjpe/0I1FbADK6S5ZI9axR7cLO9kja8
-> piv-p256 xqSe8Q Ar49h1MV117LH71oyK7kkBpKJv4t1XyDrNxWOK6cAMTL
xkQzAhG8snR+B+Bzv1OIYScslCN7yKk2iMvWH/WyRm4
-> `G&J4E-grease 5AwMc]> Tgl>j1Z:
GShgbkXFvntIBUbz2aSg4QHWdLvyxSg
--- tAQKeRaBrOxd7wnnfMn2M36WlqzFFl7GZxak7wUkg+s
öc“ß?›"e’P»r]î>Ãùæ—%�(æ’)ÛÓŠIÃÎBÁ ù
ãnÜ‘ÈI¸Ž…÷gA´¹vÚûÊ®ºg¦ç9wVFæZ«‰ñ‹šrŸÓ4Û}1ãQZšª3øõ1‚€”‡ †Ù§[ÔúÑSËä$‹�Ÿ}j÷á_V¿SeùÈ+ �ºH/
…bLYU²Œi·«¦ÍaýÕYËÊ|hñ�8TrÜ-íø;ý'„Y~Ë/'ðïÆATQŸï7®Æ¨{{x�X`õ&çqH“hw³¨�Øxvr"¢ëhSXYŒ¼9�fï’¸#,# ÐÅöUƒ[KI™Æœ:•jè7¥=žWHÂ/¦'C a°Dqœ‡¶™êüm$`?›j¥ñŸ%›¯:

View file

@ -1,11 +0,0 @@
age-encryption.org/v1
-> X25519 fnG14tqQJow7aCttB48iukNYbIENNYSCOdnGmzsUR08
CUgbzHmMTVDjVvwXoJ1Li1HJuCQcexOwTA8vyI1qBy0
-> piv-p256 xqSe8Q A2lUZF0cZPhAduYPGQg/vrpLPVidJQuIXMh1KCIw2fJu
SVtOdeJXECGJtNsJkDGnrljvO1xWqmCueMS7dISppP0
-> 97L6-grease 9 Uv0 :8=|&
5sV9Y2boLn0oRELbKB1PHp/1YbofZfNprKwUjrcXHTl2qsc02mVOVGBcoghUg7qa
z99fVBeVj+nR/E6In8lDKR7mUf7ZF8oHxIDEGQcQ9hysO3jbWFA6CMH48h9ICcen
hEI
--- gP2qI8vwLWirtwKRpx3iyNc+MUi03qQ353vfzxjYA+8
RN¯±c<�’{rÏ2_Zèj|žÆAõ.�ê*=9C‘öÈÞ¸qp‰Ê•/PÓ@¬ÈO-± 

View file

@ -1,62 +0,0 @@
{
config,
nodes,
...
}:
let
sentinelCfg = nodes.sentinel.config;
zigbeeDomain = "zigbee.${sentinelCfg.repo.secrets.global.domains.personal}";
in
{
age.secrets."mosquitto-pw-zigbee2mqtt.yaml" = {
rekeyFile = ./secrets/mosquitto-pw-zigbee2mqtt.yaml.age;
mode = "440";
owner = "zigbee2mqtt";
group = "mosquitto";
};
#security.acme.certs."home.${personalDomain}".extraDomainNames = [
# "zigbee.home.${personalDomain}"
#];
topology.self.services.zigbee2mqtt.info = "https://${zigbeeDomain}";
services.zigbee2mqtt = {
enable = true;
settings = {
advanced.log_level = "warn";
homeassistant = true;
permit_join = true;
serial = {
port = "/dev/serial/by-id/usb-Silicon_Labs_Sonoff_Zigbee_3.0_USB_Dongle_Plus_0001-if00-port0";
};
mqtt = {
server = "mqtt://localhost:1883";
user = "zigbee2mqtt";
password = "!${config.age.secrets."mosquitto-pw-zigbee2mqtt.yaml".path} password";
};
# TODO once 1.30.3 is out
# frontend.host = "/run/zigbee2mqtt/zigbee2mqtt.sock";
frontend.port = 8072;
};
};
services.nginx = {
upstreams."zigbee2mqtt" = {
servers."localhost:8072" = { };
extraConfig = ''
zone zigbee2mqtt 64k;
keepalive 2;
'';
};
virtualHosts."${zigbeeDomain}" = {
forceSSL = true;
#enableACME = true;
sslCertificate = config.age.secrets."selfcert.crt".path;
sslCertificateKey = config.age.secrets."selfcert.key".path;
locations."/".proxyPass = "http://zigbee2mqtt";
# TODO dynamic definitions for the "local" network, IPv6
extraConfig = ''
deny all;
'';
};
};
}

View file

@ -0,0 +1,10 @@
age-encryption.org/v1
-> X25519 UG9H+S0xpI/Vyou1YbuXyKMX24d19qjVX9GCDXLVbxE
LWCN9OS+DtTk0mXXQw0EHlZ6lOiucQVMJgPfujMCfLA
-> piv-p256 xqSe8Q AssJIIYkvCxgdCsTawal3/2iurumqH12qE2Z2ttHoWfc
5sUZ1UWpHctujljDPdGWD/WYt/NhJ+GJAZkXBn+ae74
-> en?Kc)P5-grease
e0CbpB/vNL73y5YW9Obg4UhwinAgWti1eqFZ
--- sg68VBPPfwBX/CH4V9S0+7C5J6k7dJASqtU/nV3Vgxw
Ü�Â×m§eAÓ$33”½‰|þ3ˆÅs&i9?g/QzWÍm„
—µ`ç9) ðN,î›în`¢«)Ršíí.Á8íhÈAžK ™\íg˜ž

View file

@ -0,0 +1,11 @@
age-encryption.org/v1
-> X25519 yDlbl9rQn8eSWGxhRgbbZnNCbVqI5otCFcpXkT/rxBY
/NcVIWnuVRgFjDuA+k31O1BUTWTXqeznhryn4ZNS3yc
-> piv-p256 xqSe8Q A0pQxoQ9oNNIvh6u7RKniS0XdtKpfgBSVTqOXk7m0ZF0
v91naiUeD3119teCxIiZiWg9OPnC52H2ljKVm41lPbs
-> 'QwT}-grease gz@~<
A4gPI7r8iA3pf8w+oQ3/v1k7QtyaAOQI+7h89bqi5USqNO5HIkykCt5qq2yRQCu0
uxKhCljFEjzJ8XxADDLmSgZFSw
--- Xrl4JEBgbG6NbfbebA/NkTh9voRrinz6U07Tr3PJiz4
玽2q殻w'B~Z{Y?=ルrオッタlカ筌76az頁>R)燿セヨ゚シタ�ク 陦ヌモ} �h籔ワ勲ブ│ghxW∵椏
ユ

View file

@ -1,7 +0,0 @@
age-encryption.org/v1
-> ssh-ed25519 lOtryw w1iYfdtWut59MAfBBPuvFt4dO+ESWN3TJBpVZ8aEWWY
HMcpeizp/s38w6Gc1lww51B2SIRnqow2TrssPK7+0Rg
-> ,J\-grease 9#8Z F/xcB#; bX$ z/
0uWc4Xf0m+BXvFlUDirseOsYmdrX3A/cdh07qAs
--- 3TRrD3GWIzIOxbISgTHBT9+ko1SMA5HMPK1kmt3UzoU
SÝÐoÔ§zq²]ú˜¸t¬GWB%ŠåÌ ¸®’àÿüÂïÙ4³7/íñK÷¯3©?lM>¿ÓÔÔ÷>`Õá<¾ãbì¡mlƒ©’ú÷N

View file

@ -1,8 +0,0 @@
age-encryption.org/v1
-> ssh-ed25519 lOtryw aT/nXWhbjH9MI8TPh7ssbJD2ROFgu88TAUAOS2WDxHY
4pt8KmP6os7i5bLQiQoWUXDDUM17LJQn0RMDG66yBv0
-> F,g{i-grease ?%#)@ zA"s2 nw-2mc*(
dA
--- JezLFhE4AcS1E8TcDlKZNSNncwC8AzEbWPxBM9a1BYs
‘‹û÷ÖÏÕéä£_�Åd¿DŒ6C3á©1/$cà‰UKÛ©bsb™8H9TȾe度P¼øú’%úl»w•_Å7Rãäò
Ñ�'ýì Ñ3Ž

View file

@ -0,0 +1,7 @@
age-encryption.org/v1
-> ssh-ed25519 1JqBOg q7moiRexLIlGgAxtyJcPaPS5Zfeqmxxk/4Es+PmL2k0
gWceWwHMIXGz5OCP7K5aPsyshXwTZOjtZvSpuUcNS4s
-> A.&-grease C`D }#P*_&r
TR1jOgFyucmKj45EbC554F8
--- H7qFUFQRnuaI7TrJPoGhBNGZz8QcUiYFBdFeidHRWqs
§¨Æ1—¸è§fJÄ^›7Ûr«â¦pz.�Ú$j¿ôOy#ýAàGþN³¦qãN™aãE¹œ6‚­(©·[`‰- ÕªD}èƒòöVW>Tg‹POOä

View file

@ -0,0 +1,8 @@
age-encryption.org/v1
-> ssh-ed25519 1JqBOg M+KGvzO5sOst3XBm9Rh1sdmEszJdIcRgU6K1ntg1d3Q
ASREfivGV9iIbc2U0HO6g5RTJfz06wzHErZAtm1PkO8
-> ["-grease ({U~x a$TW&
p9cO/xzvEnpWuUk1TqYOLcPZGKmBaW+EQIsTOvA9TsauzVkEl1yhwa4OhQkx/Eyr
kBDa5A4Vss60LW7l0OlLgqBYrP62JIjW4YFDCLnbGdiqKVzNURVNDGg
--- NjOZYDOvqJse5yKaF+IkYBckPRrUcc+alQoLG1jrVJQ
¶5ą.çó^�ť}r%€L™Gi6/tšŁÍC(=\”iÁ{Bßš›§OŠ˙k/ŤfPŘ˙źkśôÝĄé�˙yhG¨¦çrź’; }N¸Ůu

View file

@ -1,7 +0,0 @@
age-encryption.org/v1
-> ssh-ed25519 lOtryw Ca03hL7k4AtTfrDQmUb/g3Sr1yi56jk8eYD+4XOz6g8
GFYSiZ24vLsiK5qCVvKF28kWxWWhuno3+OIRTp3h7kY
-> Mrcg#(J-grease cFl0 >I gLKrt
aLXwsplsL40EqXV66Pk0V8rehw
--- 5HFB3WTo33gngrI1hMj4f7ktprlLCEVXZKkjhW/ReSg
j¸A>¬éß³´jÖÌW,•ʸ—OŽëΕ Ió%X²…£ƒiã•\.¬Íh/AaŽ?b‰Üná÷ñY =É1¦ðzKöëÅ¡BJ¸.Í9sv

View file

@ -1,8 +0,0 @@
age-encryption.org/v1
-> ssh-ed25519 lOtryw /A1dsOKjndYa/t1/LwhsFCToaScX5ZteViRmepMmeSs
7SCvSxmRzw1jbKp8P1aky3zsg+bWBIQI7eq/nI9ZrvM
-> 424'-grease 72cu]< I /
rZaO0zYGx6Mkkm20o74jEnuRng
--- GwTzHpKa38XPKJ3Ciz2fDjN7BWXuEQrJG9KtPJsD7jQ
x+õ8æÕݹÈQ ú –£—7'¨�%im9�m²=¢‡mêœt½‡wó݈ô«èD:ò5}^¾Ü2Ë‹P@Š${ä.7ÄV¢›ov³)Ò’JR0 ÅÍÁt²kìÕq¾©*ƒOÏ=\#�°(^lçM¿ß³èVHNŸ¶XÂ�q9þe:Óž�ô`y¼6¯ïk»CÐ>ºlwÛQœÝåàúÎ.²káb$¸Éi¿ÖÆd¸æîÌHatƒ�+ĉ“¦:='´+4ÑH»ŠÈX}µûØÔµÁô�Yr?†á ɈOd \SÙÛ-Ídk蜇×Oâ×Ù� ¢h—ý \±˘É?A²“‡"O¤ïÇ£ŒÌí%&h2“îáŒÎ ;à,Ý�¡k!¯l¸8'’/üºá‰Aê+ƒ�¾F7é·¦™Ü"€÷ÆF^¶àHåŠ"ŒBíÅðúÛ‰ÌdÂ_¼vPhm(ƒ;6ÎS¯�ÅáÓ›UGà߉ñ€šCƒÜ=ïunCq¡®¥ƒ;‰c�^3µ\·, GâöÊÖ>õ@™½~}ò4šÄ'µ’î!Áe¥~«É'ÿ¤–±Ü(E/«¬R
¢£ñqIš²®P¹†ïxÔðe¿

View file

@ -0,0 +1,7 @@
age-encryption.org/v1
-> ssh-ed25519 1JqBOg XGoPFeeWomE86ee08wi6w3QAy9IsNkaQCTvOKU3iWDE
d78DsCqzJ+0e3OO7ucLGh4eLWiheaMb1qAieUdWB3Co
-> "{%-grease ;\givGMk =U JCq/$.2z
tlA1q3ATXgUkALoiwhaB
--- aSVHyGQSTxu3aCYwzy073tEY9DuNolQ8zSjhhgAbP6c
`˜ˆ'¼ÂŒ,²ÇÔ%׋9|þ^×íÄs CõŽV7.uC³Ǩ&õ†\`u/{xÌåÿ¤^j^7º»Òâ/ëÉ]ˆ›ÿ΄.‚=1

View file

@ -1,7 +0,0 @@
age-encryption.org/v1
-> ssh-ed25519 lOtryw 4pz2uwU94ttWbvcVLG8h6o76B5uIAVP3E9SDtzHUumA
spuEeTgU3vudaS+HTjyNfZPYIaOuv3z/CLKoYMy+GiI
-> j-grease , \3 Yq!<2i
FzJ0b/2/1pCPyy/GjQ5E1eOKkS8PrdCUAQVV
--- 1HYTaKU8uzFyL2tqpGehK0cNJMpYiSEGLj7GDcZo9OQ
RqÀ‚E yŽ·áç_8Ëâø~Eþú°¢:]aÁÆžŠÝ AÁήÑ8fz֧ݥœà4ÜÍæ„ŽwÃÀ�‘Ý‘‚FPb¹�áE…Fï&Þ¼

View file

@ -0,0 +1,10 @@
age-encryption.org/v1
-> ssh-ed25519 1JqBOg odhTtbudrOK59V0y/conILmZ8RXC/bgaIsgcKX6+4Xo
havbGQgB3Sw8GCl/JpXp4ahRT7jtGCtRrR1RBL3+g2g
-> .m;fR}?5-grease :*z3u
BBXlnqv5Tx118ObFowzxuy2JvhWx01yXAUQhh9R6amR/pCXF5z10F5YeUS/M+1vt
v9zzsFzN9fCtwxdt8r18Wmc4di/Jlw
--- jRhoXaZSZ/LOYww54bSkAIGn/m7OaLGWPK4FnTB80cQ
ùÀe ³u»”
tëxí#Ò-8uì°¦t¬lª„CpVL —;‹ÀžöÚ`±�dÞe×]Ä9�~
t p¬Sº¼Kèå—x®ge÷`]d

View file

@ -1,7 +0,0 @@
age-encryption.org/v1
-> ssh-ed25519 yV7lcA TbUU7Qe1joDj9Vz7R0dnhBiTE8/D+EcNF/y7p5lEjn0
A7kwW/AOVy7wB7RYnSP11QIYxhiOrODgEl7AwAM1hqo
-> Pa;1-grease wep< ?nNq sM7#ln+- 4U3*y,6>
9q3AkZ8bOWDiSg
--- vaag5FKw+gm/7ZZs2TtvCcWym2A5glZrHVmcd5OgPNM
k=oCnj9¼9ÐwÇzφÑÌ ‡´Ç?Tþÿ5柭VM¶óaÃç¸>¸áÕ9®OõDƒE““ãø�#pgSç ™}-?”o^Ü

View file

@ -1,7 +0,0 @@
age-encryption.org/v1
-> ssh-ed25519 1tdZKQ 7hRaB/jl5aAQ0OaLaE84invNGJc4iuzxk/jGA7cxMS0
nKH9M7KqbC2yQbjRY7h9yeCUPjii/PKbaArv7vF0tgs
-> =Bq38rC-grease |< t'@ f
WX5ZG96lJs4zzi4
--- Msg4tXQbL4PdKR//oobUKg2lvMAp1IZgimw09W6BnK4
Î ýhÄ}ª@“hÝ4[ðœñ­ã¢Ø„=RýJ`O3ŠÍÐulàbÎ’í쌣⦫zÌUBÙâµ¢Íìĸ/]¦i¢-—®ë³ª±ÅN�

View file

@ -1,9 +0,0 @@
age-encryption.org/v1
-> ssh-ed25519 1tdZKQ tq3KnNzqtWpWxhvgRCtMWs4Rkw+N0wYBkubwi1aS4Cw
VcgxThQS7G76TPaMZeY56gBwxWYx16rrHjek3XzU8qw
-> y"`K:H}%-grease DgYWO P'q< Z^L^JEA
oK4hdyQZ5mfpNOuuxxiS1EKdIm1ALSUrxOrMAXVdGiCbSKpaAMSnVc770TI1g9aU
T2Pn
--- nqnFYa5KoFz5V5DxB+wG6jGZer8c/lZcymvAnywXpf4
¯]}Á IY$!unJ°)êmKi·¸(¨‰7h÷‡øu˜©דáò·ô[+eÙÅP0y‚sûÞØI(¢CÙ¤C‡£Æ+ÿ¯H
�Ö èmyÖæÊ

View file

@ -1,7 +0,0 @@
age-encryption.org/v1
-> ssh-ed25519 iNceIg iTd9PnSEFe5Zzwld5E/onR2xtvNRF1vs8uNAuiU21FE
8id5IERQSvIiVjEIuZ6uFrO2aLGtLD3TiGUqZJIZ4UA
-> ZLaW2-grease
OGBoLHKqHfuUnly0OEo+sSj20yKrrQ5U+xH5gBZ9ZA
--- 71by0nesi0wWF0q1HgwTlvnZL6+rC24oxGZ1ogmer9E
ºï3T—Á™ÈõD # §§‰m—«-áë³”Àí´7²U:öÂl ±Y›ÌÄúuÄÆÈ`ÌØ¸Ž•«Ðr_KK+€é$xP¾&ƒ”[/‰h)

View file

@ -0,0 +1,9 @@
age-encryption.org/v1
-> ssh-ed25519 iNceIg cKEtiheAFHWAs3EOoKo1chX3RWhz6aq5cRTwZ1/Z1WU
Tdbo+qNWIaycZ2omOLs1F3m81zCDJkRT6WomuYeDRrA
-> _i/oVPFQ-grease < dNS%z; `=D/: |u(y
+8oPOeTNfm3rVJdLKR5kMkN5uVwIsQt2epywa2B0DTMQmxc0MZ3rTa8H4ojiMUi/
ZXYwcffbbYxeCYb0IFWlalJ28zk/sYQPhe1JgNI70w5DT6VuEOHg+A
--- bw0j98/E8Ldp7T/16SQGGjoTGClzYNqPzAd6k4jcjvE
‚š·£± ©¬‚ =0}è_‚áä]“øžá;âŒTz±ù&:5i²œEçR°•¹1Çi¸N�Ê‹pñ¡™�U!D*ìzÏZÿ]šQÝ

View file

@ -0,0 +1,11 @@
age-encryption.org/v1
-> X25519 M9VlOylObbteCXZZtTtwitgmFOZNoZfIiTMRhP4ltzo
iiaeU2XZ/Fiwk+ZS8FbRKCcWABls1gkF/E/qoYPEkRk
-> piv-p256 xqSe8Q Ay2M8wNIe3AKcPy4iIxECA6LMoQKzbPe67jLfFuCpf4x
q8jQ3XP1nFYsfqA7QhGH65NPkmGfiii31VuJtlGC+0Q
-> bo?-grease
OS3X7bwub+E85sXZtogYp/hE9zpSt47/PaYaFtSQLCAZmsYd659GYdXWP9MYReUE
lW3593s9ke4hzJl+oAh7aHwUtr0GW3WT/+H7NSFVjuca5+yvgvx6psb/82hsjyM6
JQvE
--- 3Yf1OvQITDE1BfriGCa+uK1Y9watIjybbthHKo+sTJk
уZÓXy�t)Íf†¿d½ß‰¤y£ƒ„ ^| bû¬^Å™ ¤&U¼W4&ãÜyvïpŽy݇jî+ –»êþL6¢_‰äÖ%pÌæR

View file

@ -0,0 +1 @@
rV7gk0n3DVZmRj/qQHv9dJ4gH7v1FZ1Gat+Srm9k0S4=

Binary file not shown.

Binary file not shown.