This commit is contained in:
Lucy Hochkamp 2025-11-21 13:32:44 +01:00
parent 2614910b6f
commit 4667974392
13 changed files with 313 additions and 415 deletions

View file

@ -24,13 +24,14 @@ let
UNTIL="1d"
EVENT="$(
khal list "$SINCE" "$UNTIL" \
(khal list "$SINCE" "$UNTIL" \
--day-format 'SKIPME' \
--format "{start-end-time-style} {title:.31}{repeat-symbol}" |
grep -v SKIPME | # filter out headers
grep -v -P '| |' | # filter out continuing all day events
grep -v '^ ' | # exclude full-day events
head -n 1 # show just the first
) || echo ""
)"
if [ -z "$EVENT" ]; then

View file

@ -23,8 +23,9 @@
./presets/gui.nix
./presets/home-manager.nix
./presets/server.nix
./services/authentik
./services/caddy
# ./services/authentik
# ./services/caddy
./services/traefik.nix
./services/monitoring.nix
./services/wireguard.nix
./system/impermanence.nix

View file

@ -1,5 +1,6 @@
{
config,
inputs,
lib,
pkgs,
...
@ -44,6 +45,11 @@ in
LC_COLLATE = "de_DE.UTF-8";
};
nix.channel.enable = false;
nix.nixPath = [
"nixpkgs=${inputs.nixpkgs}"
"nixpkgs-master=${inputs.nixpkgs-master}"
];
nix.settings = {
substituters = [
# "https://cache.lix.systems"
@ -55,6 +61,7 @@ in
# "cache.lix.systems:aBnZUw8zA7H35Cz2RyKFVs3H4PlGTLawyY5KRbvJR8o="
# "helix.cachix.org-1:ejp9KQpR1FBI2onstMQ34yogDm4OgU2ru6lIwPvuCVs="
];
trusted-users = lib.mkDefault [
"root"
"@wheel"

View file

@ -7,71 +7,16 @@
with lib;
let
cfg = config.xyno.services.caddy;
wildcardMatcherStr = wildcard: hostName: content: ''
@${hostName} host ${hostName}.${wildcard}
handle @${hostName} {
${content.extraConfig}
}
'';
genOneWildcard = wildcard: host: {
extraConfig = ''
# extra pre
${host.extraConfigPre}
# block bots
${optionalString host.blockBots "import blockBots"}
# hosts handler
${concatStrings (mapAttrsToList (n: v: wildcardMatcherStr wildcard n v) host.hosts)}
# extra post
${host.extraConfigPost}
abort
'';
schema = import ./json-schema.nix {
inherit pkgs lib;
schema = builtins.fromJSON (builtins.readFile ./caddy_schema.json);
};
genVHostsFromWildcard = mapAttrs' (
n: v: nameValuePair "*.${n}" (genOneWildcard n v)
) cfg.wildcardHosts;
schema = import ./json-schema.nix { inherit pkgs lib; schema = builtins.fromJSON (builtins.readFile ./caddy_schema.json); };
in
{
options.xyno.services.caddy.enable = mkEnableOption "enables caddy with the desec plugin";
options.xyno.services.caddy.config = mkOption {
default = {};
type = schema.type;
};
options.xyno.services.caddy.wildcardHosts = mkOption {
example = {
"hailsatan.eu" = {
blockBots = true;
hosts.md.extraConfig = ''reverse_proxy ...'';
};
};
default = { };
type =
with types;
attrsOf (submodule {
options = {
blockBots = mkOption {
type = bool;
default = false;
};
extraConfigPre = mkOption {
type = str;
default = "";
};
extraConfigPost = mkOption {
type = str;
default = "";
};
hosts = mkOption {
default = {};
type = attrsOf (submodule {
options = {
extraConfig = mkOption { type = lines; };
};
});
};
};
});
type = schema.type;
};
config = lib.mkIf cfg.enable {
networking.firewall.allowedTCPPorts = [
@ -79,34 +24,32 @@ in
443
];
networking.firewall.allowedUDPPorts = [ 443 ];
xyno.services.caddy.config = {
apps = {
http.metrics.per_host = true;
tls.automation.policies = [
{
issuers = [
{
ca = "https://acme-v02.api.letsencrypt.org/directory";
challenges.dns.provider = {
name = "desec";
token.path = ""; # TODO
};
}
];
module = "acme";
}
];
};
};
services.caddy = {
enable = true;
package = pkgs.caddy-desec;
adapter = "json";
configFile = json.generate "caddy-config.json" cfg.config;
# virtualHosts = genVHostsFromWildcard;
# email = mkDefault "ssl@xyno.systems";
# acmeCA = mkDefault "https://acme-v02.api.letsencrypt.org/directory";
# globalConfig = ''
# metrics {
# per_host
# }
# '';
# extraConfig = ''
# (blockBots) {
# @botForbidden header_regexp User-Agent "(?i)AdsBot-Google|Amazonbot|anthropic-ai|Applebot|Applebot-Extended|AwarioRssBot|AwarioSmartBot|Bytespider|CCBot|ChatGPT|ChatGPT-User|Claude-Web|ClaudeBot|cohere-ai|DataForSeoBot|Diffbot|FacebookBot|Google-Extended|GPTBot|ImagesiftBot|magpie-crawler|omgili|Omgilibot|peer39_crawler|PerplexityBot|YouBot"
# handle @botForbidden {
# redir https://hil-speed.hetzner.com/10GB.bin
# }
# handle /robots.txt {
# respond <<TXT
# User-Agent: *
# Disallow: /
# TXT 200
# }
# }
# '';
};
xyno.services.monitoring.exporters.caddy = 2019;

View file

@ -36,6 +36,11 @@ let
in
result;
deref = x: if x ? "$ref" then getRef x."$ref" else x;
fileSubmod = types.submodule {
options.path = mkOption {
type = types.pathWith { inStore = false; absolute = true; };
};
};
buildOptionType =
{
spec,
@ -43,7 +48,8 @@ let
...
}:
let
strType = if spec ? enum then types.enum spec.enum else types.str;
strType = if spec ? enum then types.enum spec.enum else (types.either types.str fileSubmod);
objType = types.submodule {
freeformType = json.type;
options = submoduleOptions { inherit spec depth; };

View file

@ -9,9 +9,13 @@ with lib;
let
cfg = config.xyno.services.monitoring;
firstInstanceWithPromServer = if cfg.prometheusServer then config.networking.hostName else (builtins.head (
attrValues (filterAttrs (n: v: v.config.xyno.services.monitoring.prometheusServer) (otherNodes))
)).config.networking.hostName;
firstInstanceWithPromServer =
if cfg.prometheusServer then
config.networking.hostName
else
(builtins.head (
attrValues (filterAttrs (n: v: v.config.xyno.services.monitoring.prometheusServer) (otherNodes))
)).config.networking.hostName;
vmBasicAuthUsername = "xyno-monitoring";
in
{
@ -84,7 +88,9 @@ in
];
};
services.grafana.declarativePlugins = with pkgs.grafanaPlugins; [ victoriametrics-metrics-datasource ];
services.grafana.declarativePlugins = with pkgs.grafanaPlugins; [
victoriametrics-metrics-datasource
];
})
];

View file

@ -0,0 +1,149 @@
{
pkgs,
lib,
config,
...
}:
let
cfg = config.xyno.services.traefik;
simpleProxyOpts = lib.mapAttrsToList (
n: v:
let
router = "simpleproxy-${n}-router";
service = "simpleproxy-${n}-service";
spl = lib.splitString "." v.host;
certDomain = if (builtins.length spl) > 2 then lib.concatStringsSep "." (builtins.tail spl) else spl;
in
{
routers.${router} = {
inherit service;
rule = "Host(`${v.host}`)";
tls.domains = [
{
main = certDomain;
sans = [ "*.${certDomain}" ];
}
];
};
services.${service} = {
loadBalancer.servers = [
{ url = v.internal; }
];
};
}
) cfg.simpleProxy;
in
{
options.xyno.services.traefik.enable = lib.mkEnableOption "enables traefik";
options.xyno.services.traefik.simpleProxy = lib.mkOption {
example = {
"example" = {
host = "example.org";
middlewares = [ "meow" ];
internal = "http://127.0.0.1:8080";
};
};
default = { };
type = lib.types.attrsOf (
lib.types.submodule {
options = {
middlewares = lib.mkOption {
type = lib.types.nullOr (lib.types.listOf lib.types.str);
};
internal = lib.mkOption {
type = lib.types.str;
};
host = lib.mkOption {
type = lib.types.str;
};
};
}
);
};
config = lib.mkIf cfg.enable {
services.traefik = {
enable = true;
environmentFiles = [
config.sops.templates."traefik.env".path
];
staticConfigOptions = {
metrics = lib.mkIf config.xyno.services.monitoring.enable {
otlp.http.endpoint = "http://localhost:8429/v1/metrics";
};
entryponts.web = {
address = ":80";
redirections.entryPoint = {
to = "websecure";
scheme = "https";
permanent = true;
};
};
entryponts.websecure = {
address = ":443";
tls.certResolver = "letsencrypt";
http3 = { };
};
log.level = "INFO";
certificatesResolvers.letsencrypt.acme = {
email = "ssl@xyno.systems";
caServer = "https://acme-v02.api.letsencrypt.org/directory";
dnsChallenge = {
provider = "desec";
};
};
};
dynamicConfigOptions = {
http = simpleProxyOpts;
tls.options.default = {
# mozilla modern
minVersion = "VersionTLS13";
curvePreferences = [
"X25519"
"CurveP256"
"CurveP384"
];
};
tls.options.old = {
# mozilla intermediate
minVersion = "VersionTLS12";
curvePreferences = [
"X25519"
"CurveP256"
"CurveP384"
];
cipherSuites = [
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305"
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305"
];
};
};
};
networking.firewall.allowedTCPPorts = [
80
443
];
networking.firewall.allowedUDPPorts = [ 443 ];
xyno.impermanence.directories = [ config.services.traefik.dataDir ];
sops.secrets."desec_token" = {
};
sops.templates."traefik.env".content = ''
DESEC_TOKEN=${config.sops.placeholder.desec_token}
DESEC_PROPAGATION_TIMEOUT=1200
'';
sops.templates."traefik.env".reloadUnits = [ "traefik.service" ];
# services.borgmatic.settings.traefikql_databases = [
# {
# name = "all"; # gets run as root anyways so can log in
# }
# ];
};
}