From a1ed41e31ac695e412ddc867b266abf3c619bc56 Mon Sep 17 00:00:00 2001 From: Christine Elisabeth Koppel Date: Fri, 13 Feb 2026 19:54:05 +0100 Subject: [PATCH] Add Anubis service configuration and middleware for protection. --- nix-system-configs/modules/system/forgejo.nix | 28 ++++---- nix-system-configs/modules/system/traefik.nix | 72 +++++++++++++++++++ 2 files changed, 86 insertions(+), 14 deletions(-) diff --git a/nix-system-configs/modules/system/forgejo.nix b/nix-system-configs/modules/system/forgejo.nix index d7f608a..6c96867 100644 --- a/nix-system-configs/modules/system/forgejo.nix +++ b/nix-system-configs/modules/system/forgejo.nix @@ -28,7 +28,7 @@ # Package local Jost OTF files from the repository into the Nix store so # they can be installed into the Forgejo custom assets directory. - jostFonts = pkgs.runCommand "jost-fonts" { src = ../styling/forgejo/Jost/OpenType; } '' + jostFonts = pkgs.runCommand "jost-fonts" {src = ../styling/forgejo/Jost/OpenType;} '' mkdir -p $out/fonts cp -a $src/*.otf $out/fonts/ ''; @@ -175,24 +175,24 @@ in { # Fallback: one-shot systemd service to copy custom assets on activation (works even if tmpfiles isn't applied or for live testing) systemd.services."forgejo-custom-files" = { description = "Install Forgejo custom templates and assets into customDir"; - after = [ "network.target" ]; + after = ["network.target"]; serviceConfig = { Type = "oneshot"; # Use bash -c to run a compact copy/install script that ensures dirs exist and files are owned by forgejo # cp -a ${toString ../styling/forgejo/home.tmpl} ${config.services.forgejo.customDir}/templates/home.tmpl; \ - ExecStart = ''${pkgs.bash}/bin/bash -c "set -eu; \ - install -d -m0755 -o forgejo -g forgejo ${config.services.forgejo.customDir}/public/assets/fonts; \ - install -d -m0755 -o forgejo -g forgejo ${config.services.forgejo.customDir}/public/assets/css; \ - install -d -m0755 -o forgejo -g forgejo ${config.services.forgejo.customDir}/templates/custom; \ - cp -a ${mapleFonts}/fonts/MapleMonoNerd.ttf ${config.services.forgejo.customDir}/public/assets/fonts/MapleMonoNerd.ttf; \ - cp -a ${toString ../styling/forgejo/header.tmpl} ${config.services.forgejo.customDir}/templates/custom/header.tmpl; \ - cp -a ${toString ../styling/forgejo/theme-custom.css} ${config.services.forgejo.customDir}/public/assets/css/theme-custom.css; \ - cp -a ${jostFonts}/fonts/* ${config.services.forgejo.customDir}/public/assets/fonts/ || true; \ - cp -a ${toString ../styling/PRG_logo.svg} ${config.services.forgejo.customDir}/public/assets/img/logo.svg || true; \ - cp -a ${toString ../styling/PRG_logo.png} ${config.services.forgejo.customDir}/public/assets/img/logo.png || true; \ - chown -R forgejo:forgejo ${config.services.forgejo.customDir}"''; + ExecStart = '' ${pkgs.bash}/bin/bash -c "set -eu; \ + install -d -m0755 -o forgejo -g forgejo ${config.services.forgejo.customDir}/public/assets/fonts; \ + install -d -m0755 -o forgejo -g forgejo ${config.services.forgejo.customDir}/public/assets/css; \ + install -d -m0755 -o forgejo -g forgejo ${config.services.forgejo.customDir}/templates/custom; \ + cp -a ${mapleFonts}/fonts/MapleMonoNerd.ttf ${config.services.forgejo.customDir}/public/assets/fonts/MapleMonoNerd.ttf; \ + cp -a ${toString ../styling/forgejo/header.tmpl} ${config.services.forgejo.customDir}/templates/custom/header.tmpl; \ + cp -a ${toString ../styling/forgejo/theme-custom.css} ${config.services.forgejo.customDir}/public/assets/css/theme-custom.css; \ + cp -a ${jostFonts}/fonts/* ${config.services.forgejo.customDir}/public/assets/fonts/ || true; \ + cp -a ${toString ../styling/PRG_logo.svg} ${config.services.forgejo.customDir}/public/assets/img/logo.svg || true; \ + cp -a ${toString ../styling/PRG_logo.png} ${config.services.forgejo.customDir}/public/assets/img/logo.png || true; \ + chown -R forgejo:forgejo ${config.services.forgejo.customDir}"''; }; - wantedBy = [ "multi-user.target" ]; + wantedBy = ["multi-user.target"]; }; # Open ports in the firewall. diff --git a/nix-system-configs/modules/system/traefik.nix b/nix-system-configs/modules/system/traefik.nix index ff09310..6074c2c 100644 --- a/nix-system-configs/modules/system/traefik.nix +++ b/nix-system-configs/modules/system/traefik.nix @@ -44,6 +44,43 @@ in { local.userDescription = "NixOS PRG Traefik Service"; local.address = "10.1.1.250"; + # Configure Anubis service + services.anubis = { + instances."" = { + enable = true; + settings = { + # Bind to TCP instead of Unix socket for Docker-style integration + BIND_NETWORK = "tcp"; + BIND = "127.0.0.1:8090"; + + # Empty TARGET for redirect mode + TARGET = " "; + + # Configure redirect domains + REDIRECT_DOMAINS = "prg-radio.org"; + + # Public URL for Anubis + PUBLIC_URL = "https://anubis.prg-radio.org"; + + # Cookie domain for proper scoping + COOKIE_DOMAIN = "prg-radio.org"; + + # Difficulty level + DIFFICULTY = 8; + + # Optional: serve robots.txt + SERVE_ROBOTS_TXT = true; + + # Optional: webmaster email for error pages + WEBMASTER_EMAIL = "dtu.prg@gmail.com"; + + # Metrics on separate port + METRICS_BIND_NETWORK = "tcp"; + METRICS_BIND = "127.0.0.1:8091"; + }; + }; + }; + services.traefik = { enable = true; group = "acme"; @@ -103,13 +140,35 @@ in { keyFile = "/var/lib/acme/prg-radio.org/key.pem"; } ]; + + # Define Anubis middleware + http.middlewares = { + anubis = { + forwardAuth = { + address = "http://127.0.0.1:8090/.within.website/x/cmd/anubis/api/check"; + trustForwardHeader = true; + }; + }; + }; + http.routers = { + # Anubis router (for challenge page) + anubis = { + rule = "Host(`anubis.prg-radio.org`)"; + service = "anubis"; + entryPoints = ["websecure"]; + tls = {}; + }; + + # Protected service example: Forgejo forgejo = { rule = "Host(`git.prg-radio.org`)"; service = "forgejo"; entryPoints = ["websecure"]; + middlewares = ["anubis"]; # Add Anubis protection tls = {}; }; + # Matrix HTTP router for client requests (Element etc.) matrix = { rule = "Host(`lgbtq.prg-radio.org`)"; @@ -117,21 +176,34 @@ in { entryPoints = ["websecure"]; tls = {}; }; + + # Protected service: Wavelog wavelog = { rule = "Host(`wavelog.prg-radio.org`)"; service = "wavelog"; entryPoints = ["websecure"]; + middlewares = ["anubis"]; # Add Anubis protection tls = {}; }; + # Protected service: PartDB (remove middleware) partdb = { rule = "Host(`partdb.prg-radio.org`)"; service = "partdb"; + middlewares = ["anubis"]; # Add Anubis protection entryPoints = ["websecure"]; tls = {}; }; }; + http.services = { + # Anubis service + anubis.loadBalancer = { + servers = [ + {url = "http://127.0.0.1:8090";} + ]; + }; + forgejo.loadBalancer = { servers = [ {url = "http://10.1.1.4:3000";}