Compare commits

..

9 commits

Author SHA1 Message Date
aa2ca55059 flake.lock: Update
All checks were successful
/ test (push) Successful in 54s
Flake lock file updates:

• Updated input 'disko':
    'github:nix-community/disko/786965e1b1ed3fd2018d78399984f461e2a44689' (2024-07-11)
  → 'github:nix-community/disko/1e6f8a7b4634fc051cc9361959bf414fcf17e094' (2024-07-29)
• Updated input 'dream2nix':
    'github:nix-community/dream2nix/0c6b5c8ab796f6dfb2aef1133f5b7bb25ce57cb9' (2024-07-10)
  → 'github:nix-community/dream2nix/736f7ac951078454e5b8b2a96e5f905210fcd635' (2024-07-29)
• Updated input 'homeManager':
    'github:nix-community/home-manager/c085b984ff2808bf322f375b10fea5a415a9c43d' (2024-07-10)
  → 'github:nix-community/home-manager/792757f643cedc13f02098d8ed506d82e19ec1da' (2024-07-28)
• Updated input 'lix':
    'git+https://git@git.lix.systems/lix-project/lix?ref=refs/heads/main&rev=014410cbf0bda9c0fcdaf5f894120883cdc805ce' (2024-07-10)
  → 'git+https://git@git.lix.systems/lix-project/lix?ref=refs/heads/main&rev=6abad7cb238c5c7bf59a83bed55e7590c544fc2e' (2024-07-26)
• Updated input 'lix-module':
    'git+https://git.lix.systems/lix-project/nixos-module?ref=refs/heads/main&rev=5d9d94089fb1ca96222a34bfe245ef5c5ebefd37' (2024-06-25)
  → 'git+https://git.lix.systems/lix-project/nixos-module?ref=refs/heads/main&rev=d70318fb946a0e720dfdd1fb10b0645c14e2a02a' (2024-07-11)
• Updated input 'mobile-nixos':
    'github:NixOS/mobile-nixos/31704f8a55f5773c9b4e7adb7408a142d142e1f2' (2024-07-11)
  → 'github:NixOS/mobile-nixos/717ce90cfadffa449480bae2e155185c651e9993' (2024-07-27)
• Updated input 'nix-on-droid':
    'github:nix-community/nix-on-droid/8bcadcef69dcb5ca177bfb6ea3dc6b092cda2b06' (2024-07-10)
  → 'github:nix-community/nix-on-droid/248cc0806120fac9214f503dee0eaf0f47740dd0' (2024-07-22)
• Updated input 'nix-on-droid/nix-formatter-pack/nmd':
    'gitlab:rycee/nmd/b75d312b4f33bd3294cd8ae5c2ca8c6da2afc169' (2022-10-19)
  → follows 'nix-on-droid/nmd'
• Updated input 'nixDarwin':
    'github:LnL7/nix-darwin/cf297a8d248db6a455b60133f6c0029c04ebe50e' (2024-07-10)
  → 'github:LnL7/nix-darwin/0413754b3cdb879ba14f6e96915e5fdf06c6aab6' (2024-07-27)
• Updated input 'nixd':
    'github:nix-community/nixd/60a925008bc353136ba5babce437f42819c1645c' (2024-06-26)
  → 'github:nix-community/nixd/4c306e7e2694a02a99fe53a62a1bf607d0137531' (2024-07-26)
• Updated input 'nixosHardware':
    'github:NixOS/nixos-hardware/a111ce6b537df12a39874aa9672caa87f8677eda' (2024-07-09)
  → 'github:NixOS/nixos-hardware/e67b60fb1b2c3aad2202d95b91d4c218cf2a4fdd' (2024-07-27)
• Updated input 'nixpkgsStable':
    'github:NixOS/nixpkgs/7144d6241f02d171d25fba3edeaf15e0f2592105' (2024-07-02)
  → 'github:NixOS/nixpkgs/205fd4226592cc83fd4c0885a3e4c9c400efabb5' (2024-07-09)
• Updated input 'pre-commit-hooks':
    'github:cachix/pre-commit-hooks.nix/8d6a17d0cdf411c55f12602624df6368ad86fac1' (2024-07-09)
  → 'github:cachix/pre-commit-hooks.nix/f451c19376071a90d8c58ab1a953c6e9840527fd' (2024-07-15)
• Updated input 'treefmt-nix':
    'github:numtide/treefmt-nix/750dfb555b5abdab4d3266b3f9a05dec6d205c04' (2024-07-10)
  → 'github:numtide/treefmt-nix/8db8970be1fb8be9c845af7ebec53b699fe7e009' (2024-07-23)
2024-07-29 07:24:12 +00:00
797f8d032d
Enable garmin-collector on sisko
All checks were successful
/ test (push) Successful in 1m33s
2024-07-25 16:44:56 +02:00
dbb15d07ed
Enable promtail on picard 2024-07-25 16:44:37 +02:00
a39a314e4c
Prometheus pushgateway 2024-07-25 16:44:28 +02:00
2871c291bf
Promtail 2024-07-25 16:44:14 +02:00
71a3654e9a
Restic for sisko 2024-07-25 16:43:58 +02:00
865274a2df
Disable photos.aciceri.dev DNS 2024-07-25 16:43:11 +02:00
ff789db499
garmin-collector 2024-07-25 16:43:01 +02:00
a9697956e4
Helix nixd LSP 2024-07-25 16:41:38 +02:00
18 changed files with 366 additions and 98 deletions

50
flake.lock generated
View file

@ -104,11 +104,11 @@
]
},
"locked": {
"lastModified": 1721871128,
"narHash": "sha256-NyWVCnSeePnJHGJxZ0l3zdGQGrVjUcx2IJbV8KIsPf0=",
"lastModified": 1722217815,
"narHash": "sha256-8r5AJ3n8WEDw3rsZLALSuFQ5kJyWOcssNZvPxYLr2yc=",
"owner": "nix-community",
"repo": "disko",
"rev": "55e874b9c14764cb791e5740f0e92202e41393fc",
"rev": "1e6f8a7b4634fc051cc9361959bf414fcf17e094",
"type": "github"
},
"original": {
@ -124,11 +124,11 @@
"pyproject-nix": "pyproject-nix"
},
"locked": {
"lastModified": 1721736218,
"narHash": "sha256-+sSmaBrN+pJbaz9oJttVg+XCb4LVHDlEX/vMl/rpDgE=",
"lastModified": 1722235740,
"narHash": "sha256-O4Y1XRd4en+GWyU0NvwBBLB4sdt5btoK9oiPqCmtIIs=",
"owner": "nix-community",
"repo": "dream2nix",
"rev": "959d6f96784cf5fc53024e5c3c362f0a2a347b45",
"rev": "736f7ac951078454e5b8b2a96e5f905210fcd635",
"type": "github"
},
"original": {
@ -818,11 +818,11 @@
]
},
"locked": {
"lastModified": 1721852138,
"narHash": "sha256-JH8N5uoqoVA6erV4O40VtKKHsnfmhvMGbxMNDLtim5o=",
"lastModified": 1722203588,
"narHash": "sha256-91V5FMSQ4z9bkhTCf0f86Zjw0bh367daSf0mzCIW0vU=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "304a011325b7ac7b8c9950333cd215a7aa146b0e",
"rev": "792757f643cedc13f02098d8ed506d82e19ec1da",
"type": "github"
},
"original": {
@ -887,11 +887,11 @@
"lix": {
"flake": false,
"locked": {
"lastModified": 1721841700,
"narHash": "sha256-5aO0cXENUI/38xsG0ww0QSsVSlkvMvKfxbeYXYH08Es=",
"lastModified": 1721992157,
"narHash": "sha256-D5bBsSKvYmVn8U4lhrvMemko7m2I/sicjyAYEWDfW9A=",
"ref": "refs/heads/main",
"rev": "8d12e0fbb7306cbc58b12ef051d7067d703738de",
"revCount": 16014,
"rev": "6abad7cb238c5c7bf59a83bed55e7590c544fc2e",
"revCount": 16027,
"type": "git",
"url": "https://git@git.lix.systems/lix-project/lix"
},
@ -928,11 +928,11 @@
"mobile-nixos": {
"flake": false,
"locked": {
"lastModified": 1721250279,
"narHash": "sha256-S47+MFnArDvR7OFCXU0BQoyLCBwSZws+t+bany7Ol6w=",
"lastModified": 1722056346,
"narHash": "sha256-50fcuCppaLMfSOTFO4IkCBs4folToCwlhTgc6IdZFHg=",
"owner": "NixOS",
"repo": "mobile-nixos",
"rev": "472073a51745cca03257cf625582252cdd04ec21",
"rev": "717ce90cfadffa449480bae2e155185c651e9993",
"type": "github"
},
"original": {
@ -1019,11 +1019,11 @@
]
},
"locked": {
"lastModified": 1721719500,
"narHash": "sha256-nnkqjv4Y37Hydjh6HE9wW4kSkV5Q7q4iIXlL5lwUFOw=",
"lastModified": 1722082646,
"narHash": "sha256-od8dBWVP/ngg0cuoyEl/w9D+TCNDj6Kh4tr151Aax7w=",
"owner": "LnL7",
"repo": "nix-darwin",
"rev": "884f3fe6d9bf056ba0017c132c39c1f0d07d4fec",
"rev": "0413754b3cdb879ba14f6e96915e5fdf06c6aab6",
"type": "github"
},
"original": {
@ -1063,11 +1063,11 @@
"nixpkgs": "nixpkgs_10"
},
"locked": {
"lastModified": 1721713478,
"narHash": "sha256-4DYCQGmsXaa90+hkNs/vH2XtPXEevCT9VRIM/HCbhiQ=",
"lastModified": 1721956722,
"narHash": "sha256-EYYob7/Z3RKJAp9HcOMPXwvmXHjXIlmd/1eKHGKWnKI=",
"owner": "nix-community",
"repo": "nixd",
"rev": "86dc0ba9f59e4d87969e5e9bd826c586994a6474",
"rev": "4c306e7e2694a02a99fe53a62a1bf607d0137531",
"type": "github"
},
"original": {
@ -1078,11 +1078,11 @@
},
"nixosHardware": {
"locked": {
"lastModified": 1721911538,
"narHash": "sha256-5OrkPJsiZmNe99C6+KX0qx9sphoVLvldFjuqDYAZ8GQ=",
"lastModified": 1722114937,
"narHash": "sha256-MOZ9woPwdpFJcHx3wic2Mlw9aztdKjMnFT3FaeLzJkM=",
"owner": "NixOS",
"repo": "nixos-hardware",
"rev": "d3c993c851ad40bbab7e08d566138ff72cd8744f",
"rev": "e67b60fb1b2c3aad2202d95b91d4c218cf2a4fdd",
"type": "github"
},
"original": {

View file

@ -13,5 +13,19 @@
true-color = true; # to make colors coherent when in ssh
};
};
languages = {
language = [
{
name = "nix";
language-servers = ["nixd"];
}
];
language-servers = [
{
name = "nixd";
command = "nixd";
}
];
};
};
}

View file

@ -182,6 +182,7 @@
# "matrix-registration-shared-secret".owner = "matrix-synapse";
# "matrix-sliding-sync-secret".owner = "matrix-synapse";
"autistici-password".owner = "forgejo";
"garmin-collector-environment".owner = "garmin-collector";
};
};
};

View file

@ -42,6 +42,7 @@
"adb"
"guix"
"prometheus-exporters"
"promtail"
]
++ [
./disko.nix

View file

@ -34,6 +34,9 @@
"prometheus-exporters"
"loki"
"promtail"
"garmin-collector"
"restic"
# "immich"
]
++ [
./disko.nix

View file

@ -0,0 +1,46 @@
{
pkgs,
lib,
fleetFlake,
config,
...
}: {
users.users.garmin-collector = {
isSystemUser = true;
group = "garmin-collector";
extraGroups = ["garmin-collector"];
home = "/var/lib/garmin-collector";
};
users.groups.garmin-collector = {};
systemd.services.garmin-collector = {
description = "Garmin collector pushing to Prometheus Pushgateway";
wantedBy = ["multi-user.target"];
environment = {
PUSHGATEWAY_ADDRESS = config.services.prometheus.pushgateway.web.listen-address;
};
serviceConfig = {
Group = "garmin-collector";
User = "garmin-collector";
WorkingDirectory = "/var/lib/garmin-collector";
ExecStart = ''
${lib.getExe fleetFlake.packages.${pkgs.system}.garmin-collector}
'';
EnvironmentFile = config.age.secrets.garmin-collector-environment.path;
};
};
systemd.timers."garmin-collector" = {
wantedBy = ["timers.target"];
timerConfig = {
OnBootSec = "5m";
OnUnitActiveSec = "4h";
Unit = "garmin-collector.service";
};
};
environment.persistence."/persist".directories = [
"/var/lib/garmin-collector"
];
}

View file

@ -1,9 +1,14 @@
{
config,
pkgs,
lib,
...
}: {
services.prometheus.exporters.node = {
}: let
hostname = config.networking.hostName;
mkFor = hosts: lib.mkIf (builtins.elem hostname hosts);
in {
services.prometheus.exporters = {
node = mkFor ["sisko" "picard"] {
enable = true;
enabledCollectors = [
"cpu"
@ -29,4 +34,23 @@
];
extraFlags = ["--collector.ethtool" "--collector.softirqs" "--collector.tcpstat" "--collector.wifi"];
};
wireguard = mkFor ["sisko" "picard"] {
enable = true;
};
zfs = mkFor ["picard"] {
enable = true;
};
# restic = mkFor ["sisko"] {
# enable = true;
# };
postgres = mkFor ["sisko"] {
enable = true;
};
nginx = mkFor ["sisko"] {
enable = true;
};
smartctl = mkFor ["sisko"] {
enable = true;
};
};
}

View file

@ -3,6 +3,12 @@
in {
services.prometheus = {
enable = true;
pushgateway = {
enable = true;
web = {
listen-address = "sisko.fleet:9094";
};
};
checkConfig = false; # Otherwise it will fail because it cannot access bearer_token_file
webExternalUrl = "https://status.aciceri.dev";
globalConfig.scrape_interval = "10s";
@ -17,6 +23,14 @@ in {
}
];
}
{
job_name = "pushgateway";
static_configs = [
{
targets = [cfg.pushgateway.web.listen-address];
}
];
}
{
job_name = "node";
static_configs = [
@ -25,6 +39,54 @@ in {
}
];
}
{
job_name = "wireguard";
static_configs = [
{
targets = builtins.map (host: "${host}.fleet:9586") ["picard"];
}
];
}
{
job_name = "zfs";
static_configs = [
{
targets = builtins.map (host: "${host}.fleet:9134") ["picard"];
}
];
}
{
job_name = "restic";
static_configs = [
{
targets = builtins.map (host: "${host}.fleet:9753") ["sisko"];
}
];
}
{
job_name = "postgres";
static_configs = [
{
targets = builtins.map (host: "${host}.fleet:9187") ["sisko"];
}
];
}
{
job_name = "nginx";
static_configs = [
{
targets = builtins.map (host: "${host}.fleet:9117") ["sisko"];
}
];
}
{
job_name = "smartctl";
static_configs = [
{
targets = builtins.map (host: "${host}.fleet:9633") ["sisko"];
}
];
}
];
};
environment.persistence."/persist".directories = [

View file

@ -11,7 +11,7 @@
};
clients = [
{
url = "http://sisko.fleet:${builtins.toString config.services.loki.configuration.server.http_listen_port}/loki/api/v1/push";
url = "http://sisko.fleet:${builtins.toString config.services.loki.configuration.server.http_listen_port or 3100}/loki/api/v1/push";
}
];
positions = {

View file

@ -3,43 +3,33 @@
pkgs,
lib,
...
}: {
options.backup = {
paths = lib.mkOption {
type = lib.types.listOf lib.types.path;
default = [];
}: let
user = "u382036-sub1";
host = "u382036.your-storagebox.de";
port = "23";
in {
age.secrets = {
HETZNER_STORAGE_BOX_SISKO_SSH_PASSWORD = {
file = ../../secrets/hetzner-storage-box-sisko-ssh-password.age;
owner = "root";
};
SISKO_RESTIC_PASSWORD = {
file = ../../secrets/sisko-restic-password.age;
owner = "root";
};
};
config.services.restic = {
backups = {
hetzner = {
paths = config.backup.paths;
passwordFile = config.age.secrets.restic-hetzner-password.path;
services.openssh.knownHosts."${host}".publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIICf9svRenC/PLKIL9nk6K/pxQgoiFC41wTNvoIncOxs";
services.restic.backups.sisko = {
paths = ["/persist"];
passwordFile = config.age.secrets.SISKO_RESTIC_PASSWORD.path;
extraOptions = [
# Use the host ssh key, for authorizing new hosts:
# cat /etc/ssh/ssh_host_ed25519_key.pub | ssh -p23 u382036-sub1@u382036-sub1.your-storagebox.de install-ssh-key
"sftp.command='ssh -p23 u382036-sub1@u382036-sub1.your-storagebox.de -i /etc/ssh/ssh_host_ed25519_key -s sftp'"
"sftp.command='${lib.getExe pkgs.sshpass} -f ${config.age.secrets.HETZNER_STORAGE_BOX_SISKO_SSH_PASSWORD.path} ssh -p${port} ${user}@${host} -s sftp'"
];
repository = "sftp://u382036-sub1@u382036-sub1.your-storagebox.de:23/";
repository = "sftp://${user}@${host}:${port}/";
initialize = true;
timerConfig.OnCalendar = "daily";
timerConfig.RandomizedDelaySec = "1h";
};
};
};
config.environment.systemPackages = builtins.map (path:
pkgs.writeShellApplication {
name = "restic-restore-${builtins.replaceStrings ["/"] ["-"] path}";
runtimeInputs = with pkgs; [restic];
text = ''
restic -r ${config.services.restic.backups.hetzner.repository} \
${lib.concatMapStringsSep ''\'' (option: "-o ${option}") config.services.restic.backups.hetzner.extraOptions} \
--password-file ${config.services.restic.backups.hetzner.passwordFile} \
restore latest \
--path "${path}"\
--target "$1"
'';
})
config.services.restic.backups.hetzner.paths;
}

View file

@ -35,17 +35,17 @@
proxyPass = "http://localhost:${builtins.toString config.services.invidious.port}";
};
};
"photos.aciceri.dev" = {
extraConfig = ''
client_max_body_size 50000M;
'';
forceSSL = true;
enableACME = true;
locations."/" = {
proxyPass = "http://localhost:2283";
proxyWebsockets = true;
};
};
# "photos.aciceri.dev" = {
# extraConfig = ''
# client_max_body_size 50000M;
# '';
# forceSSL = true;
# enableACME = true;
# locations."/" = {
# proxyPass = "http://localhost:2283";
# proxyWebsockets = true;
# };
# };
# "jellyfin.aciceri.dev" = {
# forceSSL = true;

View file

@ -0,0 +1,12 @@
{
writers,
python3Packages,
...
}:
writers.writePython3Bin "garmin-collector" {
libraries = with python3Packages; [
prometheus-client
garminconnect
];
flakeIgnore = ["E501"];
} (builtins.readFile ./garmin-collector.py)

View file

@ -0,0 +1,82 @@
# !/usr/bin/env python3
import datetime
import os
from garth.exc import GarthHTTPError
from garminconnect import (
Garmin,
GarminConnectAuthenticationError,
)
from prometheus_client import CollectorRegistry, push_to_gateway
from prometheus_client.core import GaugeMetricFamily
email = os.getenv("GARMIN_EMAIL")
password = os.getenv("GARMIN_PASSWORD")
tokenstore = os.getenv("GARMINTOKENS") or "~/.garminconnect"
tokenstore_base64 = os.getenv("GARMINTOKENS_BASE64") or "~/.garminconnect_base64"
gateway_address = os.getenv("PUSHGATEWAY_ADDRESS")
today = datetime.date.today()
def init_api(email=email, password=password):
"""Initialize Garmin API with your credentials."""
try:
print(
f"Trying to login to Garmin Connect using token data from directory '{tokenstore}'...\n"
)
garmin = Garmin()
garmin.login(tokenstore)
except (FileNotFoundError, GarthHTTPError, GarminConnectAuthenticationError):
# Session is expired. You'll need to log in again
print(
"Login tokens not present, login with your Garmin Connect credentials to generate them.\n"
f"They will be stored in '{tokenstore}' for future use.\n"
)
garmin = Garmin(email=email, password=password, is_cn=False)
garmin.login()
# Save Oauth1 and Oauth2 token files to directory for next login
garmin.garth.dump(tokenstore)
print(
f"Oauth tokens stored in '{tokenstore}' directory for future use. (first method)\n"
)
# Encode Oauth1 and Oauth2 tokens to base64 string and safe to file for next login (alternative way)
token_base64 = garmin.garth.dumps()
dir_path = os.path.expanduser(tokenstore_base64)
with open(dir_path, "w") as token_file:
token_file.write(token_base64)
print(
f"Oauth tokens encoded as base64 string and saved to '{dir_path}' file for future use. (second method)\n"
)
return garmin
class GarminCollector:
def __init__(self):
super().__init__()
self.api = init_api()
def collect(self):
try:
body = self.api.get_daily_weigh_ins(today.isoformat())["totalAverage"]
metric_gauge = GaugeMetricFamily("body_composition", "Body composition and weight", labels=["metric"])
for k in ["weight", "bmi", "bodyFat", "bodyWater", "boneMass", "muscleMass", "physiqueRating", "visceralFat"]:
metric_gauge.add_metric([k], body[k])
except Exception as e:
print(f"Something went wrong while fetching body composition data\n{e}")
yield metric_gauge
if __name__ == "__main__":
registry = CollectorRegistry()
registry.register(GarminCollector())
push_to_gateway(gateway_address, job='garmin', registry=registry)

Binary file not shown.

Binary file not shown.

View file

@ -27,6 +27,9 @@ in
"matrix-sliding-sync-secret.age".publicKeys = [ccr-ssh ccr-gpg sisko];
"forgejo-runners-token.age".publicKeys = [ccr-ssh ccr-gpg picard];
"forgejo-nix-access-tokens.age".publicKeys = [ccr-ssh ccr-gpg picard];
"garmin-collector-environment.age".publicKeys = [ccr-ssh ccr-gpg sisko];
"hetzner-storage-box-sisko-ssh-password.age".publicKeys = [ccr-ssh ccr-gpg sisko];
"sisko-restic-password.age".publicKeys = [ccr-ssh ccr-gpg sisko];
# WireGuard
"picard-wireguard-private-key.age".publicKeys = [ccr-ssh ccr-gpg picard];

View file

@ -0,0 +1,30 @@
age-encryption.org/v1
-> ssh-rsa /AagBw
TKW/pV8ANvSWay5wTsFhV0CDSqn/wZAzNRP0WgRzBJbsrFP2/YYkhRHFtwkMjeXm
qEJPeXYdpgT6+FXq3nfhTaK/AbeebBRWO7dgGfKBosJ6Mc+PMhephrQ+oH6/zbG5
l5QclAZ4NOfkD3f/nnqog13nKTijHjHcTnEWYZZz8RowaUEkEjo4Xbgw1MUbC8yJ
khyqZOTVFnfKgcSW5rlnsbrZKkmwYYY8mej27I9AFeSLgE0DOF3OWxrNxuPdxICp
h/kfQ2lPw75TWX5vj8WKOOxjAvheIiJDAAdfOoroK1BqKAUmpC6HjpC3cJZhrMmE
Xtob+esC39M8QBO1vUB639/I0AKAMbn3rE617StUr2QyyyNahnOOOPaZplCk/uM8
Sde8d+VwTuvJXosuxi7Z+lQbeyCg7WmRigRoSiL6+9HcdMtDMDRjtloVq1o+iHXc
5A99Eeq0D/rBVSDmXKkVpcwLfruWL1v061+K7PPnjKa2CjnoEjAZDfqeQI+OBLZP
zqJ1CcQUnujYEpyhy4YV1ZpLZYOt48osEhUvG/eFnfymeDeAVAts725uzboN3uX8
ETM5k0cW1ElSTL0BltRn8hRs8BSVXtKIucRXERomIwK+45ux8DHFS2NQlEHs2x1g
d4coPbCgMt7nBPYGnAUOYaWyw6dcaCAPNoVVIyUP1ps
-> ssh-rsa QHr3/A
GM2npxcLnNk81fSJUW9tcDnaKcx42cuxaObl8oCB43GIFm7K5L89FHj4Ww9RUJy0
V41RQ802OBgudJqOI63DcW7mZ905fqLTnKZ75EJJSGgqjY0EcCOc2Oy8kV/BidWP
scmDbd+mQ1INuZBr9GBkD1brESh4vHtByPD6wkFKXlVkVTL49EQt8uBw8/0+uF0B
5a1aRQ09IkVPjluDMy2fc4VpgvkdnuXsMRD8vPk6gGzVlii72htGwYYWtIP9CgpY
trp85RxVGuqUTULFBOGXcc7YjfE1DWkPoeokCL8m7aVzdasZl+cl/Ick6rJueuQI
5ESvYKqRTfZ+oA8MapNtAZ7Nl8CT8VJoRyI6IQvPynRXCBK9D6gEAWc5l6Kv15Fl
73c8Q5I2oIaLOfeMYcZ1bL5Zvspa6Rsb5BtvOuOkacxx7GjMar1G2tUY4W3vFqn9
yf8/Uc61LU6BYVvFh6DI6TwHp6xp/DrWZYhXCvNfirMn1NSw+8q0EEcIr2sUdkbx
gf2onMjtRP/Mki0oqkMTXnIsCzL/Y7D13GdouVqz0Ttbg/BEa8RnSaJxDIwQ1Wlz
VCC+oK/jTr+0pfP+3iR75WuGC0ce+muEN/L29H6wFk4N2oar/r0BYZZ6BtV9I9kS
8xnIxKvrcJ4O5dYy4f/lMeTRlPp6pz1jjtb6AVcNzHE
-> ssh-ed25519 +vdRnA qQe9nesjyr3dCtSa7xfgsw1RjKx5UGTzg+/XrcDzl0A
912JZmwcsvsg2D8G9LakTfOa70hCkk4DALZP1fKcw2A
--- GzPDMAdvn0Gvp+gqVd/1EKvMPtqPhIjpVYRDAcvhwaU
Ș xó•²
O<>SaÐ)avŠëâGœÎ÷ჳMXü %OÍ=¶Ü`~$ ªÁù