Harden server and add Nix-native CI + self-hosted Gitea Actions
CI / flake-check (aarch64-linux) (push) Failing after 8s
CI / flake-check (x86_64-linux) (push) Failing after 2s
CI / pre-commit (aarch64-linux) (push) Failing after 2s
CI / pre-commit (x86_64-linux) (push) Failing after 2s

- caddy: security headers (X-Content-Type-Options/X-XSS-Protection/
  X-Frame-Options) on all vhosts + baseline CSP; strip SnappyMail
  upstream copies via header_down on mail.severijnse.eu
- tlsa-updater: compute TLSA 3 1 1 from cert SPKI (SHA-256), sync
  _25/_465/_993, fail-safe placeholders; coredns zone updated
- pre-commit: wire cachix/git-hooks.nix (alejandra, statix, actionlint,
  ...); CI pre-commit job over x86_64 + aarch64 matrix
- gitea: enable Gitea Actions + self-hosted runner (native:host,
  aarch64 via binfmt); add .gitea/workflows/ci.yml and local hook
- fix statix warnings (merge repeated systemd/database/configFile keys,
  inherit, bool-compare guards); add missing trailing newlines
This commit is contained in:
2026-07-12 00:05:13 +02:00
parent c5f771bd53
commit 7ed54e51a2
23 changed files with 336 additions and 147 deletions
@@ -58,42 +58,44 @@
echo "tlsa-update: TLSA set to $HEX"
'';
in {
# Ensure the distribution dir exists (Caddy does not write here).
systemd.tmpfiles.rules = [
"d ${distCertDir} 0755 root root - -"
];
systemd = {
# Ensure the distribution dir exists (Caddy does not write here).
tmpfiles.rules = [
"d ${distCertDir} 0755 root root - -"
];
systemd.services.tlsa-update = {
description = "Sync Caddy TLS certificate to mail server and update DANE/TLSA records";
after = ["caddy.service" "coredns.service"];
partOf = ["coredns.service"];
wantedBy = ["multi-user.target"];
path = with pkgs; [openssl coreutils gnused podman systemd];
serviceConfig = {
Type = "oneshot";
ExecStart = "${syncScript}";
User = "root";
Group = "root";
services.tlsa-update = {
description = "Sync Caddy TLS certificate to mail server and update DANE/TLSA records";
after = ["caddy.service" "coredns.service"];
partOf = ["coredns.service"];
wantedBy = ["multi-user.target"];
path = with pkgs; [openssl coreutils gnused podman systemd];
serviceConfig = {
Type = "oneshot";
ExecStart = "${syncScript}";
User = "root";
Group = "root";
};
};
};
# Fire as soon as Caddy rewrites the certificate on renewal (the atomic rewrite
# changes the directory mtime), eliminating the up-to-24h DANE drift window.
systemd.paths.tlsa-update = {
description = "Watch Caddy certificate directory for renewal";
wantedBy = ["paths.target"];
pathConfig = {
PathModified = [caddyCertDir];
Unit = "tlsa-update.service";
# Fire as soon as Caddy rewrites the certificate on renewal (the atomic rewrite
# changes the directory mtime), eliminating the up-to-24h DANE drift window.
paths.tlsa-update = {
description = "Watch Caddy certificate directory for renewal";
wantedBy = ["paths.target"];
pathConfig = {
PathModified = [caddyCertDir];
Unit = "tlsa-update.service";
};
};
};
# Fallback in case a renewal event is missed (e.g. inotify overflow).
systemd.timers.tlsa-update = {
wantedBy = ["timers.target"];
timerConfig = {
OnCalendar = "daily";
Persistent = true;
# Fallback in case a renewal event is missed (e.g. inotify overflow).
timers.tlsa-update = {
wantedBy = ["timers.target"];
timerConfig = {
OnCalendar = "daily";
Persistent = true;
};
};
};
}