feat[server]: serve home services also from home

This commit is contained in:
Leon Schwarzäugl 2026-01-05 04:19:08 +01:00 committed by Leon Schwarzäugl
parent c1c7431891
commit 375dc83404
51 changed files with 2740 additions and 3289 deletions

View file

@ -20,7 +20,7 @@ keys:
- &winters age1s0vssf9fey2l456hucppzx2x58xep279nsdcglvkqm30sr9ht37s8rvpza
- &dgx age1ax5hqk6e2ekgfx5u7pl8ayc3vvhrehyvtvf07llaxhs5azpnny0qpltrns
- &hintbooth-adguardhome age1c2enwel9un28dcs4wg0vcyamx9a4a6g3walkhu8w5lqhmd804paq9d24as
- &hintbooth-nginx age1c2enwel9un28dcs4wg0vcyamx9a4a6g3walkhu8w5lqhmd804paq9d24as
- &hintbooth-nginx age1nanlervuderw4qskcuessycqy2yfmptl6nym9scgp9ky2265ssmq3u73r0
creation_rules:
- path_regex: secrets/repo/[^/]+\.(yaml|json|env|ini|enc)$
key_groups:

File diff suppressed because it is too large Load diff

View file

@ -61,7 +61,7 @@
postgresql = true;
attic = true;
garage = true;
hydra = true;
hydra = false;
};
}

View file

@ -4,53 +4,53 @@ sops:
- recipient: age1wmx8y2hs83j2u5srdnfxljrzxm8jtxl6fr0mq7xf2ldxyglpzf2qq89rpx
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBBMEM4alliWlBCT3VsbVA5
OGt5bmQvZW1TaUNkbWtFdzVGNDNpY0hBOVhzCm84TldYNHBrU01HMlBkbGNwZFAw
WVk0T3FycVRHUUNtM1pTYkQ4Qmw3RTgKLS0tIE9LUlNEVjJHOGVIK1RSMmRXUDF6
QlRKY1hRVzNTVXhESUd3OElXL2pBZXcKDWYoOzi2b4qeIbCVCfTj0lTW+OfbnsXB
8MugCHu7+b+ju0v/lUP66jDW9/2AH4PzHtCNHjsafyzr2qnW8HlOzA==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBySStkZDlPL3JYTFlYVXVD
VGx0U2xxeDNXcTdwaFZsRWZoblk5eEttZWtNCmJQa3NvUHNwYmFZUG8wMlNxWE8z
bkcvNTNhWnozV2Y4Wk1lZmhmMDdEZm8KLS0tIHBkalp0M0NuU3JQQ1FMRmJNQlJX
Zlo4akUyVW0yM3FLNG9jQnBHY1BQN2cK48vxR3pPY3LJlTIEx+dy3ZZRfwFyvQGe
EuUI7TuLa0ib8JnO287Ay4gp3GH38jtkGcux4yP5Q8eY/M9GNlEK8A==
-----END AGE ENCRYPTED FILE-----
- recipient: age1c2enwel9un28dcs4wg0vcyamx9a4a6g3walkhu8w5lqhmd804paq9d24as
- recipient: age1nanlervuderw4qskcuessycqy2yfmptl6nym9scgp9ky2265ssmq3u73r0
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBJRWJXR2tYdEd4cTZsSi9l
Tm1pSC9pek5BakpEMlkwVTcrMlBuVzlXWUVrCmlnV0xJc25nL0twK3VCZ3FRK2x2
RW52Q1NxWUhTUGY0NnQ0WEhLMWxIcFUKLS0tIG83eVM0KzdLQ004aDRKNTYvdmVZ
d3ZOSStBMFpSU2ZjNWhFRkREQWlUdmcKggVvLy1mLYGf8084RQtlipS4+z4dfPsN
HZfid0srwYnezlQ5qOY8/HrDLWHEyuZ4xFZVi4n0k49qBpNwJdmvyQ==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBHTmFTbmNBWldmY2FGSThG
K1E5b1RTZE5NTll6WkZvbDhxaUk4d2N5bjNBCm04YkxSTE1FdFNFMGNFREtRbFVE
MHFuT1VONzUxcVdoK2kvUFRkc2xXbFkKLS0tIERlWE95MXVnVWk2Tk0xdG1EZUIy
cEdOaXNUQmt3KzUvZmRJWkpTdVpHdW8Kv64ZWzQbpmINagumpuHXscRf9stxO4Of
DSkGxFyLgq7yDg1iaiWy/mwxQZVw5i4ieR2+VDgi6Web2y6t81jayw==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2026-01-03T05:23:18Z"
mac: ENC[AES256_GCM,data:u9N7GzLPDW7cHT4mkUAC9Diq1RdV5iSwcz/fqzXQKRmic09eVydAgyk2g6NbJ+4tBbAjIfeUch8Bhf5eG0sGzeDkb1qWAMEnP8EPmQ64OdRyN2SxJgxkc8KFGxkrGz9slS2ozWth6q/tKBSsOYbo8WDlCqXhmYp+zBxvYFR30Mg=,iv:HC1e2i0E7dV9/au+A0kHd+UXDhw3xf7RbTpwJI+hjpY=,tag:dPCDh9qalNtbHIhs//cBpg==,type:str]
pgp:
- created_at: "2026-01-02T21:12:51Z"
- created_at: "2026-01-04T23:02:15Z"
enc: |-
-----BEGIN PGP MESSAGE-----
hQIMAwDh3VI7VctTARAAmvkQ9V14f0BT/bNdFVZtTlY4yVon37CX32SZPUcHV7o8
Dya0sZd9tuVATSv79TnybscuNx95fkoZJwujBfAadexn2zY8zl1oEWEHx7p+8/mE
W8JbQAjbcbX9sNQYXc8kYJylBThmgNN/HXK7CGtgDFr9xnGzDBnDm/M31P1HwYBm
IdIQgFGErEt1K3xvw28Lk3tPuZLK3Y+H2Yna7RRF6K1blGJUvEnL6yFdA10/eFW7
8066mO26F2l5xFuktK0nNeniLHKa5VVYp8iM+JMhX38l0wiIi8pGyxo3uAjNpa0w
IfpCneEBe/yyaUPcWMjXmUG5LJe3kWUup8cSzvu01Z3W159/QsflxIMkIsklqhim
B2zuPdAlYsjjS/05DIHInN2IIB/rjADkQvXji1XYLhWJj4jxDeck/UIc6Q22TED+
autlbl8d/5sqyO5ghPpShF/s0vMTqUfpXZrDrbuyDFqCfwi0ahP03bUsv20ZEz6u
zG3K5HuXHh7ATSppwuMbcv7vcjF1tkbo6XhWZDv0rY0DFWqiYhnxWwlFlGLxf4zX
g6r7Ca/E/YXG/eOET6M9DxwHjj0D7u/ryAkCktqPL9w8oNGarZQ/xMx0+ocI3byc
Zvzlmd63BtgaGNSxH3stK29KN3ED8cDkG/JzAxCATWiUBBkqW/ga4sGZqtLlSO+F
AgwDC9FRLmchgYQBD/9JbFZie25PO2CyELlUWm5SmJcugT9SK/mIA2fe1PlA+Gnf
5z9iXraMSQchz4R1IoiixDhubwKeKp/auqhlOPvo58Lsi6iDR/WaLWabD+hcyAb1
ck/f/PUzTLhlLcfu18VPfXVzfnky3dX8P5aS0WMLAQblj2RaaiHxnPqf49kXSn3q
VSJ0pr0nEsPuWtoCkHUAwAJ8X5GPXN2OD4YbHsNaA9h2vrJAxNd5+HNsvg8JtI88
X/uMM7cWcaXcmNZOz166HUIPcJ5cabJ48Sv8sDfMPOcTiJkMiESBnRYTwdUcp08m
nGipSrUeW3pVOC1bGyukZb6sF84pTtCpqS+kOSfKFlxFFdAEcpzFIPuOMeo2dbKj
GSGPDemZFC2yFq883yk9/mZbgjOUsqrj0ZP3rCD5ZHpfUM5IxGQ+mKaOucTXYmif
lrTPMYnAc7pHxKZ87BgiKBYrfRAZvorLYKv8zG8YagAUw8iCtc68YUUdvLW9haQf
rwWCU1z+sszYSac7I57gfqICQhMUbs1n9S2Cn0C0xo4q2Lu36ysip4rEVGg6TmUu
znXYu+3orodw2TwC0tGxXHYKwmlr7EGnBCbdVKpDoCbV6cYkDYoPUFg0alqIPd5r
KCkee9MaCLLX7IdBrbLf1lkHGwSAs81GfZRMLBauM7/hn+hMUeIJnMbtJnVIB9Je
AdT2nSH06+POnjvxa2t0dUasnG/6ISBRSk6FgBBZ+pdVlrvaB4javgWGpiAWCUu6
b2CMZF3HullmLj+wwAKlsZsIOXGICN5GeQxLHYF8Kx7Doj68Owu/zGM5MS+7XQ==
=wYdb
hQIMAwDh3VI7VctTAQ/+OHyevGNQqVV8RMOgLxV7CSBCdzCgRiEyDt8/A2twNG1x
8lM5boYrVJowPbqd1EV2hfZ8gl3vvWhGMQdR96J+Mt1PWG/lok/Opf8Sdjl5hzpq
5AjNWz8p0NQ0e2UAGDuRXy+tjeMWKox86KVhxA/L3Td4S+jV5W+3zRSkRB7g1eIH
NJiyFe+jl29mSSABKk5TclzoB/GoojAkO+8iXsjMZYd3upHyQdriipQKkJJGEaxH
8fWBYcFB3H+3nMmwi6bz8xhUpOCpKzRbvwmqWYcendqINvDU/sQxQmxcqgMiluzQ
ocHNba+K//ptmtJHeL/8o69ljqk49A9mZ3ukRZZ9htWewv5n5T71majA/lJseGv7
tsAuKYTHlSkhOVzXuBnIaGrBgF3mB0ag+9/VIlBXCZpEMdjp3C9GJBUQuxoRSwbX
3oREyM97O/rtOo9JaqzqX63S59aHPwt83WH6dp2n2hcXF0tpYff3Esw9Vg3Uq+Fp
GCSjb4jFQTu25ZbpiiUaaFib+03Y6gGrnzU7W6460cxd4iZNEPGqE1refsQGYUPC
6L7R/mkT0SBtC/8lyOvuIpzYHiAkCqdLbrVTmBHUG+a4fIP16IilIFBh8haVKqY0
pgBDyLZDVwLzslp3AK+7pusU8STqCazFISe5GPQswwjwo+J3URmQKbCNHXVRyb2F
AgwDC9FRLmchgYQBD/94rHN8+Rqod5qxDxa0JR2ZYKSUBdzkkEqYnjp0efn/dY8x
m0WUQZEy+L4ZeAmFFL/mQ/Mxk7EW2Vghwy8j8tGTogJtVS7e0GYirKAHr6fgxxpa
5BoaUSK75xybQTzWe/CETfpRlDEFmYt/hwMldfCHXwnqZxXNVHj1MN2kVNFbPfwo
Ml8RYG8ZllyOVAVgXGsV6kiJp7jKblpuKCDQPkdbE1hFBed0SKW7olUtuBE4ho7Y
J1g1gXOAqAWud+crA21bA7Uow7ZYaC0/WzTY2PrgAuS6kpVx52uUj0xqMfK+/Cco
r+KFHleJL4b8pIsImsExJv6rDKFohC7E5n5XxLLorTXB6YYie8FkpvmbWK03j+hj
Q7xwFLKWYLlPGtdhe+YpL9yiwHWaQbGUjarVH0UAZgSwJCt1cZoiL6++dp1USb3N
aV9HS0Milhbseas9YjiSoVvBXrDYEnjShJ7uWOu3Rbh4hx7jvJijLPrPcd7cym+A
tjaxFFeD0mTEj1JcjVMk3fEN0wj++oY/l+piVvYvZWvMscq83Sb6CxxDprVw8xt0
sECqmgT0yVZrbDNpANwyWMXaHs5SZm5LaW7uDIcr0egkVA6Abn6twaR12660ptjm
mcv5K+ubzRomwxgzr/5NcwSg/k8qZ3WMfV/yuNsKIkHK2UI0y49SuBuCGGa1wtJe
AenE+Zn4xyF6cpEFXNKNXFDCy2fgHQrdiQ7XawrFAPJupn1JbGXg1gBN7yQI4YW+
BuVCb07GtuU/faiT7cIxUQ1nhc1alSE/edfqAPAPqxA/MXhoC7xT9vFmvUPAuw==
=moK4
-----END PGP MESSAGE-----
fp: 4BE7925262289B476DBBC17B76FD3810215AE097
unencrypted_suffix: _unencrypted

View file

@ -35,6 +35,7 @@
prstatus
swarsel-gens
swarsel-switch
swarsel-sops
];
};
}

View file

@ -87,7 +87,7 @@ in
# this interface to gain a carrier.
networkConfig.LinkLocalAddressing = "no";
linkConfig.RequiredForOnline = "carrier";
vlan = (map (name: "vlan-${name}") (builtins.attrNames localVLANs));
vlan = map (name: "vlan-${name}") (builtins.attrNames localVLANs);
};
# Remaining macvtap interfaces should not be touched.
"90-macvtap-ignore" = lib.mkIf withMicroVMs {

View file

@ -1,7 +1,7 @@
{ self, inputs, lib, config, globals, dns, confLib, ... }:
{ lib, config, globals, dns, confLib, ... }:
let
inherit (confLib.gen { name = "adguardhome"; port = 3000; }) serviceName servicePort serviceAddress serviceDomain proxyAddress4 proxyAddress6;
inherit (confLib.static) isHome isProxied homeProxy homeProxyIf webProxy webProxyIf homeWebProxy dnsServer homeDnsServer homeServiceAddress nginxAccessRules;
inherit (confLib.static) isHome isProxied homeProxyIf webProxy webProxyIf homeWebProxy dnsServer homeDnsServer homeServiceAddress nginxAccessRules;
homeServices = lib.attrNames (lib.filterAttrs (_: serviceCfg: serviceCfg.isHome) globals.services);
homeDomains = map (name: globals.services.${name}.domain) homeServices;
@ -19,7 +19,7 @@ in
${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort ];
};
${homeProxyIf}.hosts = lib.mkIf isHome {
${config.node.name}.firewallRuleForNode.${homeProxy}.allowedTCPPorts = [ servicePort ];
${config.node.name}.firewallRuleForNode.${homeWebProxy}.allowedTCPPorts = [ servicePort ];
};
};
services.${serviceName} = {
@ -58,11 +58,7 @@ in
];
dhcp.enabled = false;
};
filtering.rewrites = [
]
# Use the local mirror-proxy for some services (not necessary, just for speed)
++
map
filtering.rewrites = map
(domain: {
inherit domain;
# FIXME: change to homeWebProxy once that is setup
@ -97,42 +93,12 @@ in
}
];
nodes =
let
genNginx = toAddress: extraConfig: {
upstreams = {
${serviceName} = {
servers = {
"${toAddress}:${builtins.toString servicePort}" = { };
};
};
};
virtualHosts = {
"${serviceDomain}" = {
useACMEHost = globals.domains.main;
forceSSL = true;
acmeRoot = null;
oauth2 = {
enable = true;
allowedGroups = [ "adguardhome_access" ];
};
locations = {
"/" = {
proxyPass = "http://${serviceName}";
proxyWebsockets = true;
};
};
extraConfig = lib.mkIf (extraConfig != "") extraConfig;
};
};
};
in
{
${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
${webProxy}.services.nginx = genNginx serviceAddress "";
${homeWebProxy}.services.nginx = genNginx homeServiceAddress nginxAccessRules;
nodes = {
${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
${webProxy}.services.nginx = confLib.genNginx { inherit serviceAddress servicePort serviceDomain serviceName; proxyWebsockets = true; oauth2 = true; oauth2Groups = [ "adguardhome_access" ]; };
${homeWebProxy}.services.nginx = lib.mkIf isHome (confLib.genNginx { inherit servicePort serviceDomain serviceName; proxyWebsockets = true; oauth2 = true; oauth2Groups = [ "adguardhome_access" ]; extraConfig = nginxAccessRules; serviceAddress = homeServiceAddress; });
};
};
}

View file

@ -1,7 +1,8 @@
{ self, lib, config, globals, dns, confLib, ... }:
let
inherit (config.swarselsystems) sopsFile;
inherit (confLib.gen { name = "ankisync"; port = 27701; }) servicePort serviceName serviceDomain serviceAddress proxyAddress4 proxyAddress6 isHome isProxied homeProxy webProxy dnsServer homeProxyIf webProxyIf;
inherit (confLib.gen { name = "ankisync"; port = 27701; }) servicePort serviceName serviceDomain serviceAddress proxyAddress4 proxyAddress6;
inherit (confLib.static) isHome isProxied webProxy homeWebProxy dnsServer homeProxyIf webProxyIf homeServiceAddress nginxAccessRules;
ankiUser = globals.user.name;
in
@ -9,10 +10,6 @@ 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;
};
# networking.firewall.allowedTCPPorts = [ servicePort ];
sops.secrets.anki-pw = { inherit sopsFile; owner = "root"; };
@ -29,7 +26,7 @@ in
${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort ];
};
${homeProxyIf}.hosts = lib.mkIf isHome {
${config.node.name}.firewallRuleForNode.${homeProxy}.allowedTCPPorts = [ servicePort ];
${config.node.name}.firewallRuleForNode.${homeWebProxy}.allowedTCPPorts = [ servicePort ];
};
};
services.${serviceName} = {
@ -51,31 +48,13 @@ in
];
};
nodes.${webProxy}.services.nginx = {
upstreams = {
${serviceName} = {
servers = {
"${serviceAddress}:${builtins.toString servicePort}" = { };
};
};
};
virtualHosts = {
"${serviceDomain}" = {
useACMEHost = globals.domains.main;
forceSSL = true;
acmeRoot = null;
locations = {
"/" = {
proxyPass = "http://${serviceName}";
extraConfig = ''
client_max_body_size 0;
'';
};
};
};
nodes = {
${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
${webProxy}.services.nginx = confLib.genNginx { inherit serviceAddress servicePort serviceDomain serviceName; maxBody = 0; };
${homeWebProxy}.services.nginx = lib.mkIf isHome (confLib.genNginx { inherit servicePort serviceDomain serviceName; maxBody = 0; extraConfig = nginxAccessRules; serviceAddress = homeServiceAddress; });
};
};
};
}

View file

@ -1,6 +1,7 @@
{ lib, config, pkgs, globals, dns, confLib, ... }:
let
inherit (confLib.gen { name = "attic"; port = 8091; }) serviceName serviceDir servicePort serviceAddress serviceDomain proxyAddress4 proxyAddress6 isHome isProxied homeProxy webProxy dnsServer homeProxyIf webProxyIf;
inherit (confLib.gen { name = "attic"; port = 8091; }) serviceName serviceDir servicePort serviceAddress serviceDomain proxyAddress4 proxyAddress6;
inherit (confLib.static) isHome isProxied webProxy homeWebProxy dnsServer homeProxyIf webProxyIf homeServiceAddress nginxAccessRules;
inherit (config.swarselsystems) mainUser isPublic sopsFile;
serviceDB = "atticd";
in
@ -10,10 +11,6 @@ in
};
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;
};
topology.self.services.${serviceName} = {
name = lib.swarselsystems.toCapitalized serviceName;
info = "https://${serviceDomain}";
@ -26,7 +23,7 @@ in
${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort ];
};
${homeProxyIf}.hosts = lib.mkIf isHome {
${config.node.name}.firewallRuleForNode.${homeProxy}.allowedTCPPorts = [ servicePort ];
${config.node.name}.firewallRuleForNode.${homeWebProxy}.allowedTCPPorts = [ servicePort ];
};
};
services.${serviceName} = {
@ -138,36 +135,23 @@ in
after = [ "garage.service" ];
};
nodes.${webProxy}.services.nginx = {
upstreams = {
${serviceName} = {
servers = {
"${serviceAddress}:${builtins.toString servicePort}" = { };
};
nodes =
let
extraConfigLoc = ''
client_body_timeout 600s;
proxy_connect_timeout 600s;
proxy_send_timeout 600s;
proxy_read_timeout 600s;
proxy_request_buffering off;
'';
in
{
${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
${webProxy}.services.nginx = confLib.genNginx { inherit serviceAddress servicePort serviceDomain serviceName extraConfigLoc; maxBody = 0; };
${homeWebProxy}.services.nginx = lib.mkIf isHome (confLib.genNginx { inherit servicePort serviceDomain serviceName extraConfigLoc; maxBody = 0; extraConfig = nginxAccessRules; serviceAddress = homeServiceAddress; });
};
virtualHosts = {
"${serviceDomain}" = {
useACMEHost = globals.domains.main;
forceSSL = true;
acmeRoot = null;
oauth2.enable = false;
locations = {
"/" = {
proxyPass = "http://${serviceName}";
extraConfig = ''
client_max_body_size 0;
client_body_timeout 600s;
proxy_connect_timeout 600s;
proxy_send_timeout 600s;
proxy_read_timeout 600s;
proxy_request_buffering off;
'';
};
};
};
};
};
};
}

View file

@ -1,15 +1,12 @@
{ lib, config, globals, dns, confLib, ... }:
let
inherit (confLib.gen { name = "atuin"; port = 8888; }) servicePort serviceName serviceDomain serviceAddress proxyAddress4 proxyAddress6 isHome isProxied homeProxy webProxy dnsServer homeProxyIf webProxyIf;
inherit (confLib.gen { name = "atuin"; port = 8888; }) servicePort serviceName serviceDomain serviceAddress proxyAddress4 proxyAddress6;
inherit (confLib.static) isHome isProxied webProxy homeWebProxy dnsServer homeProxyIf webProxyIf homeServiceAddress nginxAccessRules;
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;
};
topology.self.services.${serviceName}.info = "https://${serviceDomain}";
globals = {
@ -18,7 +15,7 @@ in
${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort ];
};
${homeProxyIf}.hosts = lib.mkIf isHome {
${config.node.name}.firewallRuleForNode.${homeProxy}.allowedTCPPorts = [ servicePort ];
${config.node.name}.firewallRuleForNode.${homeWebProxy}.allowedTCPPorts = [ servicePort ];
};
};
services.${serviceName} = {
@ -35,30 +32,12 @@ in
openRegistration = false;
};
nodes.${webProxy}.services.nginx = {
upstreams = {
${serviceName} = {
servers = {
"${serviceAddress}:${builtins.toString servicePort}" = { };
};
};
};
virtualHosts = {
"${serviceDomain}" = {
useACMEHost = globals.domains.main;
forceSSL = true;
acmeRoot = null;
locations = {
"/" = {
proxyPass = "http://${serviceName}";
extraConfig = ''
client_max_body_size 0;
'';
};
};
};
nodes = {
${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
${webProxy}.services.nginx = confLib.genNginx { inherit serviceAddress servicePort serviceDomain serviceName; maxBody = 0; };
${homeWebProxy}.services.nginx = lib.mkIf isHome (confLib.genNginx { inherit servicePort serviceDomain serviceName; maxBody = 0; extraConfig = nginxAccessRules; serviceAddress = homeServiceAddress; });
};
};

View file

@ -1,6 +1,7 @@
{ self, lib, config, pkgs, dns, globals, confLib, ... }:
let
inherit (confLib.gen { name = "croc"; proxy = config.node.name; }) serviceName serviceDomain proxyAddress4 proxyAddress6 isHome dnsServer;
inherit (confLib.gen { name = "croc"; proxy = config.node.name; }) serviceName serviceDomain proxyAddress4 proxyAddress6;
inherit (confLib.static) isHome dnsServer;
servicePorts = [
9009
9010

View file

@ -1,10 +1,11 @@
{ lib, config, globals, confLib, ... }:
let
inherit (confLib.gen { name = "dns-home"; }) serviceName homeProxy;
inherit (confLib.gen { name = "dns-home"; }) serviceName;
inherit (confLib.static) homeProxy;
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} {
networking.hosts = {
${globals.networks.home-lan.vlans.services.hosts.${homeProxy}.ipv4} = [ "server.${homeProxy}.${globals.domains.main}" ];

View file

@ -1,6 +1,7 @@
{ self, lib, config, globals, dns, confLib, ... }:
let
inherit (confLib.gen { name = "firefly-iii"; port = 80; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress proxyAddress4 proxyAddress6 isHome dnsServer webProxy;
inherit (confLib.gen { name = "firefly-iii"; port = 80; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress proxyAddress4 proxyAddress6;
inherit (confLib.static) isHome dnsServer webProxy homeWebProxy homeServiceAddress nginxAccessRules;
nginxGroup = "nginx";
@ -11,10 +12,6 @@ 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;
};
users = {
groups.${serviceGroup} = { };
users.${serviceUser} = {
@ -81,36 +78,48 @@ in
};
};
nodes.${webProxy}.services.nginx = {
upstreams = {
${serviceName} = {
servers = {
"${serviceAddress}:${builtins.toString servicePort}" = { };
nodes =
let
genNginx = toAddress: extraConfig: {
upstreams = {
${serviceName} = {
servers = {
"${toAddress}:${builtins.toString servicePort}" = { };
};
};
};
};
};
virtualHosts = {
"${serviceDomain}" = {
useACMEHost = globals.domains.main;
virtualHosts = {
"${serviceDomain}" = {
useACMEHost = globals.domains.main;
forceSSL = true;
acmeRoot = null;
oauth2.enable = true;
oauth2.allowedGroups = [ "firefly_access" ];
# main config is automatically added by nixos firefly config.
# hence, only provide certificate
locations = {
"/" = {
proxyPass = "http://${serviceName}";
};
"/api" = {
proxyPass = "http://${serviceName}";
setOauth2Headers = false;
bypassAuth = true;
forceSSL = true;
acmeRoot = null;
oauth2 = {
enable = true;
allowedGroups = [ "firefly_access" ];
};
inherit extraConfig;
locations = {
"/" = {
proxyPass = "http://${serviceName}";
};
"/api" = {
proxyPass = "http://${serviceName}";
setOauth2Headers = false;
bypassAuth = true;
};
};
};
};
};
in
{
${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
${webProxy}.services.nginx = genNginx serviceAddress "";
${homeWebProxy}.services.nginx = genNginx homeServiceAddress nginxAccessRules;
};
};
};
}

View file

@ -1,6 +1,7 @@
{ self, lib, pkgs, config, globals, confLib, dns, nodes, ... }:
let
inherit (confLib.gen { name = "firezone"; dir = "/var/lib/private/firezone"; }) serviceName serviceDir serviceAddress serviceDomain proxyAddress4 proxyAddress6 isHome isProxied homeProxy webProxy homeProxyIf webProxyIf idmServer dnsServer;
inherit (confLib.gen { name = "firezone"; dir = "/var/lib/private/firezone"; }) serviceName serviceDir serviceAddress serviceDomain proxyAddress4 proxyAddress6;
inherit (confLib.static) isHome isProxied homeProxy webProxy homeWebProxy homeProxyIf webProxyIf idmServer dnsServer homeServiceAddress nginxAccessRules;
inherit (config.swarselsystems) sopsFile;
apiPort = 8081;
@ -23,10 +24,6 @@ in
};
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 = {
networks = {
${webProxyIf}.hosts = lib.mkIf isProxied {
@ -42,7 +39,7 @@ in
};
};
${homeProxyIf}.hosts = lib.mkIf isHome {
${config.node.name}.firewallRuleForNode.${homeProxy} = {
${config.node.name}.firewallRuleForNode.${homeWebProxy} = {
allowedTCPPorts = [ apiPort webPort domainPort ];
allowedUDPPorts = [ relayPort ];
allowedUDPPortRanges = [
@ -257,118 +254,15 @@ in
# };
nodes = {
${homeProxy} =
let
nodeCfg = nodes.${homeProxy}.config;
nodePkgs = nodes.${homeProxy}.pkgs;
in
{
sops.secrets.firezone-gateway-token = { inherit (nodeCfg.swarselsystems) sopsFile; mode = "0400"; };
networking.nftables = {
firewall = {
zones.firezone.interfaces = [ "tun-firezone" ];
rules = {
# masquerade firezone traffic
masquerade-firezone = {
from = [ "firezone" ];
to = [ "vlan-services" ];
# masquerade = true; NOTE: custom rule below for ip4 + ip6
late = true; # Only accept after any rejects have been processed
verdict = "accept";
};
# forward firezone traffic
forward-incoming-firezone-traffic = {
from = [ "firezone" ];
to = [ "vlan-services" ];
verdict = "accept";
};
# FIXME: is this needed? conntrack should take care of it and we want to masquerade anyway
forward-outgoing-firezone-traffic = {
from = [ "vlan-services" ];
to = [ "firezone" ];
verdict = "accept";
};
};
};
chains.postrouting = {
masquerade-firezone = {
after = [ "hook" ];
late = true;
rules =
lib.forEach
[
"firezone"
]
(
zone:
lib.concatStringsSep " " [
"meta protocol { ip, ip6 }"
(lib.head nodeCfg.networking.nftables.firewall.zones.${zone}.ingressExpression)
(lib.head nodeCfg.networking.nftables.firewall.zones.vlan-services.egressExpression)
"masquerade random"
]
);
};
};
};
boot.kernel.sysctl = {
"net.core.wmem_max" = 16777216;
"net.core.rmem_max" = 134217728;
};
services.firezone.gateway = {
enable = true;
# logLevel = "trace";
inherit (nodeCfg.node) name;
apiUrl = "wss://${globals.services.firezone.domain}/api/";
tokenFile = nodeCfg.sops.secrets.firezone-gateway-token.path;
package = nodePkgs.stable25_05.firezone-gateway; # newer versions of firezone-gateway are not compatible with server package
};
topology.self.services."${serviceName}-gateway" = {
name = lib.swarselsystems.toCapitalized "${serviceName} Gateway";
icon = "${self}/files/topology-images/${serviceName}.png";
};
};
${idmServer} =
let
nodeCfg = nodes.${idmServer}.config;
accountId = "6b3c6ba7-5240-4684-95ce-f40fdae45096";
externalId = "08d714e9-1ab9-4133-a39d-00e843a960cc";
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}/${accountId}/sign_in/providers/${externalId}/handle_callback"
"https://${globals.services.firezone.domain}/${accountId}/settings/identity_providers/openid_connect/${externalId}/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 = {
nodes =
let
genNginx = toAddress: extraConfig: {
upstreams = {
${serviceName} = {
servers."${serviceAddress}:${builtins.toString webPort}" = { };
servers."${toAddress}:${builtins.toString webPort}" = { };
};
"${serviceName}-api" = {
servers."${serviceAddress}:${builtins.toString apiPort}" = { };
servers."${toAddress}:${builtins.toString apiPort}" = { };
};
};
virtualHosts = {
@ -376,21 +270,133 @@ in
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;
inherit extraConfig;
locations = {
"/" = {
# The trailing slash is important to strip the location prefix from the request
proxyPass = "http://${serviceName}/";
proxyWebsockets = true;
};
"/api/" = {
# The trailing slash is important to strip the location prefix from the request
proxyPass = "http://${serviceName}-api/";
proxyWebsockets = true;
};
};
};
};
};
in
{
${homeProxy} =
let
nodeCfg = nodes.${homeProxy}.config;
nodePkgs = nodes.${homeProxy}.pkgs;
in
{
sops.secrets.firezone-gateway-token = { inherit (nodeCfg.swarselsystems) sopsFile; mode = "0400"; };
networking.nftables = {
firewall = {
zones.firezone.interfaces = [ "tun-firezone" ];
rules = {
# masquerade firezone traffic
masquerade-firezone = {
from = [ "firezone" ];
to = [ "vlan-services" ];
# masquerade = true; NOTE: custom rule below for ip4 + ip6
late = true; # Only accept after any rejects have been processed
verdict = "accept";
};
# forward firezone traffic
forward-incoming-firezone-traffic = {
from = [ "firezone" ];
to = [ "vlan-services" ];
verdict = "accept";
};
# FIXME: is this needed? conntrack should take care of it and we want to masquerade anyway
forward-outgoing-firezone-traffic = {
from = [ "vlan-services" ];
to = [ "firezone" ];
verdict = "accept";
};
};
};
chains.postrouting = {
masquerade-firezone = {
after = [ "hook" ];
late = true;
rules =
lib.forEach
[
"firezone"
]
(
zone:
lib.concatStringsSep " " [
"meta protocol { ip, ip6 }"
(lib.head nodeCfg.networking.nftables.firewall.zones.${zone}.ingressExpression)
(lib.head nodeCfg.networking.nftables.firewall.zones.vlan-services.egressExpression)
"masquerade random"
]
);
};
};
};
boot.kernel.sysctl = {
"net.core.wmem_max" = 16777216;
"net.core.rmem_max" = 134217728;
};
services.firezone.gateway = {
enable = true;
# logLevel = "trace";
inherit (nodeCfg.node) name;
apiUrl = "wss://${globals.services.firezone.domain}/api/";
tokenFile = nodeCfg.sops.secrets.firezone-gateway-token.path;
package = nodePkgs.stable25_05.firezone-gateway; # newer versions of firezone-gateway are not compatible with server package
};
topology.self.services."${serviceName}-gateway" = {
name = lib.swarselsystems.toCapitalized "${serviceName} Gateway";
icon = "${self}/files/topology-images/${serviceName}.png";
};
};
${idmServer} =
let
nodeCfg = nodes.${idmServer}.config;
accountId = "6b3c6ba7-5240-4684-95ce-f40fdae45096";
externalId = "08d714e9-1ab9-4133-a39d-00e843a960cc";
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}/${accountId}/sign_in/providers/${externalId}/handle_callback"
"https://${globals.services.firezone.domain}/${accountId}/settings/identity_providers/openid_connect/${externalId}/handle_callback"
];
originLanding = "https://${globals.services.firezone.domain}/";
basicSecretFile = nodeCfg.sops.secrets.kanidm-firezone.path;
preferShortUsername = true;
scopeMaps."firezone.access" = [
"openid"
"email"
"profile"
];
};
};
};
${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
${webProxy}.services.nginx = genNginx serviceAddress "";
${homeWebProxy}.services.nginx = lib.mkIf isHome (genNginx homeServiceAddress nginxAccessRules);
};
};
};
}

View file

@ -1,7 +1,8 @@
{ lib, config, pkgs, globals, dns, confLib, ... }:
let
inherit (config.swarselsystems) sopsFile;
inherit (confLib.gen { name = "forgejo"; port = 3004; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress proxyAddress4 proxyAddress6 isHome isProxied homeProxy webProxy dnsServer homeProxyIf webProxyIf;
inherit (confLib.gen { name = "forgejo"; port = 3004; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress proxyAddress4 proxyAddress6;
inherit (confLib.static) isHome isProxied webProxy homeWebProxy dnsServer homeProxyIf webProxyIf homeServiceAddress nginxAccessRules;
kanidmDomain = globals.services.kanidm.domain;
in
@ -9,10 +10,6 @@ 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;
};
# networking.firewall.allowedTCPPorts = [ servicePort ];
users.users.${serviceUser} = {
@ -32,7 +29,7 @@ in
${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort ];
};
${homeProxyIf}.hosts = lib.mkIf isHome {
${config.node.name}.firewallRuleForNode.${homeProxy}.allowedTCPPorts = [ servicePort ];
${config.node.name}.firewallRuleForNode.${homeWebProxy}.allowedTCPPorts = [ servicePort ];
};
};
services.${serviceName} = {
@ -140,31 +137,13 @@ in
'';
};
nodes.${webProxy}.services.nginx = {
upstreams = {
${serviceName} = {
servers = {
"${serviceAddress}:${builtins.toString servicePort}" = { };
};
};
};
virtualHosts = {
"${serviceDomain}" = {
useACMEHost = globals.domains.main;
forceSSL = true;
acmeRoot = null;
locations = {
"/" = {
proxyPass = "http://${serviceName}";
extraConfig = ''
client_max_body_size 0;
'';
};
};
};
nodes = {
${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
${webProxy}.services.nginx = confLib.genNginx { inherit serviceAddress servicePort serviceDomain serviceName; maxBody = 0; };
${homeWebProxy}.services.nginx = lib.mkIf isHome (confLib.genNginx { inherit servicePort serviceDomain serviceName; maxBody = 0; extraConfig = nginxAccessRules; serviceAddress = homeServiceAddress; });
};
};
};
}

View file

@ -1,6 +1,7 @@
{ self, lib, config, globals, dns, confLib, ... }:
let
inherit (confLib.gen { name = "freshrss"; port = 80; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress proxyAddress4 proxyAddress6 isHome webProxy dnsServer;
inherit (confLib.gen { name = "freshrss"; port = 80; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress proxyAddress4 proxyAddress6;
inherit (confLib.static) isHome webProxy homeWebProxy dnsServer homeServiceAddress nginxAccessRules;
inherit (config.swarselsystems) sopsFile;
in
@ -8,10 +9,6 @@ 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;
};
users.users.${serviceUser} = {
extraGroups = [ "users" ];
group = serviceGroup;
@ -76,34 +73,46 @@ in
# config.sops.templates.freshrss-env.path
# ];
nodes.${webProxy}.services.nginx = {
upstreams = {
${serviceName} = {
servers = {
"${serviceAddress}:${builtins.toString servicePort}" = { };
nodes =
let
genNginx = toAddress: extraConfig: {
upstreams = {
${serviceName} = {
servers = {
"${toAddress}:${builtins.toString servicePort}" = { };
};
};
};
};
};
virtualHosts = {
"${serviceDomain}" = {
useACMEHost = globals.domains.main;
virtualHosts = {
"${serviceDomain}" = {
useACMEHost = globals.domains.main;
forceSSL = true;
acmeRoot = null;
oauth2.enable = true;
oauth2.allowedGroups = [ "ttrss_access" ];
locations = {
"/" = {
proxyPass = "http://${serviceName}";
};
"/api" = {
proxyPass = "http://${serviceName}";
setOauth2Headers = false;
bypassAuth = true;
forceSSL = true;
acmeRoot = null;
oauth2.enable = true;
oauth2.allowedGroups = [ "ttrss_access" ];
inherit extraConfig;
locations = {
"/" = {
proxyPass = "http://${serviceName}";
};
"/api" = {
proxyPass = "http://${serviceName}";
setOauth2Headers = false;
bypassAuth = true;
};
};
};
};
};
in
{
${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
${webProxy}.services.nginx = genNginx serviceAddress "";
${homeWebProxy}.services.nginx = genNginx homeServiceAddress nginxAccessRules;
};
};
};
}

View file

@ -1,11 +1,8 @@
# inspired by https://github.com/atropos112/nixos/blob/7fef652006a1c939f4caf9c8a0cb0892d9cdfe21/modules/garage.nix
{ self, lib, pkgs, config, globals, dns, confLib, ... }:
let
inherit (confLib.gen {
name = "garage";
port = 3900;
domain = config.repo.secrets.common.services.domains."garage-${config.node.name}";
}) servicePort serviceName specificServiceName serviceDomain subDomain baseDomain serviceAddress proxyAddress4 proxyAddress6 isHome isProxied homeProxy webProxy dnsServer homeProxyIf webProxyIf;
inherit (confLib.gen { name = "garage"; port = 3900; domain = config.repo.secrets.common.services.domains."garage-${config.node.name}"; }) servicePort serviceName specificServiceName serviceDomain subDomain baseDomain serviceAddress proxyAddress4 proxyAddress6;
inherit (confLib.static) isHome isProxied webProxy homeWebProxy dnsServer homeProxyIf webProxyIf homeServiceAddress nginxAccessRules;
cfg = lib.recursiveUpdate config.services.${serviceName} config.swarselsystems.server.${serviceName};
inherit (config.swarselsystems) sopsFile mainUser;
@ -73,14 +70,6 @@ in
# networking.firewall.allowedTCPPorts = [ servicePort 3901 3902 3903 3904 ];
nodes.${dnsServer}.swarselsystems.server.dns.${baseDomain}.subdomainRecords = {
"${subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
"${subDomain}-admin" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
"${subDomain}-web" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
"*.${subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
"*.${subDomain}-web" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
topology.self.services.${serviceName} = {
name = lib.swarselsystems.toCapitalized serviceName;
info = "https://${serviceDomain}";
@ -114,7 +103,7 @@ in
${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort 3901 3902 3903 3904 ];
};
${homeProxyIf}.hosts = lib.mkIf isHome {
${config.node.name}.firewallRuleForNode.${homeProxy}.allowedTCPPorts = [ servicePort 3901 3902 3903 3904 ];
${config.node.name}.firewallRuleForNode.${homeWebProxy}.allowedTCPPorts = [ servicePort 3901 3902 3903 3904 ];
};
};
services.${specificServiceName} = {
@ -325,69 +314,86 @@ in
};
};
nodes.${webProxy}.services.nginx = {
upstreams = {
${serviceName} = {
servers = {
"${serviceAddress}:${builtins.toString servicePort}" = { };
nodes =
let
genNginx = toAddress: extraConfig: {
upstreams = {
${serviceName} = {
servers = {
"${toAddress}:${builtins.toString servicePort}" = { };
};
};
"${serviceName}Web" = {
servers = {
"${toAddress}:${builtins.toString garageWebPort}" = { };
};
};
"${serviceName}Admin" = {
servers = {
"${toAddress}:${builtins.toString garageAdminPort}" = { };
};
};
};
virtualHosts = {
"${adminDomain}" = {
useACMEHost = globals.domains.main;
forceSSL = true;
acmeRoot = null;
oauth2.enable = false;
inherit extraConfig;
locations = {
"/" = {
proxyPass = "http://${serviceName}Admin";
};
};
};
"*.${webDomain}" = {
useACMEHost = globals.domains.main;
forceSSL = true;
acmeRoot = null;
oauth2.enable = false;
inherit extraConfig;
locations = {
"/" = {
proxyPass = "http://${serviceName}Web";
};
};
};
"${serviceDomain}" = {
serverAliases = [ "*.${serviceDomain}" ];
useACMEHost = globals.domains.main;
forceSSL = true;
acmeRoot = null;
oauth2.enable = false;
inherit extraConfig;
locations = {
"/" = {
proxyPass = "http://${serviceName}";
extraConfig = ''
client_max_body_size 0;
client_body_timeout 600s;
proxy_connect_timeout 600s;
proxy_send_timeout 600s;
proxy_read_timeout 600s;
proxy_request_buffering off;
'';
};
};
};
};
};
"${serviceName}Web" = {
servers = {
"${serviceAddress}:${builtins.toString garageWebPort}" = { };
};
};
"${serviceName}Admin" = {
servers = {
"${serviceAddress}:${builtins.toString garageAdminPort}" = { };
};
in
{
${dnsServer}.swarselsystems.server.dns.${baseDomain}.subdomainRecords = {
"${subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
"${subDomain}-admin" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
"${subDomain}-web" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
"*.${subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
"*.${subDomain}-web" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
${webProxy}.services.nginx = genNginx serviceAddress "";
${homeWebProxy}.services.nginx = lib.mkIf isHome (genNginx homeServiceAddress nginxAccessRules);
};
virtualHosts = {
"${adminDomain}" = {
useACMEHost = globals.domains.main;
forceSSL = true;
acmeRoot = null;
oauth2.enable = false;
locations = {
"/" = {
proxyPass = "http://${serviceName}Admin";
};
};
};
"*.${webDomain}" = {
useACMEHost = globals.domains.main;
forceSSL = true;
acmeRoot = null;
oauth2.enable = false;
locations = {
"/" = {
proxyPass = "http://${serviceName}Web";
};
};
};
"${serviceDomain}" = {
serverAliases = [ "*.${serviceDomain}" ];
useACMEHost = globals.domains.main;
forceSSL = true;
acmeRoot = null;
oauth2.enable = false;
locations = {
"/" = {
proxyPass = "http://${serviceName}";
extraConfig = ''
client_max_body_size 0;
client_body_timeout 600s;
proxy_connect_timeout 600s;
proxy_send_timeout 600s;
proxy_read_timeout 600s;
proxy_request_buffering off;
'';
};
};
};
};
};
};
}

View file

@ -1,15 +1,12 @@
{ self, lib, pkgs, config, globals, dns, confLib, ... }:
let
inherit (confLib.gen { name = "homebox"; port = 7745; }) servicePort serviceName serviceDomain serviceAddress proxyAddress4 proxyAddress6 isHome isProxied homeProxy webProxy dnsServer homeProxyIf webProxyIf;
inherit (confLib.gen { name = "homebox"; port = 7745; }) servicePort serviceName serviceDomain serviceAddress proxyAddress4 proxyAddress6;
inherit (confLib.static) isHome isProxied webProxy homeWebProxy dnsServer homeProxyIf webProxyIf homeServiceAddress nginxAccessRules;
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;
};
topology.self.services.${serviceName} = {
name = "Homebox";
info = "https://${serviceDomain}";
@ -22,7 +19,7 @@ in
${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort ];
};
${homeProxyIf}.hosts = lib.mkIf isHome {
${config.node.name}.firewallRuleForNode.${homeProxy}.allowedTCPPorts = [ servicePort ];
${config.node.name}.firewallRuleForNode.${homeWebProxy}.allowedTCPPorts = [ servicePort ];
};
};
services.${serviceName} = {
@ -45,30 +42,13 @@ in
# networking.firewall.allowedTCPPorts = [ servicePort ];
nodes.${webProxy}.services.nginx = {
upstreams = {
${serviceName} = {
servers = {
"${serviceAddress}:${builtins.toString servicePort}" = { };
};
};
};
virtualHosts = {
"${serviceDomain}" = {
useACMEHost = globals.domains.main;
forceSSL = true;
acmeRoot = null;
oauth2.enable = false;
locations = {
"/" = {
proxyPass = "http://${serviceName}";
};
};
};
nodes = {
${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
${webProxy}.services.nginx = confLib.genNginx { inherit serviceAddress servicePort serviceDomain serviceName; maxBody = 0; };
${homeWebProxy}.services.nginx = lib.mkIf isHome (confLib.genNginx { inherit servicePort serviceDomain serviceName; maxBody = 0; extraConfig = nginxAccessRules; serviceAddress = homeServiceAddress; });
};
};
}

View file

@ -1,6 +1,7 @@
{ inputs, lib, config, globals, dns, confLib, ... }:
let
inherit (confLib.gen { name = "hydra"; port = 8002; }) serviceName servicePort serviceUser serviceGroup serviceAddress serviceDomain proxyAddress4 proxyAddress6 isHome isProxied homeProxy webProxy dnsServer homeProxyIf webProxyIf;
inherit (confLib.gen { name = "hydra"; port = 8002; }) serviceName servicePort serviceUser serviceGroup serviceAddress serviceDomain proxyAddress4 proxyAddress6;
inherit (confLib.static) isHome isProxied webProxy homeWebProxy dnsServer homeProxyIf webProxyIf homeServiceAddress nginxAccessRules;
inherit (config.swarselsystems) sopsFile;
in
{
@ -9,10 +10,6 @@ in
};
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;
};
topology.self.services.${serviceName}.info = "https://${serviceDomain}";
globals = {
@ -21,7 +18,7 @@ in
${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort ];
};
${homeProxyIf}.hosts = lib.mkIf isHome {
${config.node.name}.firewallRuleForNode.${homeProxy}.allowedTCPPorts = [ servicePort ];
${config.node.name}.firewallRuleForNode.${homeWebProxy}.allowedTCPPorts = [ servicePort ];
};
};
services.${serviceName} = {
@ -114,32 +111,19 @@ in
'';
};
nodes.${webProxy}.services.nginx = {
upstreams = {
${serviceName} = {
servers = {
"${serviceAddress}:${builtins.toString servicePort}" = { };
};
nodes =
let
extraConfigLoc = ''
proxy_set_header X-Request-Base /hydra;
'';
in
{
${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
${webProxy}.services.nginx = confLib.genNginx { inherit serviceAddress servicePort serviceDomain serviceName extraConfigLoc; maxBody = 0; };
${homeWebProxy}.services.nginx = lib.mkIf isHome (confLib.genNginx { inherit servicePort serviceDomain serviceName extraConfigLoc; maxBody = 0; extraConfig = nginxAccessRules; serviceAddress = homeServiceAddress; });
};
virtualHosts = {
"${serviceDomain}" = {
enableACME = true;
forceSSL = true;
acmeRoot = null;
oauth2.enable = false;
locations = {
"/" = {
proxyPass = "http://${serviceName}";
extraConfig = ''
client_max_body_size 0;
proxy_set_header X-Request-Base /hydra;
'';
};
};
};
};
};
};
}

View file

@ -1,15 +1,12 @@
{ lib, pkgs, config, globals, dns, confLib, ... }:
let
inherit (confLib.gen { name = "immich"; port = 3001; }) servicePort serviceName serviceUser serviceDomain serviceAddress proxyAddress4 proxyAddress6 isHome isProxied homeProxy webProxy dnsServer homeProxyIf webProxyIf;
inherit (confLib.gen { name = "immich"; port = 3001; }) servicePort serviceName serviceUser serviceDomain serviceAddress proxyAddress4 proxyAddress6;
inherit (confLib.static) isHome isProxied webProxy homeWebProxy dnsServer homeProxyIf webProxyIf homeServiceAddress nginxAccessRules;
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;
};
users.users.${serviceUser} = {
extraGroups = [ "video" "render" "users" ];
};
@ -23,7 +20,7 @@ in
${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort ];
};
${homeProxyIf}.hosts = lib.mkIf isHome {
${config.node.name}.firewallRuleForNode.${homeProxy}.allowedTCPPorts = [ servicePort ];
${config.node.name}.firewallRuleForNode.${homeWebProxy}.allowedTCPPorts = [ servicePort ];
};
};
services.${serviceName} = {
@ -44,42 +41,26 @@ in
};
};
nodes =
let
extraConfigLoc = ''
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_redirect off;
nodes.${webProxy}.services.nginx = {
upstreams = {
${serviceName} = {
servers = {
"${serviceAddress}:${builtins.toString servicePort}" = { };
};
proxy_read_timeout 600s;
proxy_send_timeout 600s;
send_timeout 600s;
'';
in
{
${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
${webProxy}.services.nginx = confLib.genNginx { inherit serviceAddress servicePort serviceDomain serviceName extraConfigLoc; maxBody = 0; };
${homeWebProxy}.services.nginx = lib.mkIf isHome (confLib.genNginx { inherit servicePort serviceDomain serviceName extraConfigLoc; maxBody = 0; extraConfig = nginxAccessRules; serviceAddress = homeServiceAddress; });
};
virtualHosts = {
"${serviceDomain}" = {
useACMEHost = globals.domains.main;
forceSSL = true;
acmeRoot = null;
locations = {
"/" = {
proxyPass = "http://${serviceName}";
extraConfig = ''
client_max_body_size 0;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_redirect off;
proxy_read_timeout 600s;
proxy_send_timeout 600s;
send_timeout 600s;
'';
};
};
};
};
};
};
}

View file

@ -1,15 +1,12 @@
{ pkgs, lib, config, globals, dns, confLib, ... }:
let
inherit (confLib.gen { name = "jellyfin"; port = 8096; }) servicePort serviceName serviceUser serviceDomain serviceAddress proxyAddress4 proxyAddress6 isHome isProxied homeProxy webProxy dnsServer homeProxyIf webProxyIf;
inherit (confLib.gen { name = "jellyfin"; port = 8096; }) servicePort serviceName serviceUser serviceDomain serviceAddress proxyAddress4 proxyAddress6;
inherit (confLib.static) isHome isProxied webProxy homeWebProxy dnsServer homeProxyIf webProxyIf nginxAccessRules homeServiceAddress;
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;
};
users.users.${serviceUser} = {
extraGroups = [ "video" "render" "users" ];
};
@ -36,7 +33,7 @@ in
${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort ];
};
${homeProxyIf}.hosts = lib.mkIf isHome {
${config.node.name}.firewallRuleForNode.${homeProxy}.allowedTCPPorts = [ servicePort ];
${config.node.name}.firewallRuleForNode.${homeWebProxy}.allowedTCPPorts = [ servicePort ];
};
};
services.${serviceName} = {
@ -51,31 +48,13 @@ in
# openFirewall = true; # this works only for the default ports
};
nodes.${webProxy}.services.nginx = {
upstreams = {
${serviceName} = {
servers = {
"${serviceAddress}:${builtins.toString servicePort}" = { };
};
};
};
virtualHosts = {
"${serviceDomain}" = {
useACMEHost = globals.domains.main;
forceSSL = true;
acmeRoot = null;
locations = {
"/" = {
proxyPass = "http://${serviceName}";
extraConfig = ''
client_max_body_size 0;
'';
};
};
};
nodes = {
${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
${webProxy}.services.nginx = confLib.genNginx { inherit serviceAddress servicePort serviceDomain serviceName; maxBody = 0; };
${homeWebProxy}.services.nginx = lib.mkIf isHome (confLib.genNginx { inherit servicePort serviceDomain serviceName; maxBody = 0; extraConfig = nginxAccessRules; serviceAddress = homeServiceAddress; });
};
};
};
}

View file

@ -1,22 +1,19 @@
{ pkgs, lib, config, globals, dns, confLib, ... }:
let
inherit (confLib.gen { name = "jenkins"; port = 8088; }) servicePort serviceName serviceDomain serviceAddress proxyAddress4 proxyAddress6 isHome isProxied homeProxy webProxy dnsServer homeProxyIf webProxyIf;
inherit (confLib.gen { name = "jenkins"; port = 8088; }) servicePort serviceName serviceDomain serviceAddress proxyAddress4 proxyAddress6;
inherit (confLib.static) isHome isProxied webProxy homeWebProxy dnsServer homeProxyIf webProxyIf homeServiceAddress nginxAccessRules;
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 = {
networks = {
${webProxyIf}.hosts = lib.mkIf isProxied {
${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort ];
};
${homeProxyIf}.hosts = lib.mkIf isHome {
${config.node.name}.firewallRuleForNode.${homeProxy}.allowedTCPPorts = [ servicePort ];
${config.node.name}.firewallRuleForNode.${homeWebProxy}.allowedTCPPorts = [ servicePort ];
};
};
services.${serviceName} = {
@ -34,31 +31,13 @@ in
home = "/Vault/apps/${serviceName}";
};
nodes.${webProxy}.services.nginx = {
upstreams = {
${serviceName} = {
servers = {
"${serviceAddress}:${builtins.toString servicePort}" = { };
};
};
};
virtualHosts = {
"${serviceDomain}" = {
useACMEHost = globals.domains.main;
forceSSL = true;
acmeRoot = null;
locations = {
"/" = {
proxyPass = "http://${serviceName}";
extraConfig = ''
client_max_body_size 0;
'';
};
};
};
nodes = {
${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
${webProxy}.services.nginx = confLib.genNginx { inherit serviceAddress servicePort serviceDomain serviceName; maxBody = 0; };
${homeWebProxy}.services.nginx = lib.mkIf isHome (confLib.genNginx { inherit servicePort serviceDomain serviceName; maxBody = 0; extraConfig = nginxAccessRules; serviceAddress = homeServiceAddress; });
};
};
};
}

View file

@ -2,7 +2,8 @@
let
certsSopsFile = self + /secrets/repo/certs.yaml;
inherit (config.swarselsystems) sopsFile;
inherit (confLib.gen { name = "kanidm"; port = 8300; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress proxyAddress4 proxyAddress6 isHome isProxied homeProxy webProxy homeProxyIf webProxyIf dnsServer;
inherit (confLib.gen { name = "kanidm"; port = 8300; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress proxyAddress4 proxyAddress6;
inherit (confLib.static) isHome isProxied webProxy homeWebProxy homeProxyIf webProxyIf dnsServer homeServiceAddress nginxAccessRules;
oauth2ProxyDomain = globals.services.oauth2-proxy.domain;
immichDomain = globals.services.immich.domain;
@ -31,9 +32,6 @@ 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;
};
users = {
users.${serviceUser} = {
@ -69,7 +67,7 @@ in
${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort ];
};
${homeProxyIf}.hosts = lib.mkIf isHome {
${config.node.name}.firewallRuleForNode.${homeProxy}.allowedTCPPorts = [ servicePort ];
${config.node.name}.firewallRuleForNode.${homeWebProxy}.allowedTCPPorts = [ servicePort ];
};
};
services.${serviceName} = {
@ -396,34 +394,15 @@ in
};
};
systemd.services = {
${serviceName}.serviceConfig.RestartSec = "30";
systemd.services.${serviceName}.serviceConfig.RestartSec = "30";
nodes = {
${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
${webProxy}.services.nginx = confLib.genNginx { inherit serviceAddress servicePort serviceDomain serviceName; protocol = "https"; noSslVerify = true; };
${homeWebProxy}.services.nginx = confLib.genNginx { inherit servicePort serviceDomain serviceName; protocol = "https"; noSslVerify = true; extraConfig = nginxAccessRules; serviceAddress = homeServiceAddress; };
};
nodes.${webProxy}.services.nginx = {
upstreams = {
${serviceName} = {
servers = {
"${serviceAddress}:${builtins.toString servicePort}" = { };
};
};
};
virtualHosts = {
"${serviceDomain}" = {
useACMEHost = globals.domains.main;
forceSSL = true;
acmeRoot = null;
locations = {
"/" = {
proxyPass = "https://${serviceName}";
};
};
extraConfig = ''
proxy_ssl_verify off;
'';
};
};
};
};
}

View file

@ -2,7 +2,8 @@
let
inherit (config.swarselsystems) sopsFile;
inherit (confLib.gen { name = "kavita"; port = 8080; }) servicePort serviceName serviceUser serviceDomain serviceAddress proxyAddress4 proxyAddress6 isHome isProxied homeProxy webProxy dnsServer homeProxyIf webProxyIf;
inherit (confLib.gen { name = "kavita"; port = 8080; }) servicePort serviceName serviceUser serviceDomain serviceAddress proxyAddress4 proxyAddress6;
inherit (confLib.static) isHome isProxied webProxy homeWebProxy dnsServer homeProxyIf webProxyIf nginxAccessRules homeServiceAddress;
in
{
options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
@ -11,9 +12,6 @@ in
calibre
];
nodes.${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
users.users.${serviceUser} = {
extraGroups = [ "users" ];
@ -34,7 +32,7 @@ in
${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort ];
};
${homeProxyIf}.hosts = lib.mkIf isHome {
${config.node.name}.firewallRuleForNode.${homeProxy}.allowedTCPPorts = [ servicePort ];
${config.node.name}.firewallRuleForNode.${homeWebProxy}.allowedTCPPorts = [ servicePort ];
};
};
services.${serviceName} = {
@ -51,29 +49,13 @@ in
dataDir = "/Vault/data/${serviceName}";
};
nodes.${webProxy}.services.nginx = {
upstreams = {
${serviceName} = {
servers = {
"${serviceAddress}:${builtins.toString servicePort}" = { };
};
};
};
virtualHosts = {
"${serviceDomain}" = {
useACMEHost = globals.domains.main;
forceSSL = true;
acmeRoot = null;
locations = {
"/" = {
proxyPass = "http://${serviceName}";
extraConfig = ''
client_max_body_size 0;
'';
};
};
};
nodes = {
${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
${webProxy}.services.nginx = confLib.genNginx { inherit serviceAddress servicePort serviceDomain serviceName; maxBody = 0; };
${homeWebProxy}.services.nginx = lib.mkIf isHome (confLib.genNginx { inherit servicePort serviceDomain serviceName; maxBody = 0; extraConfig = nginxAccessRules; serviceAddress = homeServiceAddress; });
};
};
}

View file

@ -1,6 +1,7 @@
{ self, lib, config, globals, confLib, ... }:
let
inherit (confLib.gen { name = "kea"; dir = "/var/lib/private/kea"; }) serviceName serviceDir homeDnsServer;
inherit (confLib.gen { name = "kea"; dir = "/var/lib/private/kea"; }) serviceName serviceDir;
inherit (confLib.static) homeDnsServer;
dhcpX = intX:
let
x = builtins.toString intX;

View file

@ -1,6 +1,7 @@
{ self, lib, config, globals, dns, confLib, ... }:
let
inherit (confLib.gen { name = "koillection"; port = 2282; dir = "/Vault/data/koillection"; }) servicePort serviceName serviceUser serviceDir serviceDomain serviceAddress proxyAddress4 proxyAddress6 isHome isProxied homeProxy webProxy dnsServer homeProxyIf webProxyIf;
inherit (confLib.gen { name = "koillection"; port = 2282; dir = "/Vault/data/koillection"; }) servicePort serviceName serviceUser serviceDir serviceDomain serviceAddress proxyAddress4 proxyAddress6;
inherit (confLib.static) isHome isProxied webProxy homeWebProxy dnsServer homeProxyIf webProxyIf homeServiceAddress nginxAccessRules;
serviceDB = "koillection";
postgresUser = config.systemd.services.postgresql.serviceConfig.User; # postgres
@ -18,9 +19,6 @@ in
postgresql = true;
};
nodes.${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
sops.secrets = {
koillection-db-password = { inherit sopsFile; owner = postgresUser; group = postgresUser; mode = "0440"; };
koillection-env-file = { inherit sopsFile; };
@ -38,7 +36,7 @@ in
${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort postgresPort ];
};
${homeProxyIf}.hosts = lib.mkIf isHome {
${config.node.name}.firewallRuleForNode.${homeProxy}.allowedTCPPorts = [ servicePort postgresPort ];
${config.node.name}.firewallRuleForNode.${homeWebProxy}.allowedTCPPorts = [ servicePort postgresPort ];
};
};
services.${serviceName} = {
@ -121,32 +119,22 @@ in
};
};
nodes.${webProxy}.services.nginx = {
upstreams = {
${serviceName} = {
servers = {
"${serviceAddress}:${builtins.toString servicePort}" = { };
};
nodes =
let
extraConfigLoc = ''
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
'';
in
{
${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
${webProxy}.services.nginx = confLib.genNginx { inherit serviceAddress servicePort serviceDomain serviceName extraConfigLoc; maxBody = 0; };
${homeWebProxy}.services.nginx = lib.mkIf isHome (confLib.genNginx { inherit servicePort serviceDomain serviceName extraConfigLoc; maxBody = 0; extraConfig = nginxAccessRules; serviceAddress = homeServiceAddress; });
};
virtualHosts = {
"${serviceDomain}" = {
useACMEHost = globals.domains.main;
forceSSL = true;
acmeRoot = null;
locations = {
"/" = {
proxyPass = "http://${serviceName}";
extraConfig = ''
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
'';
};
};
};
};
};
};
}

View file

@ -1,7 +1,8 @@
{ self, 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 proxyAddress4 proxyAddress6 isHome webProxy dnsServer;
inherit (confLib.gen { name = "mailserver"; dir = "/var/lib/dovecot"; user = "virtualMail"; group = "virtualMail"; port = 443; }) serviceName serviceDir servicePort serviceUser serviceGroup serviceAddress serviceDomain proxyAddress4 proxyAddress6;
inherit (confLib.static) isHome webProxy homeWebProxy dnsServer homeServiceAddress nginxAccessRules;
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;
@ -15,11 +16,6 @@ in
};
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 endpointAddress4 endpointAddress6;
"${globals.services.roundcube.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
globals.services = {
${serviceName} = {
domain = serviceDomain;
@ -139,33 +135,21 @@ in
};
};
nodes.${webProxy}.services.nginx = {
upstreams = {
${serviceName} = {
servers = {
"${serviceAddress}:${builtins.toString servicePort}" = { };
};
nodes =
let
extraConfigLoc = ''
proxy_ssl_server_name on;
proxy_ssl_name ${roundcubeDomain};
'';
in
{
${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host endpointAddress4 endpointAddress6;
"${globals.services.roundcube.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
${webProxy}.services.nginx = confLib.genNginx { inherit serviceAddress servicePort serviceName extraConfigLoc; serviceDomain = roundcubeDomain; maxBody = 0; };
${homeWebProxy}.services.nginx = lib.mkIf isHome (confLib.genNginx { inherit servicePort serviceName extraConfigLoc; serviceDomain = roundcubeDomain; maxBody = 0; extraConfig = nginxAccessRules; serviceAddress = homeServiceAddress; });
};
virtualHosts = {
"${roundcubeDomain}" = {
useACMEHost = globals.domains.main;
forceSSL = true;
acmeRoot = null;
locations = {
"/" = {
proxyPass = "https://${serviceName}";
extraConfig = ''
client_max_body_size 0;
proxy_ssl_server_name on;
proxy_ssl_name ${roundcubeDomain};
'';
};
};
};
};
};
};
}

View file

@ -1,7 +1,8 @@
{ 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 proxyAddress4 proxyAddress6 isHome isProxied homeProxy webProxy dnsServer homeProxyIf webProxyIf;
inherit (confLib.gen { name = "matrix"; user = "matrix-synapse"; port = 8008; }) servicePort serviceName serviceUser serviceDomain serviceAddress proxyAddress4 proxyAddress6;
inherit (confLib.static) isHome isProxied webProxy homeWebProxy dnsServer homeProxyIf webProxyIf homeServiceAddress nginxAccessRules;
federationPort = 8448;
whatsappPort = 29318;
@ -20,10 +21,6 @@ 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;
};
environment.systemPackages = with pkgs; [
matrix-synapse
lottieconverter
@ -97,7 +94,7 @@ in
${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort federationPort ];
};
${homeProxyIf}.hosts = lib.mkIf isHome {
${config.node.name}.firewallRuleForNode.${homeProxy}.allowedTCPPorts = [ servicePort ];
${config.node.name}.firewallRuleForNode.${homeWebProxy}.allowedTCPPorts = [ servicePort ];
};
};
services.${serviceName} = {
@ -303,60 +300,72 @@ in
# messages out after a while.
nodes.${webProxy}.services.nginx = {
upstreams = {
${serviceName} = {
servers = {
"${serviceAddress}:${builtins.toString servicePort}" = { };
};
};
};
virtualHosts = {
"${serviceDomain}" = {
useACMEHost = globals.domains.main;
forceSSL = true;
acmeRoot = null;
listen = [
{
addr = "0.0.0.0";
port = 8448;
ssl = true;
extraParameters = [
"default_server"
];
}
{
addr = "[::0]";
port = 8448;
ssl = true;
extraParameters = [
"default_server"
];
}
{
addr = "0.0.0.0";
port = 443;
ssl = true;
}
{
addr = "[::0]";
port = 443;
ssl = true;
}
];
locations = {
"~ ^(/_matrix|/_synapse/client)" = {
proxyPass = "http://${serviceName}";
extraConfig = ''
client_max_body_size 0;
'';
nodes =
let
genNginx = toAddress: extraConfig: {
upstreams = {
${serviceName} = {
servers = {
"${toAddress}:${builtins.toString servicePort}" = { };
};
};
};
virtualHosts = {
"${serviceDomain}" = {
useACMEHost = globals.domains.main;
forceSSL = true;
acmeRoot = null;
listen = [
{
addr = "0.0.0.0";
port = 8448;
ssl = true;
extraParameters = [
"default_server"
];
}
{
addr = "[::0]";
port = 8448;
ssl = true;
extraParameters = [
"default_server"
];
}
{
addr = "0.0.0.0";
port = 443;
ssl = true;
}
{
addr = "[::0]";
port = 443;
ssl = true;
}
];
inherit extraConfig;
locations = {
"~ ^(/_matrix|/_synapse/client)" = {
proxyPass = "http://${serviceName}";
extraConfig = ''
client_max_body_size 0;
'';
};
"= /.well-known/matrix/server".extraConfig = mkWellKnown serverConfig;
"= /.well-known/matrix/client".extraConfig = mkWellKnown clientConfig;
};
};
"= /.well-known/matrix/server".extraConfig = mkWellKnown serverConfig;
"= /.well-known/matrix/client".extraConfig = mkWellKnown clientConfig;
};
};
in
{
${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
${webProxy}.services.nginx = genNginx serviceAddress "";
${homeWebProxy}.services.nginx = genNginx homeServiceAddress nginxAccessRules;
};
};
};
}

View file

@ -1,6 +1,7 @@
{ self, lib, config, dns, globals, confLib, ... }:
let
inherit (confLib.gen { name = "microbin"; port = 8777; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress proxyAddress4 proxyAddress6 isHome isProxied homeProxy webProxy dnsServer homeProxyIf webProxyIf;
inherit (confLib.gen { name = "microbin"; port = 8777; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress proxyAddress4 proxyAddress6;
inherit (confLib.static) isHome isProxied webProxy homeWebProxy dnsServer homeProxyIf webProxyIf homeServiceAddress nginxAccessRules;
inherit (config.swarselsystems) sopsFile;
@ -10,10 +11,6 @@ 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;
};
users = {
groups.${serviceGroup} = { };
@ -56,7 +53,7 @@ in
${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort ];
};
${homeProxyIf}.hosts = lib.mkIf isHome {
${config.node.name}.firewallRuleForNode.${homeProxy}.allowedTCPPorts = [ servicePort ];
${config.node.name}.firewallRuleForNode.${homeWebProxy}.allowedTCPPorts = [ servicePort ];
};
};
services.${serviceName} = {
@ -115,30 +112,12 @@ in
{ directory = cfg.dataDir; user = serviceUser; group = serviceGroup; mode = "0700"; }
];
nodes.${webProxy}.services.nginx = {
upstreams = {
${serviceName} = {
servers = {
"${serviceAddress}:${builtins.toString servicePort}" = { };
};
};
};
virtualHosts = {
"${serviceDomain}" = {
useACMEHost = globals.domains.main;
forceSSL = true;
acmeRoot = null;
locations = {
"/" = {
proxyPass = "http://${serviceName}";
extraConfig = ''
client_max_body_size 1G;
'';
};
};
};
nodes = {
${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
${webProxy}.services.nginx = confLib.genNginx { inherit serviceAddress servicePort serviceDomain serviceName; maxBody = 1; maxBodyUnit = "G"; };
${homeWebProxy}.services.nginx = lib.mkIf isHome (confLib.genNginx { inherit servicePort serviceDomain serviceName; maxBody = 1; maxBodyUnit = "G"; extraConfig = nginxAccessRules; serviceAddress = homeServiceAddress; });
};
};

View file

@ -1,6 +1,7 @@
{ self, 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 isHome dnsServer;
inherit (confLib.gen { name = "minecraft"; port = 25565; dir = "/opt/minecraft"; proxy = config.node.name; }) serviceName servicePort serviceDir serviceDomain proxyAddress4 proxyAddress6;
inherit (confLib.static) isHome dnsServer;
inherit (config.swarselsystems) mainUser;
worldName = "${mainUser}craft";
in

View file

@ -1,6 +1,7 @@
{ lib, config, globals, dns, confLib, ... }:
let
inherit (confLib.gen { name = "grafana"; port = 3000; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress proxyAddress4 proxyAddress6 isHome isProxied homeProxy webProxy dnsServer homeProxyIf webProxyIf;
inherit (confLib.gen { name = "grafana"; port = 3000; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress proxyAddress4 proxyAddress6;
inherit (confLib.static) isHome isProxied webProxy homeWebProxy dnsServer homeProxyIf webProxyIf homeServiceAddress nginxAccessRules;
prometheusPort = 9090;
prometheusUser = "prometheus";
@ -18,10 +19,6 @@ 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;
};
sops = {
secrets = {
grafana-admin-pw = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; };
@ -66,7 +63,7 @@ in
${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort prometheusPort ];
};
${homeProxyIf}.hosts = lib.mkIf isHome {
${config.node.name}.firewallRuleForNode.${homeProxy}.allowedTCPPorts = [ servicePort prometheusPort ];
${config.node.name}.firewallRuleForNode.${homeWebProxy}.allowedTCPPorts = [ servicePort prometheusPort ];
};
};
services.${serviceName} = {
@ -222,42 +219,55 @@ in
};
nodes.${webProxy}.services.nginx = {
upstreams = {
"${grafanaUpstream}" = {
servers = {
"${serviceAddress}:${builtins.toString servicePort}" = { };
nodes =
let
genNginx = toAddress: extraConfigPre: {
upstreams = {
"${grafanaUpstream}" = {
servers = {
"${toAddress}:${builtins.toString servicePort}" = { };
};
};
"${prometheusUpstream}" = {
servers = {
"${toAddress}:${builtins.toString prometheusPort}" = { };
};
};
};
};
"${prometheusUpstream}" = {
servers = {
"${serviceAddress}:${builtins.toString prometheusPort}" = { };
};
};
};
virtualHosts = {
"${serviceDomain}" = {
useACMEHost = globals.domains.main;
virtualHosts = {
"${serviceDomain}" = {
useACMEHost = globals.domains.main;
forceSSL = true;
acmeRoot = null;
locations = {
"/" = {
proxyPass = "http://${grafanaUpstream}";
proxyWebsockets = true;
extraConfig = ''
client_max_body_size 0;
'';
};
"/${prometheusWebRoot}" = {
proxyPass = "http://${prometheusUpstream}";
extraConfig = ''
client_max_body_size 0;
'';
forceSSL = true;
acmeRoot = null;
extraConfig = extraConfigPre;
locations =
let
extraConfig = ''
client_max_body_size 0;
'';
in
{
"/" = {
proxyPass = "http://${grafanaUpstream}";
proxyWebsockets = true;
inherit extraConfig;
};
"/${prometheusWebRoot}" = {
proxyPass = "http://${prometheusUpstream}";
inherit extraConfig;
};
};
};
};
};
in
{
${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
${webProxy}.services.nginx = genNginx serviceAddress "";
${homeWebProxy}.services.nginx = genNginx homeServiceAddress nginxAccessRules;
};
};
};
}

View file

@ -1,14 +1,12 @@
{ pkgs, config, lib, globals, dns, confLib, ... }:
let
inherit (confLib.gen { name = "navidrome"; port = 4040; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress proxyAddress4 proxyAddress6 isHome isProxied homeProxy webProxy dnsServer homeProxyIf webProxyIf;
inherit (confLib.gen { name = "navidrome"; port = 4040; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress proxyAddress4 proxyAddress6;
inherit (confLib.static) isHome isProxied webProxy homeWebProxy dnsServer homeProxyIf webProxyIf nginxAccessRules homeServiceAddress;
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;
};
environment.systemPackages = with pkgs; [
pciutils
@ -47,7 +45,7 @@ in
${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort ];
};
${homeProxyIf}.hosts = lib.mkIf isHome {
${config.node.name}.firewallRuleForNode.${homeProxy}.allowedTCPPorts = [ servicePort ];
${config.node.name}.firewallRuleForNode.${homeWebProxy}.allowedTCPPorts = [ servicePort ];
};
};
services.${serviceName} = {
@ -118,58 +116,69 @@ in
};
};
nodes.${webProxy}.services.nginx = {
upstreams = {
${serviceName} = {
servers = {
"${serviceAddress}:${builtins.toString servicePort}" = { };
};
};
};
virtualHosts = {
"${serviceDomain}" = {
useACMEHost = globals.domains.main;
forceSSL = true;
acmeRoot = null;
oauth2.enable = true;
oauth2.allowedGroups = [ "navidrome_access" ];
locations =
let
extraConfig = ''
proxy_redirect http:// https://;
proxy_read_timeout 600s;
proxy_send_timeout 600s;
proxy_buffering off;
proxy_request_buffering off;
client_max_body_size 0;
'';
in
{
"/" = {
proxyPass = "http://${serviceName}";
proxyWebsockets = true;
inherit extraConfig;
};
"/share" = {
proxyPass = "http://${serviceName}";
proxyWebsockets = true;
setOauth2Headers = false;
bypassAuth = true;
inherit extraConfig;
};
"/rest" = {
proxyPass = "http://${serviceName}";
proxyWebsockets = true;
setOauth2Headers = false;
bypassAuth = true;
inherit extraConfig;
nodes =
let
genNginx = toAddress: extraConfigPre: {
upstreams = {
${serviceName} = {
servers = {
"${toAddress}:${builtins.toString servicePort}" = { };
};
};
};
virtualHosts = {
"${serviceDomain}" = {
useACMEHost = globals.domains.main;
forceSSL = true;
acmeRoot = null;
oauth2 = {
enable = true;
allowedGroups = [ "navidrome_access" ];
};
extraConfig = extraConfigPre;
locations =
let
extraConfig = ''
proxy_redirect http:// https://;
proxy_read_timeout 600s;
proxy_send_timeout 600s;
proxy_buffering off;
proxy_request_buffering off;
client_max_body_size 0;
'';
in
{
"/" = {
proxyPass = "http://${serviceName}";
proxyWebsockets = true;
inherit extraConfig;
};
"/share" = {
proxyPass = "http://${serviceName}";
proxyWebsockets = true;
setOauth2Headers = false;
bypassAuth = true;
inherit extraConfig;
};
"/rest" = {
proxyPass = "http://${serviceName}";
proxyWebsockets = true;
setOauth2Headers = false;
bypassAuth = true;
inherit extraConfig;
};
};
};
};
};
in
{
${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
${webProxy}.services.nginx = genNginx serviceAddress "";
${homeWebProxy}.services.nginx = lib.mkIf isHome (genNginx homeServiceAddress nginxAccessRules);
};
};
};
}

View file

@ -2,7 +2,8 @@
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 proxyAddress4 proxyAddress6 isHome dnsServer webProxy;
inherit (confLib.gen { name = "nextcloud"; port = 80; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress proxyAddress4 proxyAddress6;
inherit (confLib.static) isHome dnsServer webProxy homeWebProxy homeServiceAddress nginxAccessRules;
nextcloudVersion = "32";
in
@ -10,10 +11,6 @@ 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;
};
sops.secrets = {
nextcloud-admin-pw = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; };
kanidm-nextcloud-client = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; };
@ -50,30 +47,13 @@ in
};
};
nodes.${webProxy}.services.nginx = {
upstreams = {
${serviceName} = {
servers = {
"${serviceAddress}:${builtins.toString servicePort}" = { };
};
};
};
virtualHosts = {
"${serviceDomain}" = {
useACMEHost = globals.domains.main;
forceSSL = true;
acmeRoot = null;
locations = {
"/" = {
proxyPass = "http://${serviceName}";
extraConfig = ''
client_max_body_size 0;
'';
};
};
};
nodes = {
${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
${webProxy}.services.nginx = confLib.genNginx { inherit serviceAddress servicePort serviceDomain serviceName; maxBody = 0; };
${homeWebProxy}.services.nginx = lib.mkIf isHome (confLib.genNginx { inherit servicePort serviceDomain serviceName; maxBody = 0; extraConfig = nginxAccessRules; serviceAddress = homeServiceAddress; });
};
};
}

View file

@ -1,7 +1,7 @@
{ lib, config, globals, dns, confLib, ... }:
let
inherit (confLib.gen { name = "oauth2-proxy"; port = 3004; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress proxyAddress4 proxyAddress6;
inherit (confLib.static) isHome isProxied homeProxy webProxy dnsServer homeProxyIf webProxyIf homeWebProxy oauthServer nginxAccessRules;
inherit (confLib.static) isHome isProxied webProxy homeWebProxy dnsServer homeProxyIf webProxyIf oauthServer nginxAccessRules;
kanidmDomain = globals.services.kanidm.domain;
mainDomain = globals.domains.main;
@ -139,7 +139,8 @@ in
};
};
# networking.firewall.allowedTCPPorts = [ servicePort ];
# needed for homeWebProxy
networking.firewall.allowedTCPPorts = [ servicePort ];
globals = {
networks = {
@ -147,7 +148,7 @@ in
${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort ];
};
${homeProxyIf}.hosts = lib.mkIf isHome {
${config.node.name}.firewallRuleForNode.${homeProxy}.allowedTCPPorts = [ servicePort ];
${config.node.name}.firewallRuleForNode.${homeWebProxy}.allowedTCPPorts = [ servicePort ];
};
};
services.${serviceName} = {
@ -207,39 +208,17 @@ in
nodes =
let
genNginx = toAddress: extraConfig: {
upstreams = {
${serviceName} = {
servers = {
"${toAddress}:${builtins.toString servicePort}" = { };
};
};
};
virtualHosts = {
"${serviceDomain}" = {
useACMEHost = globals.domains.main;
forceSSL = true;
acmeRoot = null;
locations = {
"/" = {
proxyPass = "http://${serviceName}";
};
};
extraConfig = ''
proxy_set_header X-Scheme $scheme;
proxy_set_header X-Auth-Request-Redirect $scheme://$host$request_uri;
'' + lib.optionalString (extraConfig != "") extraConfig;
};
};
};
extraConfig = ''
proxy_set_header X-Scheme $scheme;
proxy_set_header X-Auth-Request-Redirect $scheme://$host$request_uri;
'';
in
{
${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
${webProxy}.services.nginx = genNginx serviceAddress "";
${homeWebProxy}.services.nginx = genNginx globals.hosts.${oauthServer}.wanAddress4 nginxAccessRules;
${webProxy}.services.nginx = confLib.genNginx { inherit servicePort serviceAddress serviceDomain serviceName extraConfig; protocol = "https"; };
${homeWebProxy}.services.nginx = confLib.genNginx { inherit servicePort serviceDomain serviceName; protocol = "https"; extraConfig = extraConfig + nginxAccessRules; serviceAddress = globals.hosts.${oauthServer}.wanAddress4; };
};
};
}

View file

@ -1,7 +1,8 @@
{ lib, pkgs, config, dns, globals, confLib, ... }:
let
inherit (config.swarselsystems) sopsFile;
inherit (confLib.gen { name = "paperless"; port = 28981; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress proxyAddress4 proxyAddress6 isHome isProxied homeProxy webProxy dnsServer homeProxyIf webProxyIf;
inherit (confLib.gen { name = "paperless"; port = 28981; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress proxyAddress4 proxyAddress6;
inherit (confLib.static) isHome isProxied webProxy homeWebProxy dnsServer homeProxyIf webProxyIf homeServiceAddress nginxAccessRules;
tikaPort = 9998;
gotenbergPort = 3002;
@ -11,10 +12,6 @@ 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;
};
users.users.${serviceUser} = {
extraGroups = [ "users" ];
};
@ -32,7 +29,7 @@ in
${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort ];
};
${homeProxyIf}.hosts = lib.mkIf isHome {
${config.node.name}.firewallRuleForNode.${homeProxy}.allowedTCPPorts = [ servicePort ];
${config.node.name}.firewallRuleForNode.${homeWebProxy}.allowedTCPPorts = [ servicePort ];
};
};
services.${serviceName} = {
@ -109,35 +106,22 @@ in
)
'';
nodes.${webProxy}.services.nginx = {
upstreams = {
${serviceName} = {
servers = {
"${serviceAddress}:${builtins.toString servicePort}" = { };
};
nodes =
let
extraConfigLoc = ''
proxy_connect_timeout 300;
proxy_send_timeout 300;
proxy_read_timeout 300;
send_timeout 300;
'';
in
{
${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
${webProxy}.services.nginx = confLib.genNginx { inherit serviceAddress servicePort serviceDomain serviceName extraConfigLoc; maxBody = 0; };
${homeWebProxy}.services.nginx = lib.mkIf isHome (confLib.genNginx { inherit servicePort serviceDomain serviceName extraConfigLoc; maxBody = 0; extraConfig = nginxAccessRules; serviceAddress = homeServiceAddress; });
};
virtualHosts = {
"${serviceDomain}" = {
useACMEHost = globals.domains.main;
forceSSL = true;
acmeRoot = null;
locations = {
"/" = {
proxyPass = "http://${serviceName}";
extraConfig = ''
client_max_body_size 0;
proxy_connect_timeout 300;
proxy_send_timeout 300;
proxy_read_timeout 300;
send_timeout 300;
'';
};
};
};
};
};
};
}

View file

@ -26,7 +26,7 @@ in
};
local-to-podman = {
from = [ "local" "wgProxy" "wgHme" ];
from = [ "local" "wgProxy" "wgHome" ];
to = [ "podman" ];
before = [ "drop" ];
verdict = "accept";

View file

@ -1,6 +1,7 @@
{ lib, config, globals, dns, confLib, ... }:
let
inherit (confLib.gen { name = "radicale"; port = 8000; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress proxyAddress4 proxyAddress6 isHome isProxied homeProxy webProxy dnsServer homeProxyIf webProxyIf;
inherit (confLib.gen { name = "radicale"; port = 8000; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress proxyAddress4 proxyAddress6;
inherit (confLib.static) isHome isProxied webProxy homeWebProxy dnsServer homeProxyIf webProxyIf homeServiceAddress nginxAccessRules;
inherit (config.swarselsystems) sopsFile;
cfg = config.services.${serviceName};
@ -9,10 +10,6 @@ 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;
};
sops = {
secrets.radicale-user = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; };
@ -40,7 +37,7 @@ in
${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort ];
};
${homeProxyIf}.hosts = lib.mkIf isHome {
${config.node.name}.firewallRuleForNode.${homeProxy}.allowedTCPPorts = [ servicePort ];
${config.node.name}.firewallRuleForNode.${homeWebProxy}.allowedTCPPorts = [ servicePort ];
};
};
services.${serviceName} = {
@ -100,33 +97,13 @@ in
# networking.firewall.allowedTCPPorts = [ servicePort ];
nodes.${webProxy}.services.nginx = {
upstreams = {
${serviceName} = {
servers = {
"${serviceAddress}:${builtins.toString servicePort}" = { };
};
};
};
virtualHosts = {
"${serviceDomain}" = {
useACMEHost = globals.domains.main;
forceSSL = true;
acmeRoot = null;
oauth2.enable = false;
locations = {
"/" = {
proxyPass = "http://${serviceName}";
extraConfig = ''
client_max_body_size 16M;
'';
};
};
};
nodes = {
${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
${webProxy}.services.nginx = confLib.genNginx { inherit serviceAddress servicePort serviceDomain serviceName; maxBody = 16; maxBodyUnit = "M"; };
${homeWebProxy}.services.nginx = lib.mkIf isHome (confLib.genNginx { inherit servicePort serviceDomain serviceName; maxBody = 16; maxBodyUnit = "M"; extraConfig = nginxAccessRules; serviceAddress = homeServiceAddress; });
};
};
}

View file

@ -1,4 +1,4 @@
{ lib, config, globals, confLib, ... }:
{ lib, config, globals, ... }:
let
serviceName = "router";
bridgeVLANs = lib.mapAttrsToList
@ -9,7 +9,7 @@ let
selectVLANs = vlans: map (vlan: { VLAN = globals.networks.home-lan.vlans.${vlan}.id; }) vlans;
lan5VLANs = selectVLANs [ "home" "devices" "guests" ];
lan4VLANs = selectVLANs [ "home" "services" ];
inherit (confLib.gen { }) homeDnsServer;
inherit (globals.general) homeDnsServer;
in
{
options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
@ -47,7 +47,7 @@ in
rules = {
masquerade-internet = {
from = map (name: "vlan-${name}") (globals.general.internetVLANs);
from = map (name: "vlan-${name}") globals.general.internetVLANs;
to = [ "untrusted" ];
# masquerade = true; NOTE: custom rule below for ip4 + ip6
late = true; # Only accept after any rejects have been processed
@ -56,7 +56,7 @@ in
# Allow access to the AdGuardHome DNS server from any VLAN that has internet access
access-adguardhome-dns = {
from = map (name: "vlan-${name}") (globals.general.internetVLANs);
from = map (name: "vlan-${name}") globals.general.internetVLANs;
to = [ "adguardhome" ];
verdict = "accept";
};
@ -94,7 +94,7 @@ in
late = true;
rules =
lib.forEach
(map (name: "vlan-${name}") (globals.general.internetVLANs))
(map (name: "vlan-${name}") globals.general.internetVLANs)
(
zone:
lib.concatStringsSep " " [

View file

@ -1,6 +1,7 @@
{ self, lib, config, dns, globals, confLib, ... }:
let
inherit (confLib.gen { name = "shlink"; port = 8081; dir = "/var/lib/shlink"; }) servicePort serviceName serviceDomain serviceDir serviceAddress proxyAddress4 proxyAddress6 isHome isProxied homeProxy webProxy dnsServer homeProxyIf webProxyIf;
inherit (confLib.gen { name = "shlink"; port = 8081; dir = "/var/lib/shlink"; }) servicePort serviceName serviceDomain serviceDir serviceAddress proxyAddress4 proxyAddress6;
inherit (confLib.static) isHome isProxied webProxy homeWebProxy dnsServer homeProxyIf webProxyIf homeServiceAddress nginxAccessRules;
containerRev = "sha256:1a697baca56ab8821783e0ce53eb4fb22e51bb66749ec50581adc0cb6d031d7a";
@ -16,10 +17,6 @@ in
podman = true;
};
nodes.${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
sops = {
secrets = {
shlink-api = { inherit sopsFile; };
@ -92,7 +89,7 @@ in
${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort ];
};
${homeProxyIf}.hosts = lib.mkIf isHome {
${config.node.name}.firewallRuleForNode.${homeProxy}.allowedTCPPorts = [ servicePort ];
${config.node.name}.firewallRuleForNode.${homeWebProxy}.allowedTCPPorts = [ servicePort ];
};
};
services.${serviceName} = {
@ -101,26 +98,13 @@ in
};
};
nodes.${webProxy}.services.nginx = {
upstreams = {
${serviceName} = {
servers = {
"${serviceAddress}:${builtins.toString servicePort}" = { };
};
};
};
virtualHosts = {
"${serviceDomain}" = {
useACMEHost = globals.domains.main;
forceSSL = true;
acmeRoot = null;
locations = {
"/" = {
proxyPass = "http://${serviceName}";
};
};
};
nodes = {
${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
${webProxy}.services.nginx = confLib.genNginx { inherit serviceAddress servicePort serviceDomain serviceName; maxBody = 0; };
${homeWebProxy}.services.nginx = lib.mkIf isHome (confLib.genNginx { inherit servicePort serviceDomain serviceName; maxBody = 0; extraConfig = nginxAccessRules; serviceAddress = homeServiceAddress; });
};
};
}

View file

@ -1,6 +1,7 @@
{ self, lib, config, dns, globals, confLib, ... }:
let
inherit (confLib.gen { name = "slink"; port = 3000; dir = "/var/lib/slink"; }) servicePort serviceName serviceDomain serviceDir serviceAddress proxyAddress4 proxyAddress6 isHome isProxied homeProxy webProxy dnsServer homeProxyIf webProxyIf;
inherit (confLib.gen { name = "slink"; port = 3000; dir = "/var/lib/slink"; }) servicePort serviceName serviceDomain serviceDir serviceAddress proxyAddress4 proxyAddress6;
inherit (confLib.static) isHome isProxied webProxy homeWebProxy dnsServer homeProxyIf webProxyIf homeServiceAddress nginxAccessRules;
containerRev = "sha256:98b9442696f0a8cbc92f0447f54fa4bad227af5dcfd6680545fedab2ed28ddd9";
in
@ -14,10 +15,6 @@ in
podman = true;
};
nodes.${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
virtualisation.oci-containers.containers.${serviceName} = {
image = "anirdev/slink@${containerRev}";
environment = {
@ -69,7 +66,7 @@ in
${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort ];
};
${homeProxyIf}.hosts = lib.mkIf isHome {
${config.node.name}.firewallRuleForNode.${homeProxy}.allowedTCPPorts = [ servicePort ];
${config.node.name}.firewallRuleForNode.${homeWebProxy}.allowedTCPPorts = [ servicePort ];
};
};
services.${serviceName} = {
@ -78,34 +75,48 @@ in
};
};
nodes.${webProxy}.services.nginx = {
upstreams = {
${serviceName} = {
servers = {
"${serviceAddress}:${builtins.toString servicePort}" = { };
nodes =
let
genNginx = toAddress: extraConfig: {
upstreams = {
${serviceName} = {
servers = {
"${toAddress}:${builtins.toString servicePort}" = { };
};
};
};
};
};
virtualHosts = {
"${serviceDomain}" = {
useACMEHost = globals.domains.main;
virtualHosts = {
"${serviceDomain}" = {
useACMEHost = globals.domains.main;
forceSSL = true;
acmeRoot = null;
oauth2.enable = true;
oauth2.allowedGroups = [ "slink_access" ];
locations = {
"/" = {
proxyPass = "http://${serviceName}";
};
"/image" = {
proxyPass = "http://${serviceName}";
setOauth2Headers = false;
bypassAuth = true;
forceSSL = true;
acmeRoot = null;
oauth2 = {
enable = true;
allowedGroups = [ "slink_access" ];
};
inherit extraConfig;
locations = {
"/" = {
proxyPass = "http://${serviceName}";
};
"/image" = {
proxyPass = "http://${serviceName}";
setOauth2Headers = false;
bypassAuth = true;
};
};
};
};
};
in
{
${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
${webProxy}.services.nginx = genNginx serviceAddress "";
${homeWebProxy}.services.nginx = lib.mkIf isHome (genNginx homeServiceAddress nginxAccessRules);
};
};
};
}

View file

@ -1,6 +1,7 @@
{ lib, config, globals, dns, confLib, ... }:
let
inherit (confLib.gen { name = "snipeit"; port = 80; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress proxyAddress4 proxyAddress6 isHome webProxy dnsServer;
inherit (confLib.gen { name = "snipeit"; port = 80; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress proxyAddress4 proxyAddress6;
inherit (confLib.static) isHome isProxied webProxy homeWebProxy webProxyIf homeProxyIf dnsServer homeServiceAddress nginxAccessRules;
# sopsFile = config.node.secretsDir + "/secrets2.yaml";
inherit (config.swarselsystems) sopsFile;
@ -12,10 +13,6 @@ 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;
};
sops = {
secrets = {
snipe-it-appkey = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; };
@ -24,9 +21,19 @@ in
topology.self.services.${serviceName}.info = "https://${serviceDomain}";
globals.services.${serviceName} = {
domain = serviceDomain;
inherit proxyAddress4 proxyAddress6 isHome;
globals = {
networks = {
${webProxyIf}.hosts = lib.mkIf isProxied {
${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort ];
};
${homeProxyIf}.hosts = lib.mkIf isHome {
${config.node.name}.firewallRuleForNode.${homeWebProxy}.allowedTCPPorts = [ servicePort ];
};
};
services.${serviceName} = {
domain = serviceDomain;
inherit proxyAddress4 proxyAddress6 isHome;
};
};
services.snipe-it = {
@ -46,30 +53,13 @@ in
};
};
nodes.${webProxy}.services.nginx = {
upstreams = {
${serviceName} = {
servers = {
"${serviceAddress}:${builtins.toString servicePort}" = { };
};
};
};
virtualHosts = {
"${serviceDomain}" = {
useACMEHost = globals.domains.main;
forceSSL = true;
acmeRoot = null;
oauth2.enable = false;
locations = {
"/" = {
proxyPass = "http://${serviceName}";
};
};
};
nodes = {
${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
${webProxy}.services.nginx = confLib.genNginx { inherit serviceAddress servicePort serviceDomain serviceName; maxBody = 0; };
${homeWebProxy}.services.nginx = lib.mkIf isHome (confLib.genNginx { inherit servicePort serviceDomain serviceName; maxBody = 0; extraConfig = nginxAccessRules; serviceAddress = homeServiceAddress; });
};
};
}

View file

@ -1,7 +1,8 @@
{ lib, config, globals, dns, confLib, ... }:
let
inherit (config.swarselsystems.syncthing) serviceDomain;
inherit (confLib.gen { name = "syncthing"; port = 8384; }) servicePort serviceName serviceUser serviceGroup serviceAddress proxyAddress4 proxyAddress6 isHome isProxied homeProxy webProxy dnsServer homeProxyIf webProxyIf;
inherit (confLib.gen { name = "syncthing"; port = 8384; }) servicePort serviceName serviceUser serviceGroup serviceAddress proxyAddress4 proxyAddress6;
inherit (confLib.static) isHome isProxied webProxy homeWebProxy dnsServer homeProxyIf webProxyIf homeServiceAddress nginxAccessRules;
specificServiceName = "${serviceName}-${config.node.name}";
@ -42,10 +43,6 @@ in
};
config = lib.mkIf config.swarselmodules.server.${serviceName} {
nodes.${dnsServer}.swarselsystems.server.dns.${globals.services.${specificServiceName}.baseDomain}.subdomainRecords = {
"${globals.services.${specificServiceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
users.users.${serviceUser} = {
extraGroups = [ "users" ];
group = serviceGroup;
@ -65,7 +62,7 @@ in
};
};
${homeProxyIf}.hosts = lib.mkIf isHome {
${config.node.name}.firewallRuleForNode.${homeProxy} = {
${config.node.name}.firewallRuleForNode.${homeWebProxy} = {
allowedTCPPorts = [ servicePort 20000 ];
allowedUDPPorts = [ 20000 21027 ];
};
@ -131,30 +128,13 @@ in
};
};
nodes.${webProxy}.services.nginx = {
upstreams = {
${specificServiceName} = {
servers = {
"${serviceAddress}:${builtins.toString servicePort}" = { };
};
};
};
virtualHosts = {
"${serviceDomain}" = {
useACMEHost = globals.domains.main;
forceSSL = true;
acmeRoot = null;
locations = {
"/" = {
proxyPass = "http://${specificServiceName}";
extraConfig = ''
client_max_body_size 0;
'';
};
};
};
nodes = {
${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
${webProxy}.services.nginx = confLib.genNginx { inherit serviceAddress servicePort serviceDomain; serviceName = specificServiceName; maxBody = 0; };
${homeWebProxy}.services.nginx = lib.mkIf isHome (confLib.genNginx { inherit servicePort serviceDomain; serviceName = specificServiceName; maxBody = 0; extraConfig = nginxAccessRules; serviceAddress = homeServiceAddress; });
};
};
}

View file

@ -1,6 +1,7 @@
{ self, pkgs, lib, config, confLib, ... }:
let
inherit (confLib.gen { name = "transmission"; }) serviceName serviceDomain isHome;
inherit (confLib.gen { name = "transmission"; }) serviceName serviceDomain;
inherit (confLib.static) isHome;
lidarrUser = "lidarr";
lidarrGroup = lidarrUser;

View file

@ -35,11 +35,6 @@ in
serviceProxy = proxy;
proxyAddress4 = globals.hosts.${proxy}.wanAddress4 or null;
proxyAddress6 = globals.hosts.${proxy}.wanAddress6 or null;
inherit (globals.hosts.${config.node.name}) isHome;
inherit (globals.general) homeProxy webProxy dnsServer homeDnsServer homeWebProxy idmServer;
webProxyIf = "${webProxy}-wgProxy";
homeProxyIf = "home-wgHome";
isProxied = config.node.name != webProxy;
};
static = rec {
@ -97,6 +92,53 @@ in
};
}) else (_: { _ = { }; });
genNginx =
{ serviceAddress
, serviceName
, serviceDomain
, servicePort
, protocol ? "http"
, maxBody ? (-1)
, maxBodyUnit ? ""
, noSslVerify ? false
, proxyWebsockets ? false
, oauth2 ? false
, oauth2Groups ? [ ]
, extraConfig ? ""
, extraConfigLoc ? ""
}: {
upstreams = {
${serviceName} = {
servers = {
"${serviceAddress}:${builtins.toString servicePort}" = { };
};
};
};
virtualHosts = {
"${serviceDomain}" = {
useACMEHost = globals.domains.main;
forceSSL = true;
acmeRoot = null;
oauth2 = {
enable = lib.mkIf oauth2 true;
allowedGroups = lib.mkIf (oauth2Groups != [ ]) oauth2Groups;
};
locations = {
"/" = {
proxyPass = "${protocol}://${serviceName}";
proxyWebsockets = lib.mkIf proxyWebsockets true;
extraConfig = lib.optionalString (maxBody != (-1)) ''
client_max_body_size ${builtins.toString maxBody}${maxBodyUnit};
'' + extraConfigLoc;
};
};
extraConfig = lib.optionalString noSslVerify ''
proxy_ssl_verify off;
'' + extraConfig;
};
};
};
};
};
}

View file

@ -0,0 +1,11 @@
{ name, sops, homeConfig, writeShellApplication, ... }:
writeShellApplication {
inherit name;
runtimeInputs = [ sops ];
text = ''
sops updatekeys ${homeConfig.homeDirectory}/secrets/repo/*
sops updatekeys ${homeConfig.homeDirectory}/secrets/nginx/*
sops updatekeys ${homeConfig.homeDirectory}/secrets/work/*
sops updatekeys ${homeConfig.homeDirectory}/hosts/*/*/*/secrets/*/secrets.yaml
'';
}

View file

@ -10,19 +10,23 @@
"age": [
{
"recipient": "age1g7atkxdlt4ymeh7v7aa2yzr2hq2qkvzrc4r49ugttm3n582ymv9qrmpk8d",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBBWmFOUGZrbkNlQ2ppbnFw\nTVd3RVYrK1RocjU3Z0pPOUNpc05YZ0FKK2hJClAvdkZ0aFRtaE5PRWFNbWdWSjN3\nbWc1WUpuTTVDTlNldTh0ejBGakZvbDgKLS0tIHJaRmwwSEtqQXprcFZ3TlllWmJa\nczN6eE8wWUppc3o1VTRpcjF0VUM1azQKdWhbP34mx6yR6TXUMpP/npA9TjAayjqz\nHC7ztK5/zu4ML7BRCsoLNLDDVtMsmhEVKO8VV9sbMvusSq0WNu0I7g==\n-----END AGE ENCRYPTED FILE-----\n"
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBHU3ErUkRteVpGV2lFWUg5\nZTlwTWthRkZJRk5sR2pXTzZDdVhOSFY1T3hZCllQalcyR0E3UEN0SjhtbEVsTmM0\nNGxrRm1mUHFYVlpWaEpYYjMvbVlyRTAKLS0tIG5yV2RuMmxFSmFiVnZmaklBRFVY\nV0pDNW00cUdJdzFKNEN2bVQwT2FoVk0Ku1Rk8wsXyxWtgPZFoPpXB32IRRcTXLO5\nz+8H54pCpj+8+5Ew5GQOXW8wd3HXp4iggYuedp828ZjMbFbrZTTQBQ==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1cmzh82q8k59yzceuuy2epmqu22g7m84gqvq056mhgehwpmvjadfsc3glc8",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAxVUM5eTMrZ3lCeDgxVHlj\naWx4QUZ5c0NGV2xEaXliNHFyVktkTnBYR0d3CnRMcUgyUU1hNzhLcWhaYzJCMndR\nQWJyNEZJV2xNVVBSc2xnbzRqdEx1eXMKLS0tIDJhTGhVYkxJcGZ6N3dHZmV3QlBo\nNzBORDJXb1pRbVNiWHZiVjBKQjNwWDAK1z/XA6gRor2fNX70UooBqHjCFfIIP34j\n+vHx10dtoue5tSPgM3cA8QZzqM6Ht+U282JFMztrlDtiz/j/JofTNg==\n-----END AGE ENCRYPTED FILE-----\n"
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBCSHVlbXJyMG1tUGI0SVN2\nQW9CamttbFpySm1XdWRuVTZxcUJaQTV4dmdjCnhVcTVaVHZFUmxiMUVycXc0cmFP\nQ0pTZEJzUjBGaTB4VXd1RExTaDVWdTQKLS0tIDFVK3UxMHVQMkNsQjMwWW43cjht\neVdNbE1iM1h1UDRuLzRIQWJJTXpTTG8K8cn+NWUEHDGUWjqyt5fkNkQffOYLcrYM\nDsxuV9NeRwJ6uoTmeDVF+6R9HhZ4cz6TlklcXclfod6DOhu+rio81Q==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1nanlervuderw4qskcuessycqy2yfmptl6nym9scgp9ky2265ssmq3u73r0",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBwU09YQkFuK3JYZnlsOFlw\ndTM0U3U4MVAzMXpBckRWSk1ibVdkME5lT1RjClNIZDJUQXowYzljQ2hJSTdzaGJF\nRjAvekEzbHVtSzAweWtBSjVmTnBHNDgKLS0tIGp4MjRvWnJQNWNvWW1uQmRNbDFk\nZnpXNFhXcDdOQVU1bUdTa05XaFJYd3cKi8/U+tAGtrPL0RMc5HMFrViXW1lQhli7\nBBc98cm3GhzvbJM3y0Dcjy7DWkXTiFXbhplqFjp+spz9LfYP5VuafQ==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2025-12-04T19:04:02Z",
"mac": "ENC[AES256_GCM,data:nWV/knCo/MeWTBrfq1VlV6SPEQ2i2P+le82S2So0BIxPfz8tqan0MdaIaKLFlapsT9VRJOv8ZCCXSLWeGcbEvfmEz4MP1E4iHcU/4YaO+n895D1JrjeyP1cgGisnXqe01xMXCsDY178sqxHcnDDlXp9foCem+mGjIlKGPYGu5Oo=,iv:qbavbW3MF4fx+E3aybBYaz/T/Hb63ggWml4Oe9WFz+I=,tag:05vBbBGDGRNaXJWoZn1bVw==,type:str]",
"pgp": [
{
"created_at": "2025-12-22T14:07:12Z",
"enc": "-----BEGIN PGP MESSAGE-----\n\nhQIMAwDh3VI7VctTAQ//XZNxhn6vCEDo6SAtlIcA5OxNuj3326ITbjjv+XwiTHk/\n28cErtXOF+4bnjIXLwXGbbewWgvrnK0Lx5nBqpidMrhANHVEWDp3iBrW79QPdRl9\ntIcofQUK+6Dwh+XqJK4eorEAeAKlu6l5y3pc19L4j7BiDOxcXBYqTx4ScnZhFFoc\nRVC6ngRjck+2e6bL/+lopntHML41yrXpAHMBlobTbzYP8cnfMKroUZzLoNareVIS\nNlcE7oaCwAvCXYBbQN5qQCIFbLBFB+vD4ArOrL/zNxWVjnEeM4RhBdIjd0bdq1FQ\nLBsO1crEniz4Lgp5N4cWOzuOCz5fHlLJEKtNIIFt8rcocBEdyQf1OmZ2VrY57nN+\nSeCYGN+fPA87UoH+iZcmLNjDvMy+MHNIiGCEuY9jWLzgcDDvtFwtQdl2CpI8a/Ax\nKG9RgMFyjLtPCgNzDkn6LrvHKtnFkcsx22f8PHB4RZIgP43loH//xieOVnA9vo/k\nV3pRHZuZkTp3qmAED3KhbjE7aKP3bjUkJdrTATsal5YyRd76pjPvtXkX6MchgTgh\n6emt6DssvWJy5vhgitM0Ucq1IeeaLwIDTXqP5GShcQrWJ2P5ilzLGp2OKYzOqSBf\n//LfA3EHq4aFaTGuOVxjf/VS1vEeIAMaAo4eo86unIIhcQ6OBVAKzKfrSgzV9iiF\nAgwDC9FRLmchgYQBEACFwFYn12YCzYIwpSfJ7Apo5nEiLYbcD1wXR7bx7MFjJFxc\ncrS6yB/44y6a+OJfTLEVpDTPahKiOFAlmMAb8B05bDd/jqairwJPS+Sw2t/Tb6Ry\nToHi8ucg0+P8b0j+VeXoE0DlnuSMKbKQGvIq9fd8G6FymHppA4TpuKFl0QPUAbX7\nGLQbApk7gRoZK1XTQ/HKjyXdhfRogo8/07oRt6iO3nxC5NkLS/uxk/0ODqiFTGVg\nESkGQK3YQcr8hhhM467S49nzh+AQODgCTm7jSFO8kJwDP6eb5vF63qrIBZNUGc6j\nIoNHzQxqDoaFUd2GZcKg2Zsyizb91qYEMZdHUh51h1XH+jhg8G+L7I+hnBbzIj/o\naZfXALcmYNiI630SsiqA4iSufWy1bONnP0kHPSxVBqilLXpmfzIuNUwrZSQB+ZbR\nkIIA5lRqu1jWIcG/3CGQQMDfjqxus4Wt8bvGfOrbQk2qNs+l3uPb0+OBDNKQfVHD\nenXkTGrKIHt4YqnDc3ziWNAULwvRPviPQZPkJwPCDHdfA2bcQqLJOIYiBF1TdN9o\nv2eMQoTalEXfHOI5ndULjlyy5DaW2ZBKAgtH/WXg/O7ey5Q9e9QcnmwbOezEWx6x\nNNY3eoQs5LYxoWO7cEUv2MiEqY7ZWkrwmwcWzRV/7UmspvPHKULQV/fiNWb1yNJc\nATKv+sla0n0DzD+7BSiFcYC0ZvGAErYAwNIYhlgMEN7okuCscB+tz1d0yLhNt8DK\nZAn0NkIVnTn6esHqhp233ZmCrCmUezccMMINs8xQbqJR8bkns5hTDYLY48s=\n=v2/q\n-----END PGP MESSAGE-----",
"created_at": "2026-01-04T22:59:24Z",
"enc": "-----BEGIN PGP MESSAGE-----\n\nhQIMAwDh3VI7VctTARAA0D1lQY8D94Q1cu8g0UihoaImiVUXK944yuayfPO95rlj\nb9De1VOUKsUBE2wGpxwisOa12NG1a52bVVFbVUDBz2vLy4956/EjgP7CZds7OKHj\nbPxIdA75fA8QVHUVkI4AHKFebQU6OsLdOcB5pjqDlkKzmPUihwgtLCI6UfOyx4Se\n7ADHYKj24igh1Xxd2G3HzngYAQ20zn434TK/dr48yeQfNTYODtMJCdfVoYU4/bWD\n4jDdoKA0B/WdvPlJtYar+yvQxQiom2myXeeLXt8yUN5ugJkGNeFYl9JtlpchuyU4\nXvSFAKemAa1DrwFb1zakzOozZqb/i5MRFK8xGCK6CXy5YzwWHlKwW6HbSS95tWvO\nWUqVYdLplRuZ9eif+szrOXm0yQbABeVEGkyo89n3ytsirUTY+gPHpd7jiWID3d+8\nxi3oPDcxaTkfYehaAEn+LBInd47gXTkYTVizxFbdREARRI7qS/6gMXQY6EXnc+FU\npcP+dEFH3fRA7raFW3kL1Bzg1sDomAp8L0EgEaWOdTDR8f4ub3uvBPShQWFgl0t/\n0UwuR/UI//z6FiG66HiDd2ThDzeceRwyZTdFUjDH5CcS0cBBmFhYi9TxvjiJi8D3\n0Ui0h4jA1Y3/5S9Qk8nBfD2sbtzNHMEH3JVotunwTKu7BoZFHZD49SW7dGzJzjyF\nAgwDC9FRLmchgYQBEACQm0ujn9b1TG5gn7P40qv3nrjAJyH7nJXPEYs5TWXFMabm\nKnj2FYPAdynClaA2FVu6puXhbpN2aDWL9qg7iSpvLT1HZcgdudItj3N2sWJIe6Vs\narO25eKSzzJMAwOsOVwJJPCk4LCNPTl+M/o66lru3rSltSHvYJXQmfbw/iesgBVY\npq+4yGy9HxxKx7fCkpaK0cvZ3X8zpyIzkHIjoRcHWzKiW1dirmaYcRahFDOwSGx0\n91RmLpONp67kzrV603jikhsNNppGGUslv91FivK89jpTy1ZwFDw2es59tzdAapxm\nySXf1PTWAdm3VZaEixmQdMYJxrbwN4HrsyDvMmQWM3yiyYbrzGwSISxeYkPEfT8i\nWL+N1tfdM9PhQMKdB1onoyt16e6ga9nkHYDeaVgyNP4yfQedFV3ve0WOjeTqVODu\naSzBVVDTcc7mFd7IoM8cLj82FGBxI807tmBX3rHa41kVDQ7NvL+jVmz2Q4SQ+PHC\nmrifYG+GjvEIWinx4x5b6vmeAWd8nGDmMg7pUm7cVR4ryQHrF8FcIck/qMZTh6Vl\nIbZRuqKkiy+pAlPyS21wx6dqj4EBdxwtyDijrkuIgtbdMiJ/kuSqQAKlkSODVOit\nRTitR8JVHL73usPIgkzdGf16Hc+29HDlON4gaF6CdVwdVQc37oATDT6bzusWD9Jc\nAdYyhlpx1RU+o2PUWf3g4vBthXiybvNkvyUMDL6M58ehaX6UusCGV3h2zcwG8qDC\nBfD7F6+dLMblwf3vOiD3w8Pjn3nDhA7W+r8Ls33fAONg0DrfS/d0aCVCq8U=\n=baij\n-----END PGP MESSAGE-----",
"fp": "4BE7925262289B476DBBC17B76FD3810215AE097"
}
],

View file

@ -8,161 +8,170 @@ sops:
- recipient: age1s0vssf9fey2l456hucppzx2x58xep279nsdcglvkqm30sr9ht37s8rvpza
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBFdDZiY1BsaHhLYy93L2Ju
TkJHRUdTU0VFKy9jd1p2ZmJrU092Z09yMTNvCnpzbXFIZ1VMVk1QVzN6YXFmckQ0
U0hFam53Z3V5U2xYNjkwU1UxNmI4ZncKLS0tIGk1MC9EV2hnMFN6aFRtekt0enQy
RWxXVmhJU3NVbHdlS1Rsd05sSkZiY1UKaK5bSDPhQlVTryAYr/9mIgmXDzVp2KWF
M4FQURHk6kvSIVjHNfRyMX0IVtCFZMSmVpuPUP46J/5kzdN59Jn2Bw==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBRODlCSHVFV3NESi9XaTFz
SDcveEUrNzVVSXBISHVxTTQraXlIbmFtNGlVCkVGZXVOY0gxT3NkeW9kRVZzdEZv
S2FPRTRSVDBZam1hK2h3ZXdsb2VCV3cKLS0tIGFPOVh2M3FaaTZ3MWp6Mzd0Qzd2
YmM3eWhUbkJVbE83UndPUmhxd2NVcFUKeS38ytvWf/XRwh9TCcO4joL28EE1/Yn9
F6aPK5RJ0LJQ+fdbl4y3uQNuJ4bjOL0bkW0RAEOUt2LCtUm6qJqPWA==
-----END AGE ENCRYPTED FILE-----
- recipient: age18cgqlely56hgmhscllkmafwpjdk6dwep6ej3vkk97dzemp8jtuksqrrjjl
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBLRElrSnhrM0ZVQ043K1Nk
VTNlWDVDNW5veDNPM0RuOWZTZ3IwQ2pBdmpFCktEZFNvUTRrVVRBdFU5alhJSTE0
RVlqRkl5MUEzZjhUVWwrWTFWMk8yWG8KLS0tIHJKZXJrNXZiRjNiZEh6VEhHWnZT
dlI3RTl2MW43YVdJMVlDaUoxSDV3YTAKBCjLqctIpPeTYsRxhj0/7DzR0q1cGe2d
w0B8DmH56XP7vq+nLh6+imWFLsbEOS0lRPHRRBEiimEkYljO5ZkoZg==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA3bC9jT2VEUDhISkRQN2RW
ejZNcHE0R083WXpCaXRvTGxLNHhUbi9aWUZrCnNqa3hPaGxWaXM1UXRnVldzait3
S0tML2VTelhzM1hrN3JuV1k5TlFPNXMKLS0tIC9Ta3pwdUsrdFllaFIraW41WmlP
V1kxSm5LN3lmNU1XSk4yRC9ObkNGSm8K+Z+j2kv+webiouIJDtKlyMxJjmPpapPJ
b3LLdnB8/8637zXU4flWcTE/YHA1fMQ5aiF5OmLsZ526a98QJI68yw==
-----END AGE ENCRYPTED FILE-----
- recipient: age1g7atkxdlt4ymeh7v7aa2yzr2hq2qkvzrc4r49ugttm3n582ymv9qrmpk8d
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA3TEREZ0lVR2Q5aEN1S2sv
dVhURlhhWTJBdEdhbHlXZGVQa2ZwZkhFd2lnClM1QUJrMW1GU3FuVTFwUkZxR0xD
YS9kVFVRdGZKMVVRTk5sNm9nRVV1YkkKLS0tIExyKzlJUHhUdEVhSGJEUUs1YlQz
Yk5WMERLb1MyVTRvM3hkVVFNU3ZtajAKqH9sLSNTacfRj4c/FeeOyCITdz9zwgqm
e52OOUzI9nmq3zbhzd7b2nWHlJ2d/vmFN0u4oEpLodQPqBy/cvuoLQ==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBSaFd5RVFUbXc1U1orLzBu
ZzcraVZYR3RIbUQyNmgyT3ZkNHJhQmx0dEFvCkdVbDFzcENMYWRMM2t5ODdkMTNl
dEVKdHhuY2hGSWVnU3c2cXlhZmp2bTgKLS0tIEVCMUN5blgvaDlmMDFNQmNqSFpZ
NWwvSFBZVUlPUUFobXJQVzZZK1RSOTQKY4E+x3y2t6h+y4oLEWn+zcDnRYBaYjq7
KOHxDiutX+vbnpMtff6fTZMm3+aSSHrzZCubT8Ysy82RZ5bBzVyJtQ==
-----END AGE ENCRYPTED FILE-----
- recipient: age1ly2endyt0y9xyddj6yuj4nw6fa3ltvzlvew4cr4lzs6dv8dkavpqadmyxx
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBEbmRtN1FXaFYwUTBsbEhr
T0tGcVkvdmhjOWZMLzZ3UUpoQ0V6Y2luRlNrCnU0RThMcXlabWQraHB0ZjNldFRW
bUtRNGgwNDZhNjF6MzlQM2V5RmVRRnMKLS0tIDB0ZUpPZzJFMndSZXJNQWEzbjZQ
YVJxb3NLNEJkNXlzR0Q2MUNhZ0NGeTQKC204L2g3b/ER0RtnTaGtuZSukTawgiC0
94UolrcApg2tAUDJR9AqJ0iAAu8KSkcy77mQIs1t1d5lwejwsOBUMQ==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBDRnQ3cEhySFBsbUp0VXlM
REk4UXc0SXo3akxPZGQrWXc3T25zbFhwNldJCmp4ZzhwZVlEYkFnRmtndGdKSHEz
QjJJK29PTi9JYkhtaGxOOGlRZ2IvQWcKLS0tIDhGREJWQjkwVWVsOFlhSlNjLzBr
cGZTQkZleGE3Z25yOTZtUUVyOGFjZmcK1ayFsX88StLCiYJi9C6aC/y9NV452oR4
Hpg4xrLYxVdFEOzKNzz5W6Z3hU3830n9RismzsF3Qgsug65KraP/dg==
-----END AGE ENCRYPTED FILE-----
- recipient: age15klj4t7gpfp69472mne4ue62pp6m4e04dmjyw7yf30qtqd3vl3uqjmcyxm
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBjbmZRNDYwVjhacnZzTm1J
MG5FWVd5TytPNWhDVTR6Z2dxdEYwbEU5VVFNCkVpdmMxTmR2dHBKNnZNTmF4c3hs
eUozU2VkKzlKMjhWaDJXQUx3ZXdHV1UKLS0tIEtNb25NU204dFovM2xvMEpDYUJX
QWZLNDQvZjZjaDZiN3JLcWswMkhtcnMK0kkTPKMgKNiOOgen2BQANozKY0npxINI
ZhKkf/eQsPD5kUbD1gLshfeOS+GOcDJSjrYigneJo11yEhNVF7juDQ==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA4YTVqeExJL2lCUjIvY05E
ckZqWWhsQmcvaHRmZ0QvSjBGSkZCRUdHbGs0Ckg3dDcyc21Fc0ZxY0NhYzNhSmRr
TDFBR3JJZWhZS1h1VTF6UVFTUjhCc1UKLS0tIE1TUEV0ZExFOHhOOEMxckxuS295
M28xRktSOFZaMzFabElNWDB2S2w5ancKuVkMJ6gT5HHezSOa5i4fhT0IJv8EQniP
B+o175EyLw8/tIWgKgB/L6RA5Wg7Q7r7P2C4vnSY1JOwa65It9tGAw==
-----END AGE ENCRYPTED FILE-----
- recipient: age1k73gy5em3js9zklnnkzp5hme9k04lny32fgahmzddknjw5c295asdyr4x6
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA0VVBQaVluOExJSnBxaWtn
N2RXb0UzaFgvTmpXcENKaTkzb05Vb3hMeHpnCjRVSmhTZ01sVy9ZRnZrK1FTa0Ey
TnJmYlVaNGFLRmZUcnFXYkswQnQ5emMKLS0tIGNuMlBmYnNzNXczYTljbUY3bUtk
TkFMSlZzTjVjMkVUaVcyVXI3cXc0K28KUDg9+qZqrbUk+D8TEG2p5tu6v8HgGfHK
MGkbN/+3wmitC2T1HEdA18ULGrmd1SFN6qGIfYOkR6dkhETIs+w/jQ==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBkOUk5TkJjWTZ1MzVCK1RY
SWM5MmIxZEllZFJJQTk4dmpuakZCWUNyOFhRCkpvMEI3RDdVYkZHbmRzYmRjQ2dZ
RkVpN1EzTEJmK2VjeUFqMFFPWW9pUTgKLS0tIDhQeTZQUVM1S1hxdlJZRUN2WjZy
WTd4czkyV0JmN2IxNXZSS1VnK2NsRVUKzxoG+YTZKEDzBdRmOJjygD7Po+i/wTiI
RM3U+LpsP96i2vAsOKoJjNOrY6iOH8Iwbj0c5Q/OwgIgLcUQtDq4HQ==
-----END AGE ENCRYPTED FILE-----
- recipient: age1cmzh82q8k59yzceuuy2epmqu22g7m84gqvq056mhgehwpmvjadfsc3glc8
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBHSjhleGt2Y0JTU3ZRWnda
US9ScWpPYTk2Qlhjdlh6RS9JR0lzTVc1djMwCm8zZnJ2a1prOW9Vc3h4RjJXNE5G
d0IwYSttaC9iVGZaejBmK1J6SXc0aTgKLS0tIGZvbnJTZ29xcDJGbzkraytKb2tY
OUIxMHJmbTlhei9nSEpQeUtIWjJLSGsKwLTnTxIqkumhWoVbt7eKTU03upmZYvF1
S3a4mS/FZAU/9PgtHeY7LF4a0wwnHBAOxTwKcj8lYPWQzfPNSBFEBQ==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBwdFNUL1VWRHFjMFFmcCtp
TjlHMGJVeGMwVG5ZK1k2RWZKYkxHTzBSRmk0CjluNVVDVHMyRXp4ejJnVUNoZFZG
SXlZa095OXR0VTZtdzR2Z0hiRTFYZlkKLS0tIGRMRFJUbEtsVDJZSm9IcGhFdWxV
YTYycmUrK0RqVXIwTUZtZWNMdEdqRDAKhWlwQP+lz5enUF2EgFuLf2BhxcxAoWf7
Tqr0AOEXU3zr8k/pfKPNnQRoRbhjJWsW5uFtuTdTBbL1YnCBir7e3g==
-----END AGE ENCRYPTED FILE-----
- recipient: age1wmx8y2hs83j2u5srdnfxljrzxm8jtxl6fr0mq7xf2ldxyglpzf2qq89rpx
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBjMmF1VkdhUHIzYW5sdlo0
UnpRUjNieVREc09ONWtqQTdWQU82R2g2S1RzClowWVpMZTEwM1czdW0zWmdiMGd3
V1djaDBpRFZHU1BZbmRhUDk2RndmaGMKLS0tIG9oQmlKMW5TVE1lQ2ZEMnU1c0pI
dlRVNFR5ZDhJcitoaXdmdFBHenM2NEkKHrWek+5xtVdwVaLF7FuhdJJCdZxvg3ib
JKIN6/IKg6v8wWbts+oJZmH0+ibv3dPPCNll0U0toYGBkbJVUUiMbw==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBIZ3JkRHFpc2NSZlc0ajRG
Z3FaZGdzUGpqTXNCOW5hRU1NV3VJcCsvdkJNCnlmOVBkY1pZZlJ5d3dJbnlvN3ZN
MTBwRUJqNnJMOFdBWmdYMEpTTFpDK3cKLS0tIHhEUysrM2l4R28yRCtxL3VCbjV6
VUYvYWlOenNlVUt4UkhldFh2SXN4VEkKc5adiK86x+n+glENAMmeyS5WQce46wDj
ALy2W8zCDTeHBWJUXWGqovTCwmiHKb66egHMVtI4MKedTFhBuTLnAw==
-----END AGE ENCRYPTED FILE-----
- recipient: age1mjgw3nxlnqdj04mgjz3wn7fj2nl2nxla4p2r2fn4nkvayfgp09pqllxzyh
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBXQ0FYTnBILzF1TENDVFcx
Wi9pZUg1eGNiTCtGdUFrRERBVGxxR05jQWkwClBLK0FBd201ZzlRVC9aQUIwUzlz
Yy9Sc2dpQ2l3Ty9ST3JrdU54VFN2UlEKLS0tIG5ldXY1R1k0dGlsRXhPYlpLS2Yv
dFBoM0RGQXVLdnhxVnJ0V1FpWmFkTUUKCHv8KQYB2QdcTdCB3Wig7YTRKt1ZiqkA
MT5A0z0rizax0YZLGJ7QJlWkT/EmX0EsV62cvjzXeUkE2FKpYffiNQ==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBjUjNMQTFHL0sxTlUwa0k3
aFhNWDIydWJmdFpkcG5EU1hqc0dQK1NTU0JBClBwUFpXbHQ1Z01MSUdxaFkweUg5
d0tiT1dvdXYwZHh6dy9Nak13VjR1Y0EKLS0tIHZsQTk3b25FSWdqNTBaRW1xZUJk
M09YMXZ3cDdKK2U3djhIZ24xOTBvY1kKbQyzT/jLiGAU4poUBw0nvkwB5N9X94EP
bWN8WNqPv8ak4OD2V4zIvLY6zxzT+meHHF1RVOJrTviOT0LVnWDzhw==
-----END AGE ENCRYPTED FILE-----
- recipient: age16vzhcvz8tyxj8e0f47fy0z4p3dsg0ak4vl52ut3l07a0tz465cxslmhevl
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA1VVlxd3RrRDFnN0Q5SGgx
OGlDV3lyYmRQTjBsZ1kydlI4UFNVMUNZYmdRCmh0dzdEUmFDWmU0VjZHZHhhN2ZX
MW04LzB1ZHc4K1dCbGVBK1NMRDJJbDAKLS0tIDEzclhsWWhIRlUrU1ZjV2Q2dExF
cW42NFdBa1JKZTRpb2Z3aVpNVDJaWFkKynL65X4AjGw7PDrFZw+J34KajCl/TfZ7
fA1c8fyngnt42FuKVoSHiIrEUCfFEsf37NbV5WQFF61V0bO83EX5qQ==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBJYjV0bHRXMjNqTndySUpY
T3p6U1BOTmw0NnFjdjVFS2R4TkoyR2srcHkwCjlIQVRETldibWx0cmFZaktrWGRC
Njc2d3VFUFJucE1EVVplR1NmOVVqeGMKLS0tIGVzZlI4Qm5KWjRreEd3MWc3bStP
TjBvb1ZGNHV3S0hiMU1XdExldjZiTDAKVZWM03cRIkLwxaIgr+YohOxEp8ZFhbsC
2dYLP/sLx5ab03rLWWViaJ+ONkvXfHvIYosQodO8dvDLlOJPbtTFCg==
-----END AGE ENCRYPTED FILE-----
- recipient: age15cx90pnp54xp5gxlt02yn9j2pz968wp3l5ukdkx55xuecp34e5pszjku4m
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA1U2d3WXpqbkNQUnhvNmxT
NE1hUDFSZXBTOFlQMFYxT0F2VkdzK1MvRmlnCmkvc21GMTJjNmlXNWFxS0JsQzBL
MUVoWkdMR1hOd09MZUF4bUpubi9CM00KLS0tIDdCVkxXenIwN3F0YW1COEJxMTFn
a3VvbEZUUHNJcEhUMllud2tYQU1RQUkKDG5dUpTAKHdGrnD1U2JWWv2Ue/LShVwt
XRgdjTwmXtvf2s9sIetX2rLiJxcLkpRz8z+AjK5c3GWxF6ZVPuuGvA==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAwUVJtdXhkUEZMOWdpN1lk
QW1BY0FtYS9WN1JoRElFb2tocWJxM3VYTkRFCjcvWURVNDhZbEpRYVVuZ0I0ZGMz
M0Q1ZnVpNHk3OTRYa2pMUEl1b1BiT1kKLS0tIGpmZ2QwZHQwSk00M2ZiQkx5RmdP
YUtBVFpJYVJaVS95dFdxMmZkVHI3SUkK4Yo0w6ljg2TGkMqbgWqID1aCnSL1IXML
o0QeYRHVJII8ImjPbI5MYif4T9rTZKK/Gdxb+VtbnDif88E1P3NjwA==
-----END AGE ENCRYPTED FILE-----
- recipient: age18quey88vge7xytclg2nuq4ncme86dg04lxwczqxczmdchnjg3p0saehsnh
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBjQThNQVJyR1BVOElNNldl
ZmphdkE4ZVpaaHE2N2tPdGpxMFFaVHUzZkg4CmlsSmtRdnVMSDhTK1p3S05Kamhi
THRVMUE2d1NDc3FIdUpXQXoxa00xRk0KLS0tIEhhUnBIQnJQUnZKU21vTHk5WFVt
cUhkVFRNMHFkdVFMQTdWWUwyVGZxZU0K4Dn0V7ulWdSOnsFSaFTBdfOz6RD0R3Ba
MOM2I0afFAcbQI2rzdySbGzy7yJeuA1puBbrHDMOkVCK2soYm3Gerg==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA3ZVE3SjRxZk1uMW41WGxY
bFAvRzhJR3FrUnFieThWNDZKRDhtSVk0akdJCjdCalJSOTVWQlkxdXlLOXB5bk1z
S2xFcjdwL2tRL2w4OTRwUGFKaC9sN1UKLS0tIFFMbXBTSWo3aUo1K29BVFZHNkw1
ZzRBK1ppd2I5eXl1SUVZL3RiUGJZMnMKqWu3DW5SHRCWaaTl7/a789m+API/L2wD
Jh3x94vhEYBWZPlGazZgox2hzPMcCCMPYFZGAwzTFgtsoTF4h53RXQ==
-----END AGE ENCRYPTED FILE-----
- recipient: age1ax5hqk6e2ekgfx5u7pl8ayc3vvhrehyvtvf07llaxhs5azpnny0qpltrns
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBjOVpRQVJBVWFnaFR6SnBo
UXdrTk4yMW95QStMOGFqV0paSHp2Ly9Ga3pNCk1PSnFOWFUramM5OUxLU3BibG1C
blJtc3dNTWlBek5POXRMbUZDbG1WelkKLS0tIGZkVEErZ0twTFV6dWhVanUrdlpY
VkJDQ2Vmc3FPTEJKbWcrQkRwYnN2TG8KO245mM0A94pLL4/EHi6/eeh4rak02IuR
n8rBcJ/U4qOD+1QNW+mHbGiNNSHLtGHuVrM5uKaruRJDmxzNWQjmXA==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBpUVY2d1JkbHYzR1g0MlVl
NlJ3V0FLaTM0eWdOQ3gxVG1yY1djTHBuUjBRCjdWWktreWJXNmllQlk3QTBCNW05
cjdMQ2pvYW5DbW1zSnA4NFdIQzNVRU0KLS0tIHVkS1kvOVVUaDBKK0JjM01WMjFZ
M3U1NWVLdzVDZE94SnBuUUl5eERBZ3MKDqYKfil2536N4HX5bHo1POj0RzWPDhp6
+ycatTVYHojVQm3IG+tFpbMBaFD2NG15YbP64Ve45WaRb/Eox/46Kg==
-----END AGE ENCRYPTED FILE-----
- recipient: age1c2enwel9un28dcs4wg0vcyamx9a4a6g3walkhu8w5lqhmd804paq9d24as
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBkUXdnZ1FLenQ3SjNwN3c1
aTREVTBhNEIrN1NWWUJ3SlRrQmppSnVTc1JJCnFydzZoNEdxUVdDUEQ4UkUyUTYv
aXAvZmxXT1ZkSmpCWUpWeWJZYXFGcmMKLS0tIDdySzROS3dxSk1id2FKbHZ4UERG
ZzZzYjVjVCtMdVpoM0tzY2w4Mm9aSXcKr88HZkBxwuRzDtb/I8D7uopzjglZQsKD
oEd1uz/uYhDvy58MIKz9nnTMKyPUOE+uICZbjZ25ZsdkcDdCWNhyig==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBOOUVFMTg2T1ZuTjRTNWVj
eWh3UWkrdlVmd01kNERLZ3RndFYzZEthMjJVClNmUm1VSEpuUEhtMGY2a0MvZkpz
Nzh2SmJ4bDRuQ0RKMnFnWG5KeEF4SkUKLS0tIHExZ2xTTHgzdnRiaG1VLytmNlZh
K1VDaXpxdFRZeU5icVlaZkRsaDNNUWcKXQXX6+U9/v3I+Ta+rae+IrDjR57NjEA0
ZA9RvGAkTBcbXQ3izPN+qafLmJ3yyDO9HmquuA+gzZ5EKhHPbS1bRQ==
-----END AGE ENCRYPTED FILE-----
- recipient: age1nanlervuderw4qskcuessycqy2yfmptl6nym9scgp9ky2265ssmq3u73r0
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBueWVNUzFwbzJmOFpTbUdr
VnJUME85WEpiRktTTHErbllRaW5CdlVackJVClRodkdadjMxRkRIMlRSMWtLZnJa
OXdXV1FaV2tlc0VkQkdhTmxlckJCQ00KLS0tIGFYWW1SK2krb2hVeXovL3NHbUo2
THBzKzEvU1NxSElDVWl2elBhRWpsRWcKWwxOi8DGF+jruyKGsxYbeaM+Z9gbrTI7
jIBzG3LyLskn1Uo8PNn7QZW+pSUZJP7kFqSgBDPzITrGoZMe/uscEA==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2025-11-19T14:09:27Z"
mac: ENC[AES256_GCM,data:tZ6QzVPivueZiC9Qfb3KNZAv02QatgHRNnlM+Y0iV4BZkYoBjxeDojutizvAMwUarnubUdk5I6m2OZK1mvVDZKXyI6zALX4JMeT2xYQWRHYzHpOygLhhGwTFVhV+0C4jN+eJFF2cNf9lu7NuZI9ylZSOY8I3YKUl+l0l3CkXUl4=,iv:JSGOUq+j9T/NXspn70dfu0J4ISV6vVFZUe/Z1CirrJk=,tag:Hm9N55f9qMc056nSTR1piw==,type:str]
pgp:
- created_at: "2026-01-02T21:17:29Z"
- created_at: "2026-01-04T22:59:11Z"
enc: |-
-----BEGIN PGP MESSAGE-----
hQIMAwDh3VI7VctTAQ//cFd10y5cI5pCudkNrwJjjCvaJmP33pteHYJrzH951JFt
FmO5NVPxFkyZIApN2LJ+neqDhfOHWoAqb+2GWeAnKQwqWWD3mAMzTFbZ/GnfNTpJ
tdGh/PtTawnjl5olwv/TSDj4DJSH9B/r5KJG+2oKvDNYHQ06K6qVoZTtlI9wA8nR
TLZlqlHlLNrYBBKNH8hUcdwCbd9wlBZGY/dhprTUlKb+W7i5LszQJuKdmxUj4njq
QVjxMG9AHKn+SU4awAOyEI0uzTdKApem1REaJE/d+quaR7KLCjZIpQ3n4SsbBUfJ
yAsBv57JAlxbaG5xuMZ/kjWQaGiufUK0J9IBfEKAyHZM//iFl+CAPNzPrQDPI4wy
6HRL2r9EvUwZb6vJYskd8Od57nT4/0+zV8bSzh18JkEc9UKvMn7d4bx7AnKU+rsP
cDeIC5JTJjygaiodIdYAYS81FZZGj+t04hrAzkiPZcM/+3JdHNkuxV4jKbD6ljzr
xdCaJUXSmGrK4uznLFoIBz4A35UHSwSsa8s3RUL1Knem59cGSMVqfz6nJPQ/0sOT
tI+8VI5HCdJ0vlNw669opzgGGiaIKcBKWfrXsxYkww9ekWxbjWaBcFLKm3g7p/mh
KzFRmQwcOXG6nQ2ROUnL18Jh1u+iiXvzc17yK/6xuh3lLi+wvfRXMb3/ePG4j86F
AgwDC9FRLmchgYQBD/918RvwuPqcGLYgUJLJr/ycnAG5EzoSA7qqBvItgoJfzbah
oCnnVRwAyvvvYYyqWrpIxc9X5w8vD5CeLDWEX4slm6AXUbBFK9i+tesmXC6D7du/
Sb/DHYH1Fa168nZ/oK2YieVQto6VS0WK37WqT6thybyEpYZu898tE9mY9riKlE+B
JHKjGailLl4KeaWbZQgLNP9KKi1wwOC/Ae43SS3XqFWu0zx/l4RHn/KvNNVcYyc5
UuuBHhFem12f14xVy2bwjELTkQfImlBFmPmbN2sqOIG8maFzdwUVfVMcAR2Ceq9Z
pTOL2q7NCZ/JlwZ25ficJ1Og4Wnk3oTQwZswoN+nApIF7Td1QxmDLnGB8xmrnLpn
7A1PCo9IR3MdOatqN2xvotV1WotYTz3lcqpHfsYpscEBuyozxVw++1c2+QpZtmBQ
C3MQoqUDXBwvku5BfVG97XFy1QDCCTelUPdNCvIkXoJg9AUugPYRokCcI2bTybFY
unL0sirc8+/mgEQTwZgJXDhtvYTpps0pj5PFwdDHRDgrW/CzSkLz05HIKl+NKDmc
+aIxFLAQiFBiqgJneb5q3GK7uZq0YVIb86MD5sqSNT2Utz1KMzhL56sTjPEtn73E
zfwMX/EpCkpshsfbG1hLZeKPsYZBAo14Jbv/IfWHX0OXp6EVWrLM4FT8sEEwWtJc
AeNU3uXSpOW5xlKv6bpNSl0A9C8XYK28FU8JaENq85Q5VZGLf4JP2auFXQ2PWbpo
9MmhPhMNk4a5aDh+AqaB7yXCFvqzsGEJu8Xqe3gAN8Jn9ThMvUW+nwm56A0=
=arGb
hQIMAwDh3VI7VctTAQ/+I9Y9qGLQ7j2pwSMurnzrX9DlK3VKSTIyOHk1kxcDh2iU
UKrkVCsRHJkj9pf2yB5t8ehUXRyYtkzxFmszuBkrLIkqgUE6FUcl1ce37dYgDRUX
XLhKbZlEcz0FJEqDAMEqjsM5w75z2xU2M/GR6rIULixYqKPxvZG1AOUj9xi4S9Is
cZh2Dnjj8U+hmbYlcwx+zulZk+5QpjVu64GkLn27SfA5os/xj9ThKbpVcPdpXhbV
DRak2OOHeKsMAJMagmKokC2/BnAq349kz+xWSMEBgxK9bwTSVczqpJ0Nk280FoIO
2GrIQdrxXVzoR1m0sXcLtkNRnAd+OcSMsDcs4xM6jqHU1bHtdw3H4pUGB1lC5jtV
lBtkAwhA84xx+ut0UyT19S6HQ3VkgT0HousQ92uSjzkDd/AK77ir6pfM0GI5YhoC
LVFANFcind1gWMtg67D3WYcpPMi+o9IkSe7QALhqCL+fPSchrf5OZjc0w/Xb7WCT
nOTMMt9deC2GANjE1U466IKsrY+f1V9jig8qxC2XFi/HTe8krUhwblGmyga/a8Vv
52O+HX3Ub661HpILDNMi9BKNAKNRLeDZMdi2Vv3eqwFs6wZSWTtzt6m025ECZmIv
w3jR6XH2ggJBYqS/j2EpuwUUi8Lll5tnQpLNNB5ZWE1bM6Jy5Fg6pox2K1+9oYqF
AgwDC9FRLmchgYQBEACTw0JRff2oy+4h+jKZ5xXNbkk7NZypEPI00c7VX4eaeXsV
UKU/lfPEtHFl4aZ2N092McUxS0WDV/xCXoLn2kdHsmcGRDuq59Y0+ITsgLszOFnD
usYhmvocgvjWldBB6lS5yIqzr4mbg1bxkrR/7PoxHT3XH/WxdJSXikXLuZ4zpHip
E9kZNMq3qI1TnXAxciXFHBpGOjWMKxj2s1i9p46zKeCMo+tvyTVgDzyUaQ1V7OVO
NfRI2p1/LyzUANAjf1UHtcQncbGDYVM7wis16sCfUGpts09fvThfYEDZ7COL0WNZ
RSzmMgG6ClWcpx+B1WtYIM0I6sQvzgWp/QKdCEof2dHC7Adpp5q5TXmxrNhqnmoX
kRwuLSiNZTFrpzqrlXDi5ljPiPRx4RsM2Qmj/r7jlWBn+TP/jRQqO05ZuSe4wCa3
NZau32eYedMY6j2DwfHzzpXwxvN9Gj2evwqypCrbg2RYYixMZHasAF+nlPwBZtLy
B3PUXE8ftvZp/N7845MYwDrnm8EQGAD0647vffZ+J7T1s3dKQTIADWqY5J0kyfRl
lh5H5WpQ0O+POW48HUQ6ee7D7Ncu81rbRhCeOhWNgZTLq/DjdLhxCpKqaE+56Uq9
B9m3/0YAeo/6kj6Twded8OaltTEpJcMMU1EqLs+SweLw98bUniwgm+ReQJ4oEtJe
AXHdXns/mWqzshUUTLXE6QbUyxCAUlSNGZcFnBuAqaKaLlIwYbgh14Nl9XQ8B/Cd
GiHUdMjf16XZXG6evAxfoPGaWJEkvqSxPtgymxev7jpuXWRHNHtSOpRs//V8YQ==
=dVCc
-----END PGP MESSAGE-----
fp: 4BE7925262289B476DBBC17B76FD3810215AE097
unencrypted_suffix: _unencrypted

View file

@ -41,161 +41,170 @@ sops:
- recipient: age1s0vssf9fey2l456hucppzx2x58xep279nsdcglvkqm30sr9ht37s8rvpza
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAvcTNvUVVSZ2R1N1FKWWw5
dGJHc2swRXN6SmdvZ09zTGhYa1VqWnp3L0VzClZvYmhYTjdnVytBZFI3c2JqdlhI
M3NiNVFQTXkzZ09ESkUzamRleU02WFEKLS0tIElxaENIb0V6RElZeVZFZWRIRzlH
UE1mM0VEOExFNm9OaUV1NFh4cEc1alUKX6niNF5QxQ9ub+grPkUqeLw+gjBcwV2A
Y7zeR9eYAABCkDh789luQd37LXP2QdD90hiaDGMQChVMpmcIjdP34w==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBrMlNmOFRTZWVZQnRLME1O
QyswZlBYM0ZpQTh6eFRudE0ySGxQdWQ3aUFBCnFTdDc0K0hwYzU0NVBObmxrMHZX
QjJTU1ROK1d4Q2FuZHhiZWd6VExzUlUKLS0tIDhZSkx4ZVJJUmhUTFQyZy8vR21U
TnN5T3VXOWRMdkdhL1hoWDJneTF3R2MK2jdfQKotgXcN2m0y6Pm6KosUQXuVZUix
D6yHIkz8VZJpMIrFpGUriBcnQGi+vRzva7tVTo8Ch85jTj9SGT76fQ==
-----END AGE ENCRYPTED FILE-----
- recipient: age18cgqlely56hgmhscllkmafwpjdk6dwep6ej3vkk97dzemp8jtuksqrrjjl
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBOS3g4dEhVYlBGMXNzcGN6
ZldoUVRtY3FsNVNpcXI2cTk4T3RzNUQ2cW5NCmFmUXRXb3REaXZTVk5MemhOaUNk
bjYyYThFSm1ZZ2JRcDF4WnFxSndxL0kKLS0tIGJXZEsxRS9LcVRrd01xYzM5QVQx
MW9TYkhMRUdXZVVBeVkvRUFQWElhMW8KIhz1sFGRNkhVyLRZjA3IyYInRbNhN/Qq
5OWHJj/iS05xunkPNoWfxphRtHRudljgDXpt2UwYgWoTm1cAnoIj5w==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBabG0yZVllMzM5bmNkNjF1
Q0ZDeUhRWmtsUG1rV2NDeUg1UXZVeGZmTDBNCjdtQkhHVVRJanMvZU1MSmVwTndq
VW9FNlNHNExHb3N4SlNyN096RDhBVm8KLS0tIENtbmF1WEY1MWM5V0NET2pka2Iw
M1lBK0h4SFZTR3NPaFVnaVA1bW9FRFkKPqlL9CplnTizVDre+eHOrYl9yxWEN5AM
O1xYdBymskD8FF4Se3hpoOTJTv5WaaOiIc+0mlfCBJhS/WAwhCfPnQ==
-----END AGE ENCRYPTED FILE-----
- recipient: age1g7atkxdlt4ymeh7v7aa2yzr2hq2qkvzrc4r49ugttm3n582ymv9qrmpk8d
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBXbkc3aGtMcXRiTm82Nllp
aHRJdFVvcXp6ZEorNmVmUmIySzdRWW8ydWlnCm9oYWZhTStJQmNSL21hVFFyOFpL
aUFmQk0wbzVwTWRtSEtkQ3RFc3hOUFkKLS0tIHo4YzU0aHhFVmZCTGZWclNpakdn
eVVDYUNXUk5BM2M4MFJjVlY5NzJKd0EKt/vaHVeTowmbc8MfQwHqxnbolf0t5Th/
wBQHe+MUBg9lCr+TqDi7+TaRYa93V0oiBVQ1uDLweV5olpOi2ttc3g==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAwODFJZUJMUGhXT1ZvSHJ6
R1NOVDlOWi81RDRUeGphSFJoTWtlY2poSjBBClRkbkU0RVlsVEcxWk9ONVFrSHEr
a2dlQ0tNYlRReHhuUlRXR1o2M2lVN0UKLS0tIHZleUtBZUE5TUtpYWJLdHg1bVp1
WFc3QmJBZ2NLYnptSDBtdkkraHJZR1EKk+V+rF3u2eKIus9io/kqDwPwHcsPrt8P
B1sxlqCNfXtIZWelUT1AghBs5SbVjiNrITVqQORj4G0on3EW/jwfMw==
-----END AGE ENCRYPTED FILE-----
- recipient: age1ly2endyt0y9xyddj6yuj4nw6fa3ltvzlvew4cr4lzs6dv8dkavpqadmyxx
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBDUVQwYXNiVTE3dENRV2N1
Z3AwcDk0YkRFZkRjZW9KZHFlYVNaWHljMUNjCnJmN2pzaXV6RFk4NmVFdSthYVcx
TVpTclp3NnlBakNaYUQwMmg3VVM1SDQKLS0tIFF2enEwWXAwYVVTeWxNY0kwRWdC
bVJuaEdsOERBKyszcHRYUFpUcm5zeDgKISCkCqLSCUwSM7XqrY+JMW9OE9q5sfbB
EXVLqqjqBICQ50vtnGywG70qu3WXzpuVy0NK+zA/3sgVpXuU6/Cplw==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAxMk1PSzIyU3UwaGZPYTB3
V0hpWWcwR1pwYStIa1NBK3hDa0ljU1ROUVhnCnljOG96azEzdno3SzFiUmtPWUIz
ZUpsNE1UWVUxT05DUmxCQW5IenVMNG8KLS0tIFN2elpZdzVBdGFkckJYc1MweThm
VVE1akRvMFJwVXNNREtBRk5Db1JFZlUKtDR4O33K0X8ML20OYy4Pc7ZvKTK2WvmG
2a0IaaKW26oek74wjPTc2EaumTANE1hyeXrwZ53mC71nNf+G59cx/w==
-----END AGE ENCRYPTED FILE-----
- recipient: age15klj4t7gpfp69472mne4ue62pp6m4e04dmjyw7yf30qtqd3vl3uqjmcyxm
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSArYnQzTm5nMHUrTForWTlq
akhabVhFRlVxQmZFS3RId1RBU3FTYVl0NUJNCmRGUlp3QzR2RFVNU2Q4aGlud1BN
bWlzWnNUQnJlelVsS3dhWTdyTGgxUWsKLS0tIG9sRE00QVozUzJ5eEJtekRQWmVr
YlM2WXdQTFJRMTlZQ2xlTzMzbXFFd0UKZBiT6x4zfpKQctOCUFmBQHzWZ2rFIIKh
Lx2oteWtHrGABf+wc45ypz6CBEJjw7moBf7ZCupOOL+jIJpe3UriqA==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBCWEFmK014SzVzeFU0NXZG
cEliSmFoUTlRaHRmNEh5NlNEcVVkWC9WUWhFCkE1QkU1VENhbTJQa2ZZL0s4Q3V2
Sk5IMGR6L1JCL1c1YUsvQ2N5SWlhVGsKLS0tIE55MWRnOEF6MGo5TTRHaSt1MVJl
djZtZVBSNW5YeTdvV1Y4NjA0Z1FObFUKYLnXoDnCOx0jckEU3m4pfw4WBFsc9xBI
SBN/9OqOLn/9Fk71PPBmhDAjsB7ZPYOuR8IOSgPbyFgSbKt+Pd1Fsw==
-----END AGE ENCRYPTED FILE-----
- recipient: age1k73gy5em3js9zklnnkzp5hme9k04lny32fgahmzddknjw5c295asdyr4x6
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBFcHZqNFJWNGFOUUNkZTlN
L0IzcU9qR09BcGQ5ZGxGMmcxaWx4SHZDakdvCnZpc0N4QzNzTU1XWWhZYk10QjVN
dHEwMS9xOGRBSlFKQi82eE84aGMwbTgKLS0tIHNjNUFCaFdEM3lmTlhNUDJHQXlM
ZVhBQUNoYlMwQ056V1ZCRUdrdG5ESWsKO8a6+mhNR2jzTHuKROp0QbFFLJD0TN/e
5zKySP6bHrlcK9fguXWnOqshWuxPdECNmE32L0pm9maL7G2T4FhvzA==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBpNVluaHFySm9CakRjdldJ
bmhuUlUyUU9GNXdvMlhiZXJvalkyOUtRdlhJCnJqRVd6czJOTmNNQXNtWVkra0lh
NVFIKy84V3Jqb0VZOW0rSmhaUlorMUkKLS0tIHc4cTU4d2ZDL3NxUUpaYWF6alB5
VlpNektLOGVHdDM2clpBVmFCcWxYWVkKmyXJ+VcI1lRAj/7lX7UMd+bTHNmrsdPr
giY5iv//IdW+xKe22ELrIyHwLJ7IHUllntg4bIifttlHXKKm0uaiZA==
-----END AGE ENCRYPTED FILE-----
- recipient: age1cmzh82q8k59yzceuuy2epmqu22g7m84gqvq056mhgehwpmvjadfsc3glc8
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBGWDdyVm51cFZ1SjNVQU5L
UUFqbEhkV2puWEJxVmJkb1prOGNnZ1pRZG44CkZpOEZ5dUdjN0NYWXZSK1lLMERG
M3Rwb3FLa0crQmx1YkFZTnZlVGF6Z2MKLS0tIHpmd2RyZC9ZR2lIQUszZlNQbUJu
bVNkMTI3ZXpDY01KamRFb0FmY1B2dWcK1RRtVtIwzgckwxX5YEQWdL+BHUdEAD57
9Y/lLGzhGHwRA9lYaN8q+cpMDjhuIDiDqSZV7N16EZcOjZ0MIjZonw==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB0VVVuNndJekROWVhma0s5
TVhKRXpzT1BPQXdwWVJ6dm1oVzRJUEFRc2trCk8ybTdYdWg2M0h2QVFJRG11RGli
RWNFeDJwdnVjQnRPUlRlY2VlVXdSc3MKLS0tIC9MWXJEMmVqNkxPUHYvdTRWS1NT
M1lTSWMzSFBtbThHamdjQXI2ZE94VDQKy0/CUSyBWTCPZ9kt0XYZFBVQ39NqiJ0Y
E8QEcRj8EuNrpN5C6DYrhgNrQXdz7HPH2IGN94D/W9moF2ze23nbpQ==
-----END AGE ENCRYPTED FILE-----
- recipient: age1wmx8y2hs83j2u5srdnfxljrzxm8jtxl6fr0mq7xf2ldxyglpzf2qq89rpx
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAzaXZTNU4vNTArazNxZnBz
ZGNrWXJ6Y0JSaGY1UzhjdzhIdVVsNjlQUERZCm5RV0Ftams3US9WVzA0eHdOTkpX
RVYwS3MvUXZNOFFUMG9VKzh3aWk5YjQKLS0tIHZhb2ZSYndLcGJIK0xURTRBR2NQ
OVN2ZURGSWxCNkViK3NFSVRqdUo3aWMK4tjIx7paJg7bTgTwjnXjbpHE+Vvf3YbF
C9Ekp1Kw0k+THfTgnjwyNWuaLv+8VoLqt2k10H+oALjLHxQKpPSmCw==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBTY2orREt1VFpkbmszRi9y
RkZlMDlSZHZIaSsyMnI3QkEvdXBqbnV6U0ZZCmpNbWRCMVo5dXBwWU5UVmtqMHFF
RWtya1RDZXJvR0lhRUE3VndYa1BOWkkKLS0tIFNvN0lrY2ZhNXVZbFRabFdjTTY1
OElqUU8wR01ZUEl5c3Y5Rk9XT2dUdTgKS0QFWO4KWxLnXu2Zud4YqQBBfjXjuWHi
woder/Vf066n5N05Xd1nUOwkfim0Qyl8vM7JwRrCEPVaIdp0EyhhEQ==
-----END AGE ENCRYPTED FILE-----
- recipient: age1mjgw3nxlnqdj04mgjz3wn7fj2nl2nxla4p2r2fn4nkvayfgp09pqllxzyh
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB1ZmV3WUc3SGR3OU8wb1RX
aGVLUnJWdU5BTE1uSy9YSUhVUHIrMEhDVVVrCmhNYW9yd0I4RnBaSlJRRzR0R2NS
R2JkSENzQ2N4ZW5Xdmh2cW9iZHVvNW8KLS0tIDA4cTI2YitUMFlVL3ZlVFJlT1du
eXh3ZkJyRk1oOUlmM1dwdGUraXZsU1EKCVvFlj0X0Q79116nQ+8Ybsjk1HBE55vh
/j5g7ggeLdCcoU7qEevHvBukbGa84xmiwJxa13mumI7Yi4383P8Twg==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBxUkZQRlpBR1R4S0VjcG11
QTFNOEhMdzBoUnlEY0xtVjAvYmpCM0F2endrCjBRY29nUHlGNXNuR3dsZTZIZkRy
OFk5eE5lUVhPYkxXU1pYdFFDMm0vVmsKLS0tIFdJekdUMUJXSHRiMFcyOHhkUDky
S3JZSGI3NXFMNG5pNW9oSytBVlBOS3MK0IB3eMRsqAj089lAjym9KNWtz35SmzXF
DuGB21O4oJ2sJWCMyPfuuSu1ukz2v+k+1frsXbpJPfYr7WJ6CbSkaw==
-----END AGE ENCRYPTED FILE-----
- recipient: age16vzhcvz8tyxj8e0f47fy0z4p3dsg0ak4vl52ut3l07a0tz465cxslmhevl
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBMZkptNVRuYWZMWmZkdXMz
VDR2OEpOM2E2S2tZOTNPaXQ3c0taYVBZVm5rCnNqWnNHNEt2SlphdmhZZ2hGS0JE
RXlDQ281cEtjblNZeVBvWkVUaW5lc00KLS0tIGRLKytBRWNvUmlJZ2RzZHZWdFRy
K0VWbzdiOTRvbllSb1dIemVLNnZiWjQK9StbdLSPG2h98Dao5ZG3qvhvD6iSg3XK
MhgksJ/YfuWo0aaLMZ++1jjGD3O5DE3QbGrBA5R2RcInvUi7jHWBtQ==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBnUlV6dkFUK3BYTmQ0cUI2
aEo4a2xTYTYzaDBES2luQTd0WVZEZmtHQXh3CjA4ck1WL0FOcjhkWU9hcG56V1Jz
Z1VLakdoMXJ2bzJ5L3A4bmIybEdMbnMKLS0tIDlqZndKNTgxbWdKSGJCVGtRKzEv
VFBySENGL3R5bzVaYVlhRjlQdVRGd2sKC81fnlm7UllGjwJsfonPHVdqZeB5se4s
66MuY66jHOc28FK2kPhLHs1QiNDv5pHWplOpVXKLJROPJH0cZRVLGg==
-----END AGE ENCRYPTED FILE-----
- recipient: age15cx90pnp54xp5gxlt02yn9j2pz968wp3l5ukdkx55xuecp34e5pszjku4m
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAyMjZLa3J2dUlDNnJmcUtq
VndpSWxGREhCY21xRlpNb0F6dVhvZXV5YkNNCmJaVFFRdGY4NEdUcTZ4ckhmZldM
TmU5TDRwTG5QMGVHN3BwOWZuTFpQWlUKLS0tIEg5TjVjOUpaa1dabTlzM3REMmtz
ZUVWRGFsbDNWRTBaVUpnZlZLYW1GT2sKInrMXDj0MLNb4r2hwZEsw9HxpVE/eThv
TYyiPbaNkzr0EqDcOQQ/3MEw0Q2XPaMDdCG18u7kYlGGwdYNcWRgmw==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB4ZE8va1ZkbW1pOXdVQTZQ
TDd0Q3J2bFpzc3VSdXJXWkkrdUMySThCZzM0CjdPRVR2UVBFS3lueW5hak80cGl0
akI1STlRazF6WFpvcm5wWXJvL29lT2sKLS0tIDhJalRSbjlHbFBzY1NJZHg4aEVh
RGxTVCtaMmx1MmwrdEU3SzRoN2lDdTgKj2wuv4Jre8S8OWQ2J36cBRr7OCNNCDes
3ZSKTg9erIPOQDs1AJruw776y1aIbSk3QsVxjUuIyUSE8FZiGX4QLQ==
-----END AGE ENCRYPTED FILE-----
- recipient: age18quey88vge7xytclg2nuq4ncme86dg04lxwczqxczmdchnjg3p0saehsnh
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB0UVBvdXMzRVRuc0N4NktF
MzdnVExNWDNGanc3cGc0NkNoajJROFR2MUM0ClIvQnk1RmJCWXJZcjk4aHRYUTkv
cUN4NHJaSWxHckw0NTV4WWxKWHZHelEKLS0tIEs1em8xamQ4YnVpTzRZMDg0UkIz
b2N2RDRYemVDSzZESVhUOVR6MUEydG8KVLj9kVMaZeKDIQiVQF9lu80wA0m8CuMD
IBCwg5sHoz7fAK8vHpUPKh2XooD2BL9q0pPZCc3sCUjQvLgW1ZK1YQ==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBOckpaV1gvNFBDNk9YaGlL
Tmt5bUNGK3A1dm9iZmdOK3gvOFhJOXRPU2xRCkRHV25QNWxndEpUdyt0NDdqcmVx
YWdSd05xS3llNXlodVRHK2VMQjRIRGcKLS0tIG5aSWQyZGdNNE9zVGhhUGd2QkZp
RWZMUlJIYVRKcTN4c3VlbWQyWUZzWWMK/5JvgRQo6LEmOMiY3b7mVaZVXX0zAG62
DgCxZmnHfTSUlutNPugKRXOrTHxt2VaU74boorPlGBZizFfjJRBZNg==
-----END AGE ENCRYPTED FILE-----
- recipient: age1ax5hqk6e2ekgfx5u7pl8ayc3vvhrehyvtvf07llaxhs5azpnny0qpltrns
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB2YWtZNlJBMUVna2tmODdo
TC82U0ZtMFV5L3Q4NktxZ1N5cklyR0ZUZ1R3ClNzSEhEVmg5WEpROTZIQzQ1dm92
UGpxcHNzUytVYUM5dFJDcVVzVzNuWU0KLS0tIGtYaVNBTHNYNVZQTnZUN3BZSEh5
eFQvUWx2Y3JPa2VCem55TkR3M3U2M00K5TSdJyIS1yCV8GIYZgWlSC/y2r5+hquL
RLougeJFaSXiZ9AOzsnC9jGzzBVvlsf5RNH+fYsK9oHuTH3Kv/s8Jg==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBDTk56dlBBazVHRTM0enVD
QnFIYUNGK1Q5T0xiNUwwNm8xSk5MNWdMcmc0ClpVUkhzM1o4d0FRR3RiV3JXUmR4
OWlDcldKZEpidm45NUNONVhVT3phN1EKLS0tIHVxcFh6RmlrY0xQSHMvSEVMalJy
M0k3eElRRGxaY3hFTjV6STEra0hFc28K7HWQo129OjU0id7l1e3cNRcJa/ZR7ao2
a7oEzW/4I7C4eymhsSSAYLRsEzRoJArgQanP1IcqvyI1oR9jn+Xwxw==
-----END AGE ENCRYPTED FILE-----
- recipient: age1c2enwel9un28dcs4wg0vcyamx9a4a6g3walkhu8w5lqhmd804paq9d24as
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBwWWRpTkFsWVZGbkY4dmli
VzRQaWt0UFM0L1BkV3dTSjMxbm4xMFhCT3hVCjNXbllqNDl4cXhZaDJVd1gxQ2No
d2tLL2VSY3N1T3E2WldHdDlwNXBycE0KLS0tIGd0YzUrZzF5cjlxVDBwWCtiZHNp
RVFnZWs5T1pxN3VHRWdnbjR4UFFIcGsKUnEeBhX9K2tUNd48XOvpb0n2OoeUPyq2
N+LBxwPYoSxoiZAW0vDg4mNcJwALYDXA5ew0fSZj1nP2LvaROV84Jw==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSByU3ZtR3NFSng5MWorNVVT
NU9xMlhyMWRuRTVtdFBpUjNXeEt2Wnp6alFjClIwdytPb2s3UXNGT3QvOTlQUWx2
eDZXbkY2cnFKbVhZekJKclBOQ3E5VXMKLS0tIGRhMWV5S3V3dFpjMDF1c2diMVlH
ZGFEaHlnT2Z6ZVg2dVlURXcxa1hFRDAKYaKXKJUfif1UTrDGGGGrnMrX5PgbPC8p
tY2QYvbCIUPg2Ihq7frxwu7mN1kDgHRZhIjNkmxGuwDizbF+p4dYNQ==
-----END AGE ENCRYPTED FILE-----
- recipient: age1nanlervuderw4qskcuessycqy2yfmptl6nym9scgp9ky2265ssmq3u73r0
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBXY0FtT08vYWJYM3NXWjBY
UGtyeXU4SG5YTE1vZzJLUlRUTzVWSHhaa0FvClEwR2tTTi83TVllQ1FCUDVmbkt5
MmxZMk1COHhUdHYvT2g4S0svaU5pRUUKLS0tIFBZN2ZPVzlKK3dmbllDdTQrUUI2
NHBHK2NZaVQxcit1SkYvTmZiTEpqZkkKBza+5xkk+RZP0Ki7x4L0I1zW/8/8tSdo
BXrsxtgL28sIyqmh9q74e5W315cWOd/3aoRmgiJMVIx3gM2mCdBs/Q==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2025-12-23T01:11:36Z"
mac: ENC[AES256_GCM,data:e0WoFBQSR5q3GOQ+GMJGBd4lNBAMqlnVjtUq3snxrdvcytb9YvKnoYQH+GjbdGIiqrND8pOVnZt34AjkR8YfpWe+VrkP3Vj/3l+1GjF1XIHbzBNKOQHdYPSVsH2NZwftcAdphbStf3GTlb+b+cpTn4a9Y4pTNGVoOaOA1tBr8bM=,iv:sPXktitTNMkBhHr6E/QRZCVKrgyED9/o9hiivbObACI=,tag:tTNr4UEf92UrtI0Jvi5o3g==,type:str]
pgp:
- created_at: "2026-01-02T21:17:35Z"
- created_at: "2026-01-04T22:59:13Z"
enc: |-
-----BEGIN PGP MESSAGE-----
hQIMAwDh3VI7VctTARAAzjG3sJ25PaNOD6VowSNYaaK4DCY6PU2LGCCpJWzDXnwo
irJZUtGOiqeZeu/8BdWmQSwBiI9k/JuCt131rwXCrtj0+Yj0MRKTK/xc8NoDnW5t
R0CpQnWJ8yc1RRAMhx9l26HXH44786rhVt5/4ZCvq2mje6Ha0yK0vmjO6P+WR8kA
AUCuVUtQCtN5UP0yecdRHl6MvZe1qPd8tv3kLittJ2c48LD02CL3g0ZeATtCgiGN
5h9cBfDQnFcBh5EuMxn3AoGQjIJollCS5fRNNi1VUTp4uyAqYnyRjnORNI6vRk2k
hju5W5ThidbYQlJlwO6hZM7e/sW/XM8RWi6x4TO1VN8MuXavKnIbzlOKmJZlLbb/
yp0ueIzKuJpEz0nQZh0DFCD/D8yoTAfgtXgzzZKuUgErhkCQEXe/xKPDFvSKkWqA
AnVl6RwyTl5110Ea3535K3vycYR0EAxapEqzEZ0Ez/o28wR/1hgMrTWE9f++6HwT
wZ7EiPTs45yzZYJ0ONE4s9u9HNIvUY4UX3ncIhvTIWMyASfS2dbDu5fqxg5e+Szk
9QcDL0bzLnGCmR4w6fKUl2mkupTMsi6sfRFMzGlabK6FizUnpwNQHd2LAxL7rNF6
JiD6LxVQfY/TfKqQdKa93Ctf2k/tkdW2aw8JKZh02V9PqXUax0N4uR/TxOjKa/GF
AgwDC9FRLmchgYQBEADJTfHgtKmwdG4s+Mbml+VD3f0tDJnbOXBfISFp4+s/6Wf+
kILyeL7V4yllzJWqUZ97IH4BScUBSbvcg45IvuzgfTrBTx6ZSa3OQYo+2KS76Wsv
uQkItpGdsVSrLYDseH4cOWev9D5zscU+pEdT6VKXP47UHbJPdxQ2IU0oncrMatgm
rBh+PfB+XeJRX9mKzsL9qVWuc5k9SVcsXLKSCM2IJszfRy/vsSJcAphReHxXHSuO
XYGVkSYLGgzA1by0wjZ4Gi3y8MVaUEm8rXYVnbaVRnx5bntEfj1pTjmqStH0EE07
vkOooLLDFaP6o4c58jvRTwXBWKlBbgWqoSBgm08OPKQpFFpM+14GrLqGv5ECti6W
299pjfyWU99ILNG6RdQiS5MLA01z4wWYXRlxyNVXOHlspVaacX8cE3/uGOslURwH
ZbDgmpyAr3Ss5nj7s8plnxpYIRdXNCgPJ8qZtEVSuQkHbkHMKUJ8gycQNRcB8wZI
H4EtOkeG6mLt7WJlWa4T2VF1AEfQXZoewkaWCK7JekY+DPyyK+b3JT6qArAMvGMl
apVaDegSptYYUteO67yHwP83GNAGwDY+o1/ECZhG4ucGkXYpS6MCBkyCeV++gy3B
qotF5Hr5xSOK8jzFm7k4UUiBiQmv8IDh6UUOOXAzejxn61ZYPdA+aEIBiSoueNJe
AffTd0ldG9HGm016X1uYrN63xNCRA6kVUWP+2c86CTGX2GKHb4YgtULBrVRW8hUR
KoofPhcaEVIUvrnMrPDIrp25Uh4DRakUMQUwsOjfliLmm03/07IJziTMWTZkYQ==
=qR6M
hQIMAwDh3VI7VctTARAAiIJhabJhfH8+fwpni4PPFhAPGvSeG7q6SBmIJ84WueYk
taLXEHLJ11fXflfPrZY8iPkT5ilYwPcs/4jPTtn0eNerPVPAUrVcTT2b7agPNR4r
rvnIwtMhB5+mAYtHOVyXnWPfVt+l2pMoTV4PDzumgoIW85eARU8hT8VeN3yZaX2n
ipsmFKtGHPBWii/ev39RjVcqa+Bl+CLFF1g9j0jPCZhh9B00V3vaVqVRZ9OV9RQf
cGZfYLUS0ZMiM2i9SPPIAuFwt25SHob2n1hxKdYNUGJV2+TCBHfkjMfD6iQ6SzZZ
A8DK6VLVgXMbqM+6/o1UzW4DSe7aMVWRUB01ISjvkzEuKkjnwkLb2gJxiILKFFD7
g0KPZxrfF0Iz4gFmCh7lRjLggAaivzPn2EJBerVPAk5xikv/8xt/QfmrzsZ9Bnc5
YJMIUJWs/U+uKDvEsqWGMK5vGKUz8vmwWz9h0/sWwAGAoPxnHKZ9aj/LvIwcTVRs
E4TULZZ66PXprwupqtLaMMTTnW8x0CzsTatJfTbUid9ecQyeWSSCKQod8xK+dOwT
EwC+ysJTS//Tfmw1t9q7yG3lRFRsmIbD4tggTyP7LNqw9tKIrAA7XERBe4hX4wE2
HOiEBHlVfhKgWdgGfyVy+SdwSb3fBEhXFyxl0QnFWUVdZ2jvPLUWKO7zfYU/rdqF
AgwDC9FRLmchgYQBD/4gn7stoW0VDtqzpyxdo97BwGWSUaZxcAsDGtkZBdalW8WB
nsyTaGoxqeXC9gEJFdy8vnhn4B0yvC/UIQHUTaZPxPqeVm/OQuGcPISbJnXqEScE
pzps09nIfy8tidSSWCa+VerJkprhp9lU56QIZ+YmQVXzqtQF+oNsQQypaKT+bIdZ
d55kKGVM8EqtY5qidMBNH80eXvNvY1vONgMX35kdIfHuS2xlOd+O/nmUaeADcBSJ
x9583Ot8jRWiCtB0Ap5za1lwJtEJup1OtsqRGX9nbvxckZtPmTMF6KRlqIN6VVCM
Miq3UZG0x5FNkoUaHyXoVu5vwAnRyDAo2zZhqscrmPjen8tpzx2n6tKOQkk3pCuQ
ofWoGGg3SLs29MWrgkzKtsn21pIZZ90R9wFelCwqCehnFdZW3ElVoVQ7J9lnx+NX
ULWP+DfSMD5OP4MUIwRCzBdqAZaFgTxPafSQ2ZPXpzDzJhqqEFJBiJBM4fWG0RgN
1F3fB5KEhsF3nWn+J6ngCULanXBpD5tcHdRC1dsBeBpHRxCfPjZftEFs2JrJu73W
CXTAyNglUWN2jvRgnLYMPhafSK4JG3uA11nZY6675ifxzOqsebyP1JmG4bOquma4
ql+RmYgVvFq3xpYfaI4EsH5cAjOyYtvRBnBAzNVW4tj/Ytn5W1mvOPks+3W8dtJe
Ae5ElyCqI+AhRQ2+4ZvqhgfKIDFHPLSppFx3rjRQTN1NglCAl/AuiSwUA6lJ4G6Z
0/T4wrvC8fj9HmiuVsY8ALJl3RMpZ46v32uwyZdjRH69L+b6NxRXrw+uO3Ht2A==
=zr7F
-----END PGP MESSAGE-----
fp: 4BE7925262289B476DBBC17B76FD3810215AE097
unencrypted_suffix: _unencrypted

File diff suppressed because one or more lines are too long

View file

@ -4,67 +4,71 @@
"age": [
{
"recipient": "age1s0vssf9fey2l456hucppzx2x58xep279nsdcglvkqm30sr9ht37s8rvpza",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBOU3VqNFJpVEFBN2lwWlNS\naExNbUpMMWQ2Zm5kWklxR0dMOUZUVWNhYWxrClFBRkVFUkhaSVlTamxhRTc5d09H\nWW9wVzdxTkZjME5pbVVmUnBXakpaK0EKLS0tIHFIY2JwTDB2REdqWHRSQkFoaGE2\nN3FWbCtpUm1SSFg0b3BEN1ZwUEhINzAKFjA6KD3PK7BZRYkHLSs58ffMHrCwhvy/\nrF0zA2UKhIBN1LvYlyDdO2yZSOCK+0iwEuvz++VhDm1UnR0hDNu8Tw==\n-----END AGE ENCRYPTED FILE-----\n"
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB5dTNOa3NabG94OHZxMFdZ\nRW1ucnNCNHJXYXk4NzhtZCtocEk2R0RFRms4CjNPSVV1ZFhrazFJekpNTzhXT2FY\nenVJR2ljNjg1N3hwUW5teDJiaXhlWU0KLS0tIDd4dS9rWERVYThhKzNJYkpqbnpF\nZG5uMDhwUnBaWjU1V3pmcHB5YjJCQ3cKv1cyhmmH780Qg6GS9y0P/3lrrB+e0brm\nTYGhmyIGS4LqXwpXcY2rTAtajfUU0uk4C0aB5eyXp959yEk2I2cUYA==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age18cgqlely56hgmhscllkmafwpjdk6dwep6ej3vkk97dzemp8jtuksqrrjjl",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBoa2F5ejliVW80blE4NUwy\nTUdCamtkZ1hPMk9hQ1I0d3hYV2o2R0p5NVNBCmQ5WGZLS0ZnYzRUTk5rc0JKbEQ2\nTEM4V1hNdEhzWFFJbWNuSUpVN3ZTT0UKLS0tIEU0TGlNYVJZV1dCQkRHM0phYmRH\nUVg1bi9IQllUQWpkYTA1bGRyMWVIRVEKPiZdGYR0bxk2ldQ/4Ce1RcXyZACcCjD3\n6oDBe1DT7mPHN1jPertICLYW8Q5/LBRX63AJxZIi+epZMGszI4m48Q==\n-----END AGE ENCRYPTED FILE-----\n"
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAzVzlZeFlrcXdYd3YvdCtM\nWVROUndnblcvRVRBR1FZRkhYb1IyNnpTQVFFCjNSSHRXUDh5bGNEbjNVSHl3cDh3\naFBVMW5jUWQvRmd5OHJ6bWtpb0UwVm8KLS0tIFkvSWROZ1daZ1N1bzRsTkxoVEdW\nSjdaaE9NTHM2aDVNdWhNa051WXorbGcKfs2BbpCoxIe9z8EPf27xO+x5LwoTNroA\n7RLErW20t8O9f0fTcDZwz3qM47Py0vZ/jk1PmW++10ZFlcSNtF2DNw==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1g7atkxdlt4ymeh7v7aa2yzr2hq2qkvzrc4r49ugttm3n582ymv9qrmpk8d",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA1T29EeXY5cDA1em1oWjhn\nYXRuci83ekU2d21ZMFc1R2tPT3c5RHNXazFNCmFYVWNwYXk2Q1pTQW1pVWpPNkV3\nb0UwSk9BVUJMMTFKV0xxQUgrNVNmYUkKLS0tIDNpcW55MTF6a29nd1d4WHEwNTZh\nWDBNcHF4S1hwVzFTaTVycHUyMnNFaHMKCJDevUKtn46qMNpNjTIctBVMCLs5lH5Z\nfU2rzvwIBxwn16NCOAInRxQEOASYITYo7FKuMD7W+3eQf0vAj22LRQ==\n-----END AGE ENCRYPTED FILE-----\n"
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBkbnIrYkIybys5MytXOUxO\nNjJQdlg1czBndHBVYzhoMDNvVHN2MFJ6ZERnCmZvUE1hSEJSclp3Ykhya0lDeGNu\nQlFLS0JPcHFwREUwazNxRGtZcWJiS3MKLS0tIE9pUDNKRWJUa3c0UXdrblBGaCtq\nY0JJRWhLUWtvZWVQZHEvT3FRQ3BUQmsKN+UlXPD5hwUBa7dSJMt/Smjaz5jfG824\neJHaQskY/aRvC4CMRCBUwANSs3raQQirb4R3+XgthrA/92gwN3LX1A==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1ly2endyt0y9xyddj6yuj4nw6fa3ltvzlvew4cr4lzs6dv8dkavpqadmyxx",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBlZUhxUDdETlZCRnNJbldO\nU0NiV0hRVmtNYW5TWjdvOThyS1RSaExaWmdzCjJ3S1lXVmlFMjIyUEdad2xDWmlM\neFJOSnJSc2ZIMEJuK2NLVmdXSzRvcG8KLS0tIHlmZTNra0pzVVA5QThhN1ZaY0lO\naTN2S0VSTVgwSzBVZEN0em53STE3Q2sKlaQp9T/T7ZRY8FLB7yksMOwIfRWs/s7G\nPk3JnpuptFehhI/FeYAh+0fznBuTCKjqXF9X96a6RIFIC44/nKlfxQ==\n-----END AGE ENCRYPTED FILE-----\n"
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB1N0I0T0VGbmV4OUVZSU13\nV0kxdDJSN2V5SElCTFRmRUJkT0w0QUxNWkZZCnlYNmI5TFFicjJhR2xIbDlkZjlx\nbWZFM3FUWVRsSFFqZDVBRzJJMjdaTVUKLS0tIGttZ2dUMW45M0FOQlBwMWpoNmgx\neVdabmpybmpiWUdlRUlVcEY4d0d1V0EK99D1AXnubdAbSO3X+10tZ4UFSn5WY8ws\n3cQXdHryJ7AhRP7jA+4G6Flyriuzyv6TTGepZyTal4vmaPL3+mrg5g==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age15klj4t7gpfp69472mne4ue62pp6m4e04dmjyw7yf30qtqd3vl3uqjmcyxm",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAzdVo5cUswRm1yS1BWU20v\nN1RlMkRXR1dhcFQwdXZhUVNWbkVrb2RrVmxFClZVVDJ1ektCT3NmYlk1WTBXVGUy\nWllkOTdlZ24wMHdKSmUzdmFMd0F6SEkKLS0tIGd3WGdueEpWTkNxQnZrbXdXTzhB\ncXVrNk43NlA2OWE1cnpqWmJKVktsNFkKwyaRDz53nk8nljSnqN+CXY7J1f2LmJls\nXfbOZfFH7Ayoelv0OCoWCm1ZfD5QLnTBoCZGCUw21r8YuXzu5+maoA==\n-----END AGE ENCRYPTED FILE-----\n"
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBQV3ZXcWoxWnJEZEdQWWx5\nQ3poeTAwR1l5QWVmaUF5eUhxaU56VW1MUzJ3ClRJMW5JTVJIWlZYWFMzeHRZUHFw\nR0dlR1MyWmx4dWJtOXJSN2h1NHRqQjAKLS0tIFQvU2NWNmljSnNsZkFwMDViampP\nSFFOd1AyTmRNU3hONkFtS2RUbzBveHMK+tKQrsByW2KvpmYIFOmzf1J2N48ou1fO\nzE+gtHjSpc+bn8maRBNJxRfy3OKvNgfi+juD5shmdGo71TANJrAPHQ==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1k73gy5em3js9zklnnkzp5hme9k04lny32fgahmzddknjw5c295asdyr4x6",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB0dkI2RXR4aDlSaGhxQS9j\naXlXdjdscjJqQVQzblNQdkJxaWpSZG5DaGdFCmcwK0JKVHJZaDNzU1FlR21FUkd0\neW5nWHFhTDZNTnJzZFI1SEdTOExwN1UKLS0tIEhaclEvbXllRG5EWFBYQVoxMXBZ\nSXltdFM1a3Y5bFREVzhBRm1YS0orMHcKUrHg6YkMF20G+GdLI0J1pj1zLe06Xn3Q\nWwxgB6ctI8D1qs+0GMoXB7sOsfczgYtVt1hC6EvYpmiHW+g54GGRHA==\n-----END AGE ENCRYPTED FILE-----\n"
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBualhJWUN3R3VSNXliZmxT\nbWduRjNkQXFqeGFyWFdBSnhKdCtPUnJFUVRjCjNLaTBxTE9jYU1hNlZDWWJpeVY1\nUzVIMnZrUjY1d05Ed1kzU1BKbFJpajQKLS0tIExxcWdqSXlhTXphYUhWczZYTjQ1\nN2dhdHRYUkRLdTNjTlcwbys5eEdKNWsKnIXUrRJR0M4cPgSS19DBd/ovTAYchUL/\nfTsfVQJnDEiD1QoA6YZd7XZxya4h73KeWzfi+hWBpRW8ZawzZRlyoQ==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1cmzh82q8k59yzceuuy2epmqu22g7m84gqvq056mhgehwpmvjadfsc3glc8",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBlU1NCRFRYUVkwZ1VMTVlx\nVStFYlBaY3NGTThpS1NYMnVSdzVCU29NV0NVCmdKU0dPM2lySStVOENZajVRU21C\ndmJHVkhqNWFpbEpqOXdxd1kydjNFTXcKLS0tIFI1QWdmSVRHaG8zV29MSFJhRWU5\nREt1THJJR0RrK2ZzWlAzQ3dobjVOM1EK9sczJcZo9sW/rlKczTo3PYRmgm+mJ/ek\nyRniR+IaC+cdiSIuDS6nz6XwGqIrTpBjizpq3a5uWTzwzscU+uMuig==\n-----END AGE ENCRYPTED FILE-----\n"
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBnS2xSc1lqaUhrS1BaZlN2\nSXdVbEJpdzRYNkp0a1MwQjhZNzd0V01DdEdrCmNNTzNFZmhZQlk3d3AwYnU5WUdQ\naFFnTHA5NGptNUJ0SzZLWjMxQm5jMFkKLS0tIG5zWXNZWW1lZm8xdHFRYmRmVVJt\neUxUazdTT3VlSklBejZjVm1NTXE2MGcKFPA9tQB5RRfwnyfCcGRE7hpOxqkD52Q9\nohSQW87SmzhP6srUiAoao6cXihSk1mjtBU6HADL+TcjhchxN3lGDEQ==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1wmx8y2hs83j2u5srdnfxljrzxm8jtxl6fr0mq7xf2ldxyglpzf2qq89rpx",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA4L0VvQXk5bWNVc2FUTk83\ndGp2KzdrclF3bW4yQlV4emdCQkIvTmV3WER3CitTOVZVWmp6Um5NVEs0aGg2TFhF\nRWtueVluSUMySVBjYVFmaHlYM1ZhalkKLS0tIDl5ZlZ6bEpIZW0wQ0phbnAwbThV\nVHZ6R1lCZE52alJGS1ZVMDljQzZ0TTAKptXEII9sr9zkdAXJLLCKVd3E3pOsgnIB\nLNqoJfg336E2aquo6LCjtBA0nSBxHkAnw0FFz81Kph7zK+Z1+tFB7A==\n-----END AGE ENCRYPTED FILE-----\n"
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBrVitUYTlYb21uUlFjZ3lF\nTHJFWFh1WG1DNzltUmhYbXl2L3owRnZSZ0NJClFFSHM2SDBKQWpKbkVNd2NRTXlv\nQm1hdHJlaExOUm5zeGtVRnlUck5LN1kKLS0tIGdkSUFYMWkvQlA1dnNTZFdxVmNm\nVnliUHdEVis4VTFXOS83MWlZWVVmcDgKK0vs2LIng8RGRv2yCK8luWz+oJyYFEYJ\nvB2+jgFyFIBF7HQa0lPJzZzu7Ft9bPfskHW3APq+e403I+kJAIC0Jw==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1mjgw3nxlnqdj04mgjz3wn7fj2nl2nxla4p2r2fn4nkvayfgp09pqllxzyh",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBBcEZVc1RpbC9vck5zYmh5\neWxObTlpMjlpUFZYWExCUDhQU1BHS3EvL1IwCk5xelVyRisyZUVLK3ZueUdRTmxI\nWlhZSlJQT1RSZXNZNWlxRFJpenhvb2MKLS0tIGlxeWl4VnFXQ1VVMXNmM2x2WXI4\nejd6djF5d1k1cm1Kd1JuNVBiWnI5TEEKnjIih/AMCQOakcmiEpG4Fqa+yYDafML/\nSepnQsojq99JF6oxtGAa1P6ibmAIglRtyo5ypRRTVMm6LWt8Nul1yA==\n-----END AGE ENCRYPTED FILE-----\n"
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBoNngzRXZtajNqeHJJTkln\ndVcvVHV1bXZ0U09HYkx5Sm1ZcWpNVGFvS1NVCk9URXFMcGNoZEg0T29hVGVpRHRQ\nTkJ5RXgySWg3UWlJTXZMeCtxNFMvU00KLS0tIDlQNWZWRi9YKzQxK2VpZThLM0xu\naUk4aHJvcnhiZEQwSjZJYWloM3hyQ3MKn1X1EbTkSi/8IkjF8iSlRGd0MnP415sJ\nzfevVvPy2xVX0S8VS8C5keICCeB9pc26dpefQh22VS5BHgZMG8YaPw==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age16vzhcvz8tyxj8e0f47fy0z4p3dsg0ak4vl52ut3l07a0tz465cxslmhevl",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA1ZXpKOHRwWVByVXpUdHBS\nTEJ6dUJJSUQrSzc3MHZ0WHV6ZnM0dzlwTURFCjlxLzVDTDZhbGVpL3pQay9Md2lh\nTStxem5adyt0TVBjRnhsNmR0NnhLek0KLS0tIFhlWkQrKzFHall6Z0JXWEVMY0tT\nR040ZnhzTWFVbnlXdktVWnNuY00yU3cKmNYw+zRsH+KvxPW5o+fSKPKAVbxiVIoJ\nLZNXdAr6NGYMgKmvhq68M0C0mbLmmo505qb/oBntbfoGZJtSULAUnQ==\n-----END AGE ENCRYPTED FILE-----\n"
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB1MXBXRGxLZDdlUkFWdDdK\nR2gyWGdnQytqTkp4VzF1Qm94S2svc1JuZkQ4CitMa0gyUVNHT0x6Z2l4aHRsNUVL\ndTNTekw0T0lLdWRSRFZwV25NdTRsOXcKLS0tIHptd2tBM0hCQ2w3cnFxZDM0WWov\nVVJBU1dPN1RGWFhCZDUrdk9jMmZ0U0kKJ5Dt6N3ZATCQSO/PMf2AQDRBpeyAu1rq\nu5iDJdRpy17MdiYn02Tdd/c1N5TU5TqTxyePbEnAmnWHeGFronk17Q==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age15cx90pnp54xp5gxlt02yn9j2pz968wp3l5ukdkx55xuecp34e5pszjku4m",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBJeUVRU2hGM1RxS0d0Ykw2\nazc1MWd1ZEZweU9PRFRPRG1BblZTakx3WUdjCmlyZitaZGVwZHRZWnRrOGdSazMw\na25McWhRZ053Y2lRNmdMc04rNGkyTWMKLS0tIGtXRkZWVHdmRTNYcG9xZThZY1VY\nZ0gwQlptSHRzOUVCS3QrNkQ3aG9YelEKt+43DmQ0Zn1x7NIWl57eGxG3gsALxhMv\nImpMryrccmEV3Ddc2LPpxIaRYnFBJhTKDNOyuSOSD+I471PJlOu9yg==\n-----END AGE ENCRYPTED FILE-----\n"
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBrb2hmUS81MkVldzBBS3Bs\najVGeEdpZ0J3Vi9ZekR2djc3eW13dEdCZkNzCmxHSVQ1U0gvVWVUMFdkV0NzeVl3\nNkZDeU92Qm93Q1puZ1V0RVdBMU5MckUKLS0tIHhvbW5rY245TkZzQTYrNm1sd0tk\nY1N3dUNCbVhxL0M4d0hPTEVUUXh0SU0KBJI1e11cg1kSrKLdS3+18/f4KMqcVl17\nyNq38yKRqUNqZ8fV3f9usnZv3qdWuZl9XxNTfqsU6B79SKbyrZFcyQ==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age18quey88vge7xytclg2nuq4ncme86dg04lxwczqxczmdchnjg3p0saehsnh",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA3emtuVmF1c1hnZFNtcFkz\neVlnbW4xKzJIVE10Y0NtWWZLMXRQNkI2L1JNCjhpb0dmQU5pa0VOZnNaejZSa01I\nRldSSUxOKy8zekpCQVZtUTFMOGptZ2MKLS0tIDJIWDk0OWc0TThTTDJvdkF4RnFn\nZFowbEppZFdBc21SNWlFQVo1bE44ejQK2YVQILlu2yxCkTdwAP7J25NOgSHeNgJj\nOCrH1TU7mjp6dlB/hxeUWDRCbmqHs9ko054ZdXrxY+9BeodA02B1bg==\n-----END AGE ENCRYPTED FILE-----\n"
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB1OHRiWGdUYzRQeWUxUFM3\nY3pyUlRONWdvTGdJamoycmtDeTZTTklxSmxZClk4K3BvSThZNy90Q2pCTVBYL0lH\nZmZGSGdwcE1WSUV2R2VVZHlqL2RnOWMKLS0tIFlQTkhaa25tZDlKZmFMOE5GVW1k\nektlNlp1dWhTdC9ZVnVpb09sWmRCKzgKmNJ8XgJqnBh65PeMUb6VyfC73Lmvkk0y\nZuVYLVuBdHqPIPZ2vfqlDpdK/ejZd6ASAdkcNFKKJFjKQwa5nvLcYw==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1ax5hqk6e2ekgfx5u7pl8ayc3vvhrehyvtvf07llaxhs5azpnny0qpltrns",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB1NXlqMHAzUUZtbDl4Nnc5\nNmxISjVNUFJsNHlSUDl3U2RpWUV1b2phb0RVCkowVitwa2ViaEpFZUVIMG1LK0ZL\nVG1FU2tUdUFhNzRTeGI4bnNoc3ZuQ1UKLS0tIHZ3amttT0VkbkVuTG9yWkFQcEJN\nc0VqQ2RKb3k1Q0pkV0RjZEg4YTM5dG8KkUaAqAlF5hPuENwYWjVXFETePjtW7w25\nUUHOYmr+3j77FuT44TKYlmN4PJNAabbkDAcXDhBvtN4Ja41SGucy4A==\n-----END AGE ENCRYPTED FILE-----\n"
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB1eVJsM2NIRE9EQVJDNWp4\nMFJJeGltY0dmK3UyWnBXQWJCeFZTa3FVVHhjCjUyVGdqNmV5c25CU0tCSkIyN3JH\nQXJmVXdGb1YzZGZQR3NCWXNJY2FOeVUKLS0tIEhqakc4cHBleHFPamkyNlltZXdQ\nT216NnAzcVdQT09vZmV4Y3hxeWxtajgKgIkJMiQbPt3y5zbmDcgAxQKXUkA1JEIy\nUSMOusghzm1rbro74Mjp61QY7Gf4FP2OzDKTu8Ha5lMbjC3bSq9wcA==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1c2enwel9un28dcs4wg0vcyamx9a4a6g3walkhu8w5lqhmd804paq9d24as",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB3dGRuaW5XTFdPYlZMNkN4\najZRc1BNWUs1TExCdTAzTCs0RGpDM1lPMXhBCkxac2NmY1lpZmsvbzA4cEF4ekt0\nb3IvQTNrbk03ZWFKREhPZnp3OW5pNDAKLS0tIDdYYWR6NEIrOUtoYWxZdEJDWmdm\nT25XdkYvL2tXOEtFR1U1WlE4RjVGcHMKZ5MM7iTvGFi34ZoTNg65FHrJKa8SONcT\nCjdgJIcU/7wFbgTm295vvjfrXw54+pKUT3u9NqmPGVkA0o1rsBbZoQ==\n-----END AGE ENCRYPTED FILE-----\n"
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBURUFPTWRmMHRXa3JpODFx\ndkxQbHVCZmN4Z3Rnb2FZRWdMZjhmQ2ZiMEhjClIwZnpDS1dMUjdtSVJTOUtUSG1r\nZTdKM0hBRHZHOGo0bUZOSHh0ajMxY0EKLS0tIGw2TzFDMlMyT3ZYM2NCZmdvM3NW\nai8vaitmSStJUVRYUFlXUHRvUklYU2sKyQJI/SvpYeT65edWwGTMbOAq3FlN5XTJ\n7m+TkFHpGi1lG35aGndtYDqeXFRyOL1DbgRHO1AvThGI5av7+A6VCQ==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1nanlervuderw4qskcuessycqy2yfmptl6nym9scgp9ky2265ssmq3u73r0",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBSdEJUSGtOQ2JEcWg2SFJR\nU1E5NmdwZjhvYTVyK2NNeHlFOVpmVk05SnlFCmxJTi9MOWEwWS91WFBYdHc5S2kv\nOG8zRUJRSE8zY082eVBBb2JiUkkxZGMKLS0tIGRrSm1kY1NKRFk5K0t6bzVuU1hu\nbmlKZUJtVVBCb1E0NEJVRVJiNzMyL00Ks7khrDa6lLXFox9PB7VVas2qhDlymhJg\nX7By+etk2D0H8jTj/N9quJOfHZppLVuFk5w1rpIuJ2up+56Q/dGwNQ==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2026-01-02T22:08:10Z",
"mac": "ENC[AES256_GCM,data:dwn1YbVF8pXOItkLrdPHIXN3ZoXsCuoCcCuv9Cz9UQBKaIISS7xDpwVLbpf2DMxPmpzjq7cbJHTe714Zi7uN9t80wN91Kt1YKIsr14kOAuJkoCZPh35Sanqo0tL347C24E3PrpvB26RWGPqA6CrKp13swDPpljMrdhz9GO5bzo8=,iv:NiEV6uQXthBauTe6otoPxaoPNsaEKQ0JlzZNYna8eg4=,tag:mUc+AUMoDADysZCSin5XQA==,type:str]",
"pgp": [
{
"created_at": "2026-01-02T21:17:51Z",
"enc": "-----BEGIN PGP MESSAGE-----\n\nhQIMAwDh3VI7VctTAQ/8DSXgLzTxvatqeyCClZwBZ1fczXzy1eCVMRCtd49ci9Fy\nZ28xzCeWf78i5QAEr7UtrkfcDYXojsaiTROQ1VbWm+Xx5SP00sOTsmlMlz4qAVpQ\n2uhIEX+v14jkTh4xluqVmqMnq2cFQCNSoCEJfeUzYiH+IR0JOpltGAsewGc8BVPF\nKCl+/PnybTFeNXNvJV+k6jdw9pboAid6ehJVFW0K7iJ5Ine4fCsnlTSs1xTbofhB\nfzxUDZqLc5VpwCvlM/aN/pFGwGhxezXwYo5arFlcW5ZTpakVWlpBQ9+qF4gSTfTU\nfOaLnKexJnbEIpfK3IfmftZnoSEucs+DG5Fyxf0TNXnovVBk1Q24f3r3b25lL6Pw\nLCkTVc1WB3EVPDkLho1KGx58A2BTLvl8beKXoBDpk+rIFnABVYjqjJcxRSmqgkV0\nSgYxAghk+6UZs9iREvn9ruWRaYMJz3Zyda1cfdbyeqRDi7cT/C2jVaq7LLDSuUQW\nwyKjrAXaHtuNa5goUwPnT4hDgImekXC8N1qR5fzI47/ZoYymeCxGt9z8geE3hEg7\nw4jYcIV+oHFenu7RB3b3NOZwchUEeBFPGlA274oM3nHrtKpL3fclnV1hvHmNEB0u\nirclqP9EYh3DLfvtcXXTpE8Pm5/8QPVbFTIqcc3RMA7b+SE8ZvE0xgMC1PxJN6uF\nAgwDC9FRLmchgYQBD/47FReVLf9fl8aqqiDUnWz3/3Rcz+KUp7UisUgDrdi3L2wv\ne8mYl32v8qOPVPkKyEPIdjLfLhdcv1TxP3U6UT8C9TeP3Edile2s7MbuO6u1V1yj\nSuCez5naXww4KiJozwl6FtAZZZ9aKRLLkxsPcfItkCPKlxcKc2DvEDWKOdHBWB0L\nKYBf0u8bF2SUHR8ykeKybc5imMg3/jI8Vbu0gt8TfihU2btqwR7Pd291421S6irT\nK4/8VCsB4uPz9JxF91XfW5m86NPCTODcTB2C9VIWmdkxnk4jpQmv6qwkQqVKdApN\njJO8P4vgu2iB12zq+dsmx9W+TfSizocrCbuUBieq64EOx80QtZEgGc8ORf7MWq+1\nrO6iC0QjlUnAW4oRNV/Qv3l7NSm0pCA9XQL9x7PMh0f3rTYLajOrYDI7cZticAA9\nC7ZuVjUiMB8ykj8nfflOsXUJyHVYT8njeMqVEixEWehj6aq9eMx1VStphS6C/cbr\nXQT96ISnIG0fa6fNqEqzXBES1HYvd6Wo/jjH70wzNCWezvJ5IDANPkEhvThc+MmW\nxgPSK1+1UEzJGQ7uDo4Aadwn/Fym3P558icaEdjt8Ykay+gZsIi7ANVhJa0SI5tk\nNKAXvcSA6Dq9tnILre+oLewf6A/AfFdUesiantEaKjUgWQtad2P3iDqyJHtsz9Jc\nAXI8hZQSfOmDjpgjG27pTajjhmwNQ7XD2ttm1iHp5ho16zYtS8bDtX7bEB35YyM+\nFBuxrwcUNDD/mfi9uAtcjQm3x/IdLU4e+NL07GvSEWRU5H8pUBPcaOeUqLI=\n=pnj0\n-----END PGP MESSAGE-----",
"created_at": "2026-01-04T22:59:15Z",
"enc": "-----BEGIN PGP MESSAGE-----\n\nhQIMAwDh3VI7VctTARAA2YLNxz/sThqhzyG/y8eiKLCXlB7GTZeO7UVw5IQWEvCL\nGQELWjkdVC3KqdsJL6/TmJHZGiH5Wlua7yuFmLGcvGYWQE363S0mhKZa3QmUeVhl\nT2nq4aCmQ+cv1zKZUNzi8GQsZ/utGlxbJrEBBfJxLUq0xTgZKcl9XJsHi8uZNO/x\nzOmUiR4DsTu0h9Iun05FENbydmoscTyI5Npi299F8NpAvyox4yWC6Tu4AjCfVFCA\nEJQcCMnjWO6Ux4LsJMgqVJEYFMkuyv5LV5zbFwO58GYaj5M1jxOggOZRAAjzLSZW\nCB3Sx8OM91U/ajVzfP2tmnysDt9bEN/f0mhlSm5pHUyufC///xDFoXfgP0x6N4/G\ngxEX+JyRYnfxaZyW/i7kIREhxWFbE4RK6SJ7toznjxFE3Jqk94wzW6tEOzjs0m5r\nReUliQKdqfzYTsvJGFNNq7N/OK0hPI+Zu26XbyBcdqRRMCqHTIH9bl0ThZ4QaO2G\nG7r7WdCmNsw6mCz30w8eAqSQ/ICEF68Yd6tXNfM/xk5Rh7dwdWqZyobVJ+3hQUwo\nyj5rQzjk9GaZHtUB1yvpM1GVFFQqi93qCYImsGuMLtRwnc2RCsFqUYAL4/i8QPgI\nEWd5s3kydbCAs8Q3oN5wnNrRkbBFY5ThOZTJlu21EFjmpV2fIJ5Do9Z3nOpZQWGF\nAgwDC9FRLmchgYQBD/9ywMb5GgyiyG8015QNtDqOGw6yCE6pUSzusuxmXN7yECK9\nAn+cVeqC2c8ajdrVs5fdiG+IiPBVm/4Q5r2ZFYgNTMrNTLaar0c/4+72PrHXISQP\nk+M9H+toy44AleSDbncYWTHwcMWwBDIrKad6KNrlTc0K+wn3JXGlL3ZPo/cP1OUo\nM78KdWo1bc+fHljuHHtmAzX3K89JZasxM5kW21vd0/1jiJklhH2EVrphgixIbXIb\nX6lt5zQVarl6vU6wTKSKkRhYaC/1t/vGPl0Tw0a7jNR4pCRZo9GgwOJjgkYLa/+s\nZUOVqDJrIZsTr46WJcBdxRQ4DFMUxPB/Mq7qKzXH6freu2BjBG33ornLedmkLElS\n+QYi93cDlsYtw0+K3eozr/jkd2yY2GcQPtmjdkI4KZ/ShnaPdDwR9G9KcGVDeJXm\nUUSqyDndko/woZc6sXBBYMBFy5jmYO3A+K05Q3eq4pGn9WUrTSVVUxV07+Cij2X2\nAL3UmSV7yBCooPc1tjiz0XLVJ0/Kb8GZYTFc8PBpT8eATYEtLawGAAHa+TY3gnW+\n4np6diWggYK/8LtUXVTvW5TKTFDQ/cXwzHAjWYSgHo+z7jvU2JI2nqB4Z/Srzztt\ni6VlLOHqZ5ODdvJqPqhciUZ9NSxeGhsPi6yS0dkrJQC3XjxYLsl2/N0clbUoltJc\nAUuhQ+EbMNJSYan9rD9RYvIH4e5Bh8YSOMHnnnham8wfQCr85f8RMvUxczUu7Fjl\nUPUdcZy2QUsaNEJsCat5z1pMbwSdWd1rtf4j5/ulaFvyv1M0Yazt9yQTQV4=\n=VUnT\n-----END PGP MESSAGE-----",
"fp": "4BE7925262289B476DBBC17B76FD3810215AE097"
}
],

View file

@ -3,6 +3,7 @@ wireguard-twothreetunnel-moonside-wgProxy-presharedKey: ENC[AES256_GCM,data:Y/Ew
wireguard-twothreetunnel-eagleland-wgProxy-presharedKey: ENC[AES256_GCM,data:dF8VPApd6iYKIZjBXB2rjIXIxyy2+U76TdyFuyUW0zSbtjzqn1ZKrhX4w/M=,iv:GqOHsS97di9sHqjndlq0EdWLcJ1EMLmDOnFJlBgTvYU=,tag:PdxEYlg3lPShUJYlANLjhg==,type:str]
wireguard-twothreetunnel-belchsfactory-wgProxy-presharedKey: ENC[AES256_GCM,data:NAbVE7ysGDD6TT0RxdL6bTNloac4RBU1JWeTFqYo9PO6ZU2f/yq6aboi2AA=,iv:Ky4UvgRDEG1UgDmi+m5mHWHO+yUGzphQPYIuyAXDkhw=,tag:WP+/8q8jfitNC/rXN5Mp2A==,type:str]
wireguard-twothreetunnel-hintbooth-adguardhome-wgProxy-presharedKey: ENC[AES256_GCM,data:Gr9tP9SkizZOR4brFO3+7PqDC9pG5RojWa+xDDtqfZT4Xo6ZAN2002WGUXQ=,iv:Zj7oy/d/o5sNYTsyPaUQ9Th/xDuG7o82NpnP6TZzqeE=,tag:OI/DCxjJNpZC1C7foO4xsw==,type:str]
wireguard-twothreetunnel-hintbooth-nginx-wgProxy-presharedKey: ENC[AES256_GCM,data:2LdQ/gIt42qnoK8ZfaQO43YzZr0VZe5guji8N9n7o2eNLL/qMQ5ZFbFNa0o=,iv:3U1WmLaUi0CDLiW53PwXE1zvtO5YWfdLw2O/Kpudyww=,tag:CTmwvF8CA6MrqLzQSGoBtg==,type:str]
wireguard-hintbooth-winters-wgHome-presharedKey: ENC[AES256_GCM,data:57KGUxn1BibZ+9H9mXg9EYmcy1JBX+M79ACL3Qt0XEMl0dFlk9Wq6cr3JTg=,iv:9QHdykNlUU1H0uco21zA8leQH73PAeL+xTVi6V9zx7U=,tag:6mfSCddnVGMBEAqCHDIIrw==,type:str]
wireguard-hintbooth-hintbooth-adguardhome-wgHome-presharedKey: ENC[AES256_GCM,data:zBfV5HMy3h6q7yEF6Cu7sCTONa8nJRmMDHgVFvHVinKmyj0qpf/WGfnyb3g=,iv:3JlNgsJHkE1EawLWIJaZsiZlu7pN9ymFQ5ZqdM7W+AU=,tag:pGfsh34HnL8mUhKyFkLniA==,type:str]
wireguard-hintbooth-hintbooth-nginx-wgHome-presharedKey: ENC[AES256_GCM,data:BGdVjcCyhrSgIIZtdoBUscCitNjBat56YjZOFx9Vao3vBMjoHFGY1WFV7zk=,iv:wxVClKJE6R178vCp/RE3PgBYYLIvOdSV97AfJagWZ8o=,tag:zbuMwlJYIKtV7ylwvgLutw==,type:str]
@ -11,161 +12,170 @@ sops:
- recipient: age1s0vssf9fey2l456hucppzx2x58xep279nsdcglvkqm30sr9ht37s8rvpza
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBOcGpVNWtxdTJLYWwxakNk
dW5vRTNEOCtBNzlPbEpGR2g5MDhIYU5pWmlzCmo2YnRGU3FCZXBXUXNTdm5qNzBD
dWNHYy9kZTJwaWxHeFFmZFh2ZTBtbjgKLS0tIEliVHZIbWFFYUdOUDljNVNwUTNS
N0c2ZStaaU8wVFRKeTAwRmtDV25wc2sKjFO0FeMx3v5Zn4Ipm2549/boRorripM/
q11ro/tNhsSt+GJ4FTQA2hnmRj+fG7BQuTw/ewXC0posKS5optxAbw==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBHL0RGd0F3ZW93YjJabnFC
WWNZUHBOK1RZemNraWF5MXljNGRUaWNDRlhnCmZ3NlBJTCtQWlF4d1BVV0hLY2NQ
TTNEdlFmb2MxcmRkNU4yU3NmZ044eHMKLS0tIEdRU0VjZElSNnVMREExdlpwaE01
S2VCaEN0SUkwdWY5ZkxVZDdkS2JqbFEKaG4zwEtWtrVAW8jvFgwX8eoe7MM9X0cQ
E/R67hG4G/kewIj/gz3dbN0vI+hvTdx+doR1MVYiBee7iqmgICLTew==
-----END AGE ENCRYPTED FILE-----
- recipient: age18cgqlely56hgmhscllkmafwpjdk6dwep6ej3vkk97dzemp8jtuksqrrjjl
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBsTUVIQTFYanlUQWswRUg4
bSs4ZWZYcnFMVUlUUFdyVnE0T21IVkdWbTFnCkd4dndFcWR1RXRLeCtXWlYvTUFn
Uk81dHZXdTBSekJkaEZxUWZnZnUwR1kKLS0tIHc1a2tpSmNOc0s4akRCVzVjcVQv
cVNDL1JGd3dGNnIxSHhNckFLcTFJUWMKzqsDS/S3wHigjHBSgztEmg2na/2fR9As
JxUe/ZSdEaMKDj2ZJ3EM8u5aY6Sp79aNypHsPcOXjhX0VoAwPtRqFg==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBjMmxLeER3Z2NZMHU0dmlE
UEdKZ1dKdVFzZzYyQ095WnNpZ0thMFZWZUE0CnBtRFNGZEE3Q2EybGpiODdES2JF
eU9Wb0FFVlpSNUhXRnBFdnN6bk10RkkKLS0tIGpzaUdPeEtnY1BjSUJ6NWU1SU5a
ak9OenBtT05lWHVXeVl2SUZ0YWZ6UzQK11o/FPoXrkjOry+4+oiE831HPQ6Cv8Ig
V+/zAg2Q+pRsMuVddE8w6S5SI3v/jgTZSGbxyC8Csj3wNxxBvx/SgA==
-----END AGE ENCRYPTED FILE-----
- recipient: age1g7atkxdlt4ymeh7v7aa2yzr2hq2qkvzrc4r49ugttm3n582ymv9qrmpk8d
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBrMjVXZVFnTEczbEg1ZXBG
RmQ0c0RoZS9pWXdhT0ZVSURLVGxTWFBWM0FjCjV4cjVER05YZnFaclJnVEllSURy
YmtzUzdOK0pldjJiaFVKVDcwY3VzQncKLS0tIC9xMUd2OVlsZ3lmRDYyYlZpYjUv
anFDWE1CNGljY3ltN1lpdk9ZK1JySXMK58PNBo74DHptQTfT1ozV3Ikgf5BccRIH
Bw26F4GF8hjJL1Gp8szouJ9iN/mSNR47NdQN0nWy0GfOs5fClFfWvA==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA2SnFWVkxEanFYV2dKY0R6
d0dKWkRJK0pBZm80SFdwNnRENjU0TUVlalhFCm9lYmUyVHQ4VWRuNWFOVENpcldw
RjFPNnA1cmRxZk1Bc2s2Ni9LeWg2aGMKLS0tIC9OckV0bEJGT0NmbzhyTjMrUHhD
ZHdpQUN6M0VVKzhCcDlBOUV2VWc0Z2cK7Ns4QO4dhpq2zSEuDGePjJfXRdc3DS5O
+nWgDGYzWxq5dRXc52X3y39ozi3cwGP7hysVvVvAANrJAq32T7RljQ==
-----END AGE ENCRYPTED FILE-----
- recipient: age1ly2endyt0y9xyddj6yuj4nw6fa3ltvzlvew4cr4lzs6dv8dkavpqadmyxx
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA4T014MWhrRjdpRGkvallr
cDIwME0yUzZseXZVUlBra2d5aXgvOFh1SXdzClM4QS9zanRhWU0xZVFSdktDaWc2
TnFWL0N2M3VmUFVMWFN1OGxqSk05QWsKLS0tIG14L1BiVnJ0NFJCYUZnWXl6TU9v
VTU1ajNOTWxWTG5OUWRFMStLRXJlTEkKR8JA3U5MLBwMnFDZtlbrkJxmY9nENsza
JCmxPW1BTH+VadbefjGPAEwVj8XqgTCw5f8awNNZFUUe0SIud80pmQ==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBsQ1h0LzVkVFo4TjJWSHdw
Qy9ZRTIxcWNTb3NHcFhZOUJTY1J1Uk9jSURJClg4Qi9VSGFBMFQxYmJySzJkSjND
NWI0T29kVDB1YWhLamgyRE4rKzJFaFUKLS0tIDhkakx3Zkdhc2R6YnFPenFEV0l6
L21HWmxpT0pycS9jZFRVVFRuSDJJWnMKUl6daQgN1ldztZNGQZHix0tUNZVTnS2U
XvY3OGGtFfqYf/2+GfZmGsJEKMPAHX5nGQe2vyez5jrtYIwI4WpGMQ==
-----END AGE ENCRYPTED FILE-----
- recipient: age15klj4t7gpfp69472mne4ue62pp6m4e04dmjyw7yf30qtqd3vl3uqjmcyxm
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBFWmpBbXY4YVZmVkVzQ3FW
eGl1SWZqZWFSa3lmNFBNRUh4UG9qREhQR2ljCk00bElJcHk3dTFNaG5FT1NiOU81
aENlNHpkckFoRUVpakpmb3lIYU4zOEUKLS0tIFBpQjFEa2xiMmNHM3NhKzMrMFl3
Vm91bU15TFJwSUd5WXI3VER5WnFEZlUK89Iu2PeG/7mXaTaCUClCVL44VFLJEZpM
1s6QFAemy/B5UYeZBQsWiN1v9yAktvA+B7BeS0lyZohpV6SypLgjGQ==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBZdlJuN0E1TEVKT01SWVRk
Y0pYeUxHOHFRUFRFRjlRY0prOHJkTUNncGlzCkRERDM2bjZBcGx5Zk5MV3dmRTht
bXhBQzBxYXQ3OFhoS0ZleTF2TnlabzgKLS0tIHJHdXM1SEU5ditkUlRYejBuRk02
U2l3Qy9qNzgxU1pBK1ZNaWJmVVNkQlUKToTU77sH9hEwJerlJTNftzV/cD/Tx9J+
2SCd3HyfxEwRzc4nbpJzATu+gnSnE9AbwFdrYlIayaJtT2nXqgJXSw==
-----END AGE ENCRYPTED FILE-----
- recipient: age1k73gy5em3js9zklnnkzp5hme9k04lny32fgahmzddknjw5c295asdyr4x6
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA5RW9MOXMxcmZQRkhKcSt4
cXJRYnVPVytOVDY1dlAveFg1eWlMZmxqcTNZCmVhaVZyZU9VcmNVczFLemNuYTJJ
SG5WWnNJNExBanVJb1VlT0VIWUtmYzAKLS0tIFBtSDN5aEJRVC90ek4weENZSmhQ
QUMrY0dlMStHZXY3VzBkZ3NZMFVnYzAK9C1GRRqXNWesrK3JYwol3hDkmjaBBUNW
3CroUXgWDEQ5U8M3aFKSdhXND3WkPdDAKpt9cn34lEtlUOoy4MF/AQ==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBlN1VaT1Q3cjlETEZTbEZZ
WkRlMDRzanU4QXNnT2tyWjhTNCs1ckoxTXdzClJnR0JsaE9JM1Bxd3lGcWFTYTZu
a0d1NXZIRDdKNUZLTW9JdEdDY2FWK3MKLS0tIDRIb0xxYWhOc1pJQmt5WHI3cVZ2
eTBLZWh5M09yekJPNGVBMFkzSXh1Tk0KgATVjuxSUd3eqJV2HGV3cMrTpTtfNSUb
SJH/M7ixk+0GQv3DU8QvuIAf8w9/uKjs9nS7dFlHVrJnDWCAKpNYgA==
-----END AGE ENCRYPTED FILE-----
- recipient: age1cmzh82q8k59yzceuuy2epmqu22g7m84gqvq056mhgehwpmvjadfsc3glc8
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB2TTV6QTNBNzV1T1BVQUlq
OEVGUFpvNDlUT1lWanlQZ0E0cDhaY29vRUJVCkVVbzR2d2gwWGNESUZNSGJianBC
ZDk5anJ2V0hwQUVEMUg1dmZFLzFLODAKLS0tIFlGR0xGamFKY3lwUkhaRFMzK1ds
U2dyTlNkdFVTYXJKQ0pBRnE2S295czQKy0E1Iajqkzg8cyTYNXoqf9bas8BaBP4+
x7kjIbKIgBbWpT3niLA6Zl+SN0tLva67ddau4undz7YA7OZ4VzZ2Sw==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBFb1d0VTFSVVYwdjNaUmt4
WjBBelQ4QlYvNUcwV3NVbUE3OEF1WlJqZW1RCjc0V2U3QytGYXJTTUFadk12V0Uy
QkwvSXZRUEVRMzk4V2ozNE5EWWh4TmsKLS0tIEVkRW5JUTVWSVAzaVBpaGdSWUNC
ZzBrN1VlZ3pGVGhaY1M0cWIzcG85R1UKSGFw4lYFtwEuLKNMmNew3ADiXHjv8B75
NjeDvYco/mYOj8+TyqI1QHmlo2GjLSNX2M9M/Y2Braxe0obB41KsjA==
-----END AGE ENCRYPTED FILE-----
- recipient: age1wmx8y2hs83j2u5srdnfxljrzxm8jtxl6fr0mq7xf2ldxyglpzf2qq89rpx
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBnajNaMk9JcE1xSHpyOHV5
L05FL2lPd0ZBNVBEQ2thRDZEdHFYL3Nnd2hJCjltSnJ3MUVvSGNyclppNTA5TGsw
OVozcGJ6c3RCMXkxTnN0M25RcFhyVDQKLS0tIGljdHZUaTNhVEZKZE1FbXNaOGVu
T2k5RlNWWGt6a3NSSE9CQjFvK01mMncKuUQ8PeSkfj0RJgDRWbFXBFAuWAOvKAox
LxBKr1TZ4oHIYJjtgP9mnKpNL5ikda+EkdEAt7V7exy2m3SvV59frg==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBubWpoclVFQm56NURMMGVi
V0FBeUp0RnVnYzFiektrTmV0cGh1d3hVNVdzCkF1SEhFcjJ0N2NwM2V4dWVIYmZ6
REN2NU5SK1NxbXhMV20zOW1mbHE2N1kKLS0tIENSWDBiODBKMFV0c2RmdUIvWkRJ
dFZhWmJNWHpNQmtlNzFySkFpZjdXdDgKsOnFEvnjrSkhoBCkXIiUaDjJmAEueux2
HAIIm4jHQYlz/v6j969TxaAln5KW+78ao+Ma4by9rX4sTckbw2bTBw==
-----END AGE ENCRYPTED FILE-----
- recipient: age1mjgw3nxlnqdj04mgjz3wn7fj2nl2nxla4p2r2fn4nkvayfgp09pqllxzyh
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB3TFR0dG5YVjRYZUs0bk5W
SE5aK0lRWGhMVFhNNmNKbCtLa2tibXhJL0JzCldGN1hNdldXVWJ0b3VwaVRFMzk5
OTdjTGpMS1NUTU50RjFRaVAxSHcrY1kKLS0tIHNvaEdING1kc2RMalhZL1FqL09K
d29KMENYVEVyNzUwNEVvbitXSHVjUncKokOmKLepXUcsYf/5QUBlsd0G8ZyCsV6T
z9otd0AdEPeRTSbh5pJ05WYEIR929aEPlaLLGhIdEI3XCOHey6GpvQ==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBlTUUxY1dqYmdLbGdVOTFQ
T1d1R21JV3NzZkVYV3F6M2Zxb1RLd2t1L3lvCnRvTFpQZGhUNldEVjZSL1Z6T0pY
UFBxS1kxUzdOSXBGWllHcW9jRG15S2cKLS0tIDU4UUtUeFNEVWI4bC91UWNkb3hW
TkJ1Sk9ZZE5oODFXS0JlcWlNSUk4UmsKtTTBv8uYQFSFlIRdzpBl9rdHPxpIHj/t
agccAsKe2x+8OOZZEnXhwsI5Il4bavm5X2orsP0kUcyfkuRLR++zyw==
-----END AGE ENCRYPTED FILE-----
- recipient: age16vzhcvz8tyxj8e0f47fy0z4p3dsg0ak4vl52ut3l07a0tz465cxslmhevl
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB4ZFRFcDc1cWRLeHhmZ0dB
RFNOVGVpMENydmRMRkxuWXpCaHdxUWVwa1IwCmRUMmUzampKS3BidFVLYjJEOU1F
eEFqVXRCakpTclpGOEpMbUdVbkZORkUKLS0tIGdjUkg5UmRuV1M2Rmc2Uk5VeS9t
Z0ZtWWFRdkl5NDQwVjcvYmxKVG1wNFEKrP04VYIFR2V48RqpAMXgp1sDbr1NH0+0
kvWoYuJcaKB1Tw3xBaLmrCjKt5Xd54linwpgidX4dOAqHjHWyNIHjQ==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBzZkJacmZqQnNDLzhDeEpk
MWxjeExMd1hOUlovYndaNU1qdU1qbFExRW1JCjBZUThjZzNQak9uL3NHVUlWakpF
N3NaZ3RhdkQ5UGllTTZRTjBxbWpqRE0KLS0tIDlES0tSNWl1TG0wMEJKdVBWYUF5
Q2ttL3pZbkVFZ2Y1aWx5bXhlem9tOU0KH3JQ2Xyz6BK6rNHNd8b/Bprot7fwUyMw
FFBQAILpD79ioHvCzanPvUj4KoLd1jU9nRKMdXX0hcWOQchoQ/XnBQ==
-----END AGE ENCRYPTED FILE-----
- recipient: age15cx90pnp54xp5gxlt02yn9j2pz968wp3l5ukdkx55xuecp34e5pszjku4m
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBIeFFhbTRvQWNtaUNZWm5l
bnlBbVBlb28zd3hMRTFxRnlacUU5dng3SENVCnFDT0J0VWJmZXhueFFmTGs2TUlP
a1I4TkVnY2JPSkJlUmU2U3R0cFUzNmMKLS0tIGNLb2JVNnBZWDM0QngraUFkSXB4
ZHR1N1Ivejc2VzFVdUlKL0lvdXJja0UKENB2JzmrXT/sFVpVzxR64OpoGwq65Q3H
KamGdqdsD1+MYsbnklUdHSJqqAbfTH+BYpjKtF+ZsPqaXcKB9VjKyQ==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBHblVvWWpaWVhNMDdTbEZN
SlFTdXNzN0NRT2lVbUtpWDh5Zm5XTW02cGx3CkNvTVYrUDBDUk5lYWFOSEszR011
UzYyTnp1YkVEMllHYjlIdjBHcDRiUEkKLS0tIGw1QjBSektnOG9HU2tpUEg4VDM3
aE9iOFpHbVpPV1AvR0E3QzZkdWE5OVkKy6k35mWpKLew1VJyhBAb9+7VSg6+y2jy
1DaTZ+5drVLyMnfFqbI8dyO3laT/R6MqjEEvgaozUoHxjjELa0rTvw==
-----END AGE ENCRYPTED FILE-----
- recipient: age18quey88vge7xytclg2nuq4ncme86dg04lxwczqxczmdchnjg3p0saehsnh
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBoWXJ0NUlEbXZNdHlzcmlC
N3VoaEFKVXdMTjJSYXV3Vlp3dmtFVCtNang4Cm93RDFVVXgrQnM4K2lraWNSVjBo
emR1MUlEdWJxY2h6RlhTdEx1SnpmZm8KLS0tIFlLenQ5WC8vZnpGVEZmVG1MbFZU
NkRQb3c0YjV1RnhzUm9CRVRtc3Z2MUEKbwFjrd9OxDUmw7SSMGYXjlzsMVL12iNv
31E4a7ZCPw0zucoJpB3kFkQ/0vveOHZU3bjj0htm89H1BIaW0AZkzw==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBvWXpUZDdaRjJTeGoyemx5
Tk9rSVlRY2JTVVkvVUdGbU53SHEzRHlKeGk4ClN2ZXRlbUZ6Q3ZHYllKYkRObVJo
WjZ4eEdCNzJpNy9pSDFTZUMrSmNoLzAKLS0tIEQwa2NvYWlHTWx2YmxPVmFtUTJK
MTJGZWpwQXJ3cVRTMWZaTDB3OEVLbEUK2AN9O+L9GyaaMxAGJjaOeY/dLd8qhb8U
M8kMdQKNvhFJxTS6j9oMmfM6gIp3v79ejWLefXVjOT27kJAfw5QZHA==
-----END AGE ENCRYPTED FILE-----
- recipient: age1ax5hqk6e2ekgfx5u7pl8ayc3vvhrehyvtvf07llaxhs5azpnny0qpltrns
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBCdDZ1QThYRGJ0Ni9QNk9D
eE41Y3BsMmJWVkRkV05FWjhlcXF6ZlhsOEFzClBzZGxpU1Y1TmJVOHN0czNNcjZn
UGVQSm5RRWhwZjVDMDV6Qzk5RmljMjQKLS0tIGp5dUljSEExUGNxUnRZcHVTMFdj
ZW5MY1NJMmRJUmcyRTJnVDMzUzB3cHcK54+0I7202n4P1kZGaCI5kM5BRAnNh/ts
7ygeuksGvi+7gs2UFn3LCUdsaL7RsBuX3NBiVyBvE02gfKecT7W/XQ==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBLOTd4YlFodTN0K0o5dmZq
Ym9qR3B6TVdvbjlETnNCWE5kS3BVNk9iR2hrCklic1Rha0k1bU1tTjlqNXhIemQx
Z3hmV0orVFJuM3NSZy92YldiWmNBNkkKLS0tIDU5RkxGUUdERW5uUHlzZUVQL0ht
Z05sT0JFcmczS0kwRXJMSFozUFpOL1EKUEoSYae/2AhcnL9RVUtPuybiRW/ojm5N
g2hEYmjsIZCrYDa/6Iyyk7KHUS/55tD+zJtdp83b7pYan2FGvpKWcw==
-----END AGE ENCRYPTED FILE-----
- recipient: age1c2enwel9un28dcs4wg0vcyamx9a4a6g3walkhu8w5lqhmd804paq9d24as
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBKQ04yNzR6MXU3aEdFNU1J
c29qdk5pbjA0Q1FGcUZTaytrWFNyM3RXRVNVCmVyU2czclVjYmpmQmNuTmhHdUlv
MkpES2FmK1JLc0tmN1BBRW95YXl6SWcKLS0tIHhCendLQ0ZmbThYb2phTG1CWk53
TTErRmhuaDlkenNSdkxiWEVTSGFEazgKZj2nEn4bgT8+oVUG38UDGmNrq9wAk7sq
9PzYw3cjGwRUFwT4lV3vK8ZNU6DAepga7ebwxfPNjP35h9eMtRVQIg==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBhRHZWeGxxMzJxTXprb0oy
MnhBT2FzYXlROGVGZjE2ZTB1djhIK1BZd1hFCkJYSEtlS09NYUF0VFNqZXpqdWxv
TVJJSlVTRHg3K0tzbXFPcDUyTytMNDAKLS0tIE40Z3JMMHlCazZKRFJUdVM1dGJO
R2J0eWJIQmROZU0zV1k0dkR5R1V4RUkKGcuP1pOhyABTqfiOrKuHM6id9uMuZsVR
QfUhXXve7RxghZu/eHYSPhbsPmK5Awt2rWzW/YWsNX/Wttrm6j13Iw==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2026-01-03T05:23:41Z"
mac: ENC[AES256_GCM,data:D1iqvJh7qLoC6GlwFItacyb15X7LrnXZfSQQVhFRQRnVbFc/ECqM6P9OP4PlCfAH5Up0c/iv84MsE/UFubGKGR0i19lCQ78nLPNkFfvJ+NXg0sr03FiFmW0Q8hwzauzdMUiQr9/36D/ax+BVBTQyWgZEneiCY7KoDaQKJWzOGT4=,iv:+AZ+1u+TZNqrLMaDcHU0fgPsvx5HFprlKQExH5pIjyM=,tag:ytnj7FQQ6YivKncyZUHigg==,type:str]
- recipient: age1nanlervuderw4qskcuessycqy2yfmptl6nym9scgp9ky2265ssmq3u73r0
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBMNGROOGE2MHN2TG9teTFX
NHBNV3loWTJ4MXRRRm4zc21MOFpjYTNLcHpVCmJDWnlKc1JzVExnVTEzZ2xMRDgx
Z28rK2JEZzF6aVRRWE9vZ2I5MC92QWcKLS0tIDJjV1FpcTFvN1NqcFpwVWUyalZq
aS91aDE3RkliYVhRWndkSDRaRkVjNFEK0BFAxjd+QAsN5WYiKprfpYOHooCs35Di
yw8IEn7iLdMXAJz7ia5GRHWF1fjF6Um7WaoyQqX50Z4NNh7w1KkuDA==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2026-01-04T23:29:21Z"
mac: ENC[AES256_GCM,data:SfZxZpnYQsNQeAdIsnN5eGW7zha4IhCCsprTLk6YUwalDCBYqJ87AY2nz7FzdGvsm5WaojLTXBi7kOlepD3UnJ4v9Qi76tNYCVhLO7djGBW7t9gteyNsJwz2kxCZSKPXJ5nvTB8cLyDMZ+qedR7CO29dV/R++wQ04+Jp0vS8wtE=,iv:w8oYMzEhgjHMKJMpDlC5ukg2CEoG352jgrTF8zcUOn8=,tag:1SS+sLwjCBsdIwn2RoG9Qg==,type:str]
pgp:
- created_at: "2026-01-02T21:17:55Z"
- created_at: "2026-01-04T22:59:17Z"
enc: |-
-----BEGIN PGP MESSAGE-----
hQIMAwDh3VI7VctTARAA001QiHU3uO1goHUTsx+QnhCrfIBDjVAHhZtj8CEx1tqk
YaxNUNDra1uyGQqwdH1Ly8h6cSzeUfEtPfkjsvegYo58PSkz5F6mrpROkB1mzzfG
/H3MpCHTzroXPmrT3lNxXZyYqxGzcfLBLU05etEiFV+sV2mjoV1nYY2gTnH8XtV9
HVayfxR4cYZOS7ox8SkGoTvZHsbNT5+jaJn7GqRjrcjmjd7S3gvq83ROe82YHNA0
1O04PSGwnaGC88E9Y/7segZC8Tl1e25Z0c8yMd8JHsn/RL8beHwUHTn6nuyo65Bj
Xmic9M5C16ur5yQtVr/+xU/FCbmkecsOL4u5YgECFt5w7zJZzfGUHa2Z5dIQ9T5o
2oY/h+GsN9xTM/6ZVcgCbZrcHnIvP+5VmIEmXkdTtb4cvTFJMkDWxx7NrS8dI/Rh
76hoCStleuLpw8+zwIYC4QdJfFWBaQyw8w0nON/qp4E+kyU8E3syMsjqFOqclSeU
vFDTvgl4/Z0nPxTl+IBzG0cBPMjUXgmvGZj4NAhZhE5nNwkA34GvmMcfjVhy8ROX
WWwgiFBP20Po7p3aHz57KA4UTkgIZfhK4BRbb4BhQoaYEcXL8Sata/SJOR3RT2vQ
8uB8H8orPpugdafS4wLv/qcwYn6pa2ubEQG59WfihIomDWh4jl+i+kfnM5fYwX+F
AgwDC9FRLmchgYQBEAC4bp8seECcmzLFnRZsABQI/TJg7jKDEZuudEiEGmKUhhOf
Mz1pQEEHyh5aTFSJDVq2bNgPKt4NJ/bQL1QOq1lnsprpAAL6+HoyezA6ygfh6YmW
8kJOwJrVXlgo+H3XD4XeoA7VFVdcHkszFYgq4KCd8KX+haSkt0Wbj0s7sQkKQo/j
PUUQN34pxfyJ0IiqlKuLgpu7ggMJkDqZGoYnXH91Qt9TYi/liMMx4wo82YOQFH0d
xJUewsVvUpjwmFotOBKdhk+zZlOoNNr7QnyZ2SRyXNUFI66fsw5QsbwDSXJ4Hy8C
3RVRZ7baxw2p5wMyZQBtMyqu9quS/XED0cZA+sxvKOTrC24YbD+nb1ktc/9ZJghH
TZjhQLLhmrbHPNnrHIrnEJ6XrxbgNHWTFE+yX/e2lRIRGwz0cfgbY2pLFJ+6uhSu
PkodKyq/PCerYZPnUMjnLxogNtgZhf6jK4AzG2xuFZne37NBEaXY3q1ktwafpRia
1UrO4PC2cwJpNuIpMfHbA8xieppwRZbqBSSAM80V12963cFakUxLmZdMG0ApFTDU
5NoAxwBaRooHjTgYwdfgtjikwsPOf/VFWrB2IkBqF/QhxdV2sxasmJCM04e1gidi
0prCX7KoMNtBnHpubfwV7sTNdhN15IKmyHNLw9hXfZZmN9UAh6LxUS/KHMZSv9Je
AR+Ty00mCszxvBco6ee6Tv7gEhBU2ZBhu4yyWZC5Kd0pNvr4ZtCGNNY5wIjv00jd
nNnMW7MrEF4Tz/So+1TJHiLLFuap2RpXifCHRiXDMHqOUuFUgGFSNNlhYXycXQ==
=lDR9
hQIMAwDh3VI7VctTAQ//RZDgcJwORDcdCgh90HAw+3x/ltfi2O4IeEciyaimNd2G
SJKV9y2VGwCFwrDfdlBuy8NDHSnE2oM/Cdk7sv7MTZpuDpofj/41qYVA55PVyh0n
oWkXfsNCXx/2mJizPddPDf51bKlEkeG+NrbJym+nWQqPH9Ty+y5QmSDUrSUoir8G
bnbS/9O69P8MSsGAL23sLuRr7rnFXVjZkovlsxY+c86Eob34EgY9iryzFHXnQZIA
4JqNL9MIygxn1HA8JCBl/zUJOvEO1QBANYFb78pMr4juDFn6n0iU1TeDwMB8j4DB
/Wn648EvvR4bt2UR3KCCcG6lJKM/weCd1PEjW3adKIn/D+sUI0gEY8OuEQ0qVhDp
w0FUDPa3SI4Tv+RxAbZ4tsVwnK+NDK9ZJ6bb6aSox7By5aCEKQem9YztCl4NclOr
arFNC9rNdJVfl6ed3RY1T8pySfpbfWGboQbsAKr/kUoFKPAdOD8dk+IDPnatJHg9
S5XoVv/XrB4G+G6ubsQ2hIOh27cnVo8L3Nydtxs1L2Abw2zK0/a/zQLABGxDsSQy
UxAi2yJbgcLVmTNssjlTFDPfl0cTUYeH+eitDedLjdgcymFFZYXOaXpoJywaaXHv
CC0dF4M3Nx1iz6iJLeP5AwaRDliXVi/f/Imrk2S6Re0dlgJu61ExvCgPUnNl1suF
AgwDC9FRLmchgYQBD/0QZwJI6czuYVOarwVttQxZGUaiwXnZaFYuENqoJWyDd3hV
dCcy39pM0Ant4khELdSS7qw+47aWAnk1mjMLUIEv+VuA3820p6Y/luBHJZMcaGm8
ZDKt8Hamgxevrc68TODacNOu75hq5zKm3w9WLpXc7W/b6+BBcMbq6tTahtvWpEnG
x9cSjpW27PeEnE4dM+Q3gzugL9WaXhGg81+Q3s/wOj5nnJ0ydcK0dfV7sk9ciDrE
91Or/FtIgDFFEP5VdGI2SFApbBiSSA3/kE5EPf3vVd05TDFh0muVkbl2TnfwXRwx
ktBwlLZaFxuNH1jZqj9i3Nt6VT+zDXtGk4s0cuVUN1bHfOZdYN2f1Eim9ewYwwKi
iZ9VX+3kznLuY/TbJEO82hnk10uYO45SoQd+4J4h18Sxn7+lVoIxJgEfoafllOPr
YcMeD7bteqNePjGGB6HueZ7iUnHWfceHiaIcfOq4nL6c5nQcorrYmcIKMy2Snq6z
eS9aiNQvBM6ogJBbdhIqxQCydH5hA71VoBA4ljZj1p/FkQ91ZizOoSfCGuOmkCTf
Stv9lRcBV2Fmy1CEwUHbYlZIV7UkZ9ElbV6aF8gyfUvDOhiVmsZAluzvIA0EVYB9
L8iyH6qzVgyBPJ0AgAjNEUmRbWH/mx1X4pFRkPCQ4hoVQxoZhN6BDj6xKvBVuNJe
AVpL/bfor37Yenx/YBdYsY5ALb6u32vC3Hk2n5bt6fb1BNwi/Trvrv8vLDEAFvRl
cUQCj67vh6Wg1LkzGAxuQ5BTE54Mxndjt/PLmOhxBGl+gCBwxKZ0QtuqiH9tIw==
=uBYL
-----END PGP MESSAGE-----
fp: 4BE7925262289B476DBBC17B76FD3810215AE097
unencrypted_suffix: _unencrypted