Compare commits
No commits in common. "797f8d032dcaa429d2856cddbe0213df6473581b" and "7f52ad42cd5a11d67eb13d41f6edb8813f549423" have entirely different histories.
797f8d032d
...
7f52ad42cd
17 changed files with 73 additions and 341 deletions
|
@ -13,19 +13,5 @@
|
||||||
true-color = true; # to make colors coherent when in ssh
|
true-color = true; # to make colors coherent when in ssh
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
languages = {
|
|
||||||
language = [
|
|
||||||
{
|
|
||||||
name = "nix";
|
|
||||||
language-servers = ["nixd"];
|
|
||||||
}
|
|
||||||
];
|
|
||||||
language-servers = [
|
|
||||||
{
|
|
||||||
name = "nixd";
|
|
||||||
command = "nixd";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -182,7 +182,6 @@
|
||||||
# "matrix-registration-shared-secret".owner = "matrix-synapse";
|
# "matrix-registration-shared-secret".owner = "matrix-synapse";
|
||||||
# "matrix-sliding-sync-secret".owner = "matrix-synapse";
|
# "matrix-sliding-sync-secret".owner = "matrix-synapse";
|
||||||
"autistici-password".owner = "forgejo";
|
"autistici-password".owner = "forgejo";
|
||||||
"garmin-collector-environment".owner = "garmin-collector";
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -42,7 +42,6 @@
|
||||||
"adb"
|
"adb"
|
||||||
"guix"
|
"guix"
|
||||||
"prometheus-exporters"
|
"prometheus-exporters"
|
||||||
"promtail"
|
|
||||||
]
|
]
|
||||||
++ [
|
++ [
|
||||||
./disko.nix
|
./disko.nix
|
||||||
|
|
|
@ -34,9 +34,6 @@
|
||||||
"prometheus-exporters"
|
"prometheus-exporters"
|
||||||
"loki"
|
"loki"
|
||||||
"promtail"
|
"promtail"
|
||||||
"garmin-collector"
|
|
||||||
"restic"
|
|
||||||
# "immich"
|
|
||||||
]
|
]
|
||||||
++ [
|
++ [
|
||||||
./disko.nix
|
./disko.nix
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
{
|
|
||||||
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"
|
|
||||||
];
|
|
||||||
}
|
|
|
@ -1,14 +1,9 @@
|
||||||
{
|
{
|
||||||
config,
|
config,
|
||||||
pkgs,
|
pkgs,
|
||||||
lib,
|
|
||||||
...
|
...
|
||||||
}: let
|
}: {
|
||||||
hostname = config.networking.hostName;
|
services.prometheus.exporters.node = {
|
||||||
mkFor = hosts: lib.mkIf (builtins.elem hostname hosts);
|
|
||||||
in {
|
|
||||||
services.prometheus.exporters = {
|
|
||||||
node = mkFor ["sisko" "picard"] {
|
|
||||||
enable = true;
|
enable = true;
|
||||||
enabledCollectors = [
|
enabledCollectors = [
|
||||||
"cpu"
|
"cpu"
|
||||||
|
@ -34,23 +29,4 @@ in {
|
||||||
];
|
];
|
||||||
extraFlags = ["--collector.ethtool" "--collector.softirqs" "--collector.tcpstat" "--collector.wifi"];
|
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;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,12 +3,6 @@
|
||||||
in {
|
in {
|
||||||
services.prometheus = {
|
services.prometheus = {
|
||||||
enable = true;
|
enable = true;
|
||||||
pushgateway = {
|
|
||||||
enable = true;
|
|
||||||
web = {
|
|
||||||
listen-address = "sisko.fleet:9094";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
checkConfig = false; # Otherwise it will fail because it cannot access bearer_token_file
|
checkConfig = false; # Otherwise it will fail because it cannot access bearer_token_file
|
||||||
webExternalUrl = "https://status.aciceri.dev";
|
webExternalUrl = "https://status.aciceri.dev";
|
||||||
globalConfig.scrape_interval = "10s";
|
globalConfig.scrape_interval = "10s";
|
||||||
|
@ -23,14 +17,6 @@ in {
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
{
|
|
||||||
job_name = "pushgateway";
|
|
||||||
static_configs = [
|
|
||||||
{
|
|
||||||
targets = [cfg.pushgateway.web.listen-address];
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
{
|
{
|
||||||
job_name = "node";
|
job_name = "node";
|
||||||
static_configs = [
|
static_configs = [
|
||||||
|
@ -39,54 +25,6 @@ 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 = [
|
environment.persistence."/persist".directories = [
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
};
|
};
|
||||||
clients = [
|
clients = [
|
||||||
{
|
{
|
||||||
url = "http://sisko.fleet:${builtins.toString config.services.loki.configuration.server.http_listen_port or 3100}/loki/api/v1/push";
|
url = "http://sisko.fleet:${builtins.toString config.services.loki.configuration.server.http_listen_port}/loki/api/v1/push";
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
positions = {
|
positions = {
|
||||||
|
|
0
modules/promtail/protmail.yaml
Normal file
0
modules/promtail/protmail.yaml
Normal file
|
@ -3,33 +3,43 @@
|
||||||
pkgs,
|
pkgs,
|
||||||
lib,
|
lib,
|
||||||
...
|
...
|
||||||
}: let
|
}: {
|
||||||
user = "u382036-sub1";
|
options.backup = {
|
||||||
host = "u382036.your-storagebox.de";
|
paths = lib.mkOption {
|
||||||
port = "23";
|
type = lib.types.listOf lib.types.path;
|
||||||
in {
|
default = [];
|
||||||
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 = {
|
||||||
services.openssh.knownHosts."${host}".publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIICf9svRenC/PLKIL9nk6K/pxQgoiFC41wTNvoIncOxs";
|
backups = {
|
||||||
|
hetzner = {
|
||||||
services.restic.backups.sisko = {
|
paths = config.backup.paths;
|
||||||
paths = ["/persist"];
|
passwordFile = config.age.secrets.restic-hetzner-password.path;
|
||||||
passwordFile = config.age.secrets.SISKO_RESTIC_PASSWORD.path;
|
|
||||||
extraOptions = [
|
extraOptions = [
|
||||||
"sftp.command='${lib.getExe pkgs.sshpass} -f ${config.age.secrets.HETZNER_STORAGE_BOX_SISKO_SSH_PASSWORD.path} ssh -p${port} ${user}@${host} -s sftp'"
|
# 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'"
|
||||||
];
|
];
|
||||||
repository = "sftp://${user}@${host}:${port}/";
|
repository = "sftp://u382036-sub1@u382036-sub1.your-storagebox.de:23/";
|
||||||
initialize = true;
|
initialize = true;
|
||||||
timerConfig.OnCalendar = "daily";
|
timerConfig.OnCalendar = "daily";
|
||||||
timerConfig.RandomizedDelaySec = "1h";
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,17 +35,17 @@
|
||||||
proxyPass = "http://localhost:${builtins.toString config.services.invidious.port}";
|
proxyPass = "http://localhost:${builtins.toString config.services.invidious.port}";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
# "photos.aciceri.dev" = {
|
"photos.aciceri.dev" = {
|
||||||
# extraConfig = ''
|
extraConfig = ''
|
||||||
# client_max_body_size 50000M;
|
client_max_body_size 50000M;
|
||||||
# '';
|
'';
|
||||||
# forceSSL = true;
|
forceSSL = true;
|
||||||
# enableACME = true;
|
enableACME = true;
|
||||||
# locations."/" = {
|
locations."/" = {
|
||||||
# proxyPass = "http://localhost:2283";
|
proxyPass = "http://localhost:2283";
|
||||||
# proxyWebsockets = true;
|
proxyWebsockets = true;
|
||||||
# };
|
};
|
||||||
# };
|
};
|
||||||
|
|
||||||
# "jellyfin.aciceri.dev" = {
|
# "jellyfin.aciceri.dev" = {
|
||||||
# forceSSL = true;
|
# forceSSL = true;
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
{
|
|
||||||
writers,
|
|
||||||
python3Packages,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
writers.writePython3Bin "garmin-collector" {
|
|
||||||
libraries = with python3Packages; [
|
|
||||||
prometheus-client
|
|
||||||
garminconnect
|
|
||||||
];
|
|
||||||
flakeIgnore = ["E501"];
|
|
||||||
} (builtins.readFile ./garmin-collector.py)
|
|
|
@ -1,82 +0,0 @@
|
||||||
# !/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.
|
@ -27,9 +27,6 @@ in
|
||||||
"matrix-sliding-sync-secret.age".publicKeys = [ccr-ssh ccr-gpg sisko];
|
"matrix-sliding-sync-secret.age".publicKeys = [ccr-ssh ccr-gpg sisko];
|
||||||
"forgejo-runners-token.age".publicKeys = [ccr-ssh ccr-gpg picard];
|
"forgejo-runners-token.age".publicKeys = [ccr-ssh ccr-gpg picard];
|
||||||
"forgejo-nix-access-tokens.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
|
# WireGuard
|
||||||
"picard-wireguard-private-key.age".publicKeys = [ccr-ssh ccr-gpg picard];
|
"picard-wireguard-private-key.age".publicKeys = [ccr-ssh ccr-gpg picard];
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
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ó•²
|
|
||||||
yÃdæO<>SaÐ)avŠëâGœÎ÷ჳMXü%OÍ=¶Ü`~$ ªÁù
|
|
Loading…
Add table
Add a link
Reference in a new issue