diff --git a/agenix/hosts/sail/config.nix b/agenix/hosts/sail/config.nix index e3b1b0f..1049e46 100644 --- a/agenix/hosts/sail/config.nix +++ b/agenix/hosts/sail/config.nix @@ -68,6 +68,7 @@ nitter-config = { file = ./nitter/config.age; + mode = "444"; }; nitter-auth = { diff --git a/agenix/hosts/sail/nitter/config.age b/agenix/hosts/sail/nitter/config.age index ddbcc9c..f3a14d0 100644 Binary files a/agenix/hosts/sail/nitter/config.age and b/agenix/hosts/sail/nitter/config.age differ diff --git a/system/nixos/nitter.nix b/system/nixos/nitter.nix index 3af5125..7463adb 100644 --- a/system/nixos/nitter.nix +++ b/system/nixos/nitter.nix @@ -1,31 +1,55 @@ -{ config, ... }: +{ pkgs, config, ... }: let + nitter-pkg = pkgs.nitter-unstable; + proxy-no-auth = { recommendedProxySettings = true; proxyPass = "http://127.0.0.1:8001"; }; in { - virtualisation.arion.projects.nitter.settings = { - services = { - nitter = { - service = { - image = "zedeus/nitter:latest"; - container_name = "nitter"; - restart = "unless-stopped"; - ports = [ "127.0.0.1:8001:8080" ]; - environment = { - "TZ" = "Europe/Berlin"; - }; - volumes = [ - "${config.age.secrets.nitter-config.path}:/src/nitter.conf:ro" - ]; - labels = { - "com.centurylinklabs.watchtower.enable" = "true"; - }; - }; - }; + # Based on: https://github.com/NixOS/nixpkgs/blob/nixos-unstable/nixos/modules/services/misc/nitter.nix + + systemd.services.nitter = { + description = "Nitter (An alternative Twitter front-end)"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + serviceConfig = { + DynamicUser = true; + StateDirectory = "nitter"; + Environment = [ "NITTER_CONF_FILE=${config.age.secrets.nitter-config.path}" ]; + # Some parts of Nitter expect `public` folder in working directory, + # see https://github.com/zedeus/nitter/issues/414 + WorkingDirectory = "${nitter-pkg}/share/nitter"; + ExecStart = "${nitter-pkg}/bin/nitter"; + Restart = "on-failure"; + RestartSec = "5s"; + # Hardening + CapabilityBoundingSet = [ "" ]; + DeviceAllow = [ "" ]; + LockPersonality = true; + MemoryDenyWriteExecute = true; + PrivateDevices = true; + # A private user cannot have process capabilities on the host's user + # namespace and thus CAP_NET_BIND_SERVICE has no effect. + PrivateUsers = true; + ProcSubset = "pid"; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "invisible"; + RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ]; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + SystemCallArchitectures = "native"; + SystemCallFilter = [ "@system-service" "~@privileged" "~@resources" ]; + UMask = "0077"; }; }; @@ -39,23 +63,22 @@ in } ]; + root = "${nitter-pkg}/share/nitter/public/"; forceSSL = false; enableACME = false; locations."/" = { - basicAuthFile = config.age.secrets.nitter-auth.path; + tryFiles = "$uri @proxy"; + }; + locations."/pic/" = proxy-no-auth; + locations."/video/" = proxy-no-auth; + + locations."@proxy" = { + basicAuthFile = config.age.secrets.nitter-auth.path; recommendedProxySettings = true; proxyPass = "http://127.0.0.1:8001"; }; - - # Disable auth for certain paths - locations."/pic/" = proxy-no-auth; - locations."/video/" = proxy-no-auth; - locations."/favicon.ico" = proxy-no-auth; - locations."/favicon-32x32.png" = proxy-no-auth; - locations."/favicon-16x16.png" = proxy-no-auth; - locations."/apple-touch-icon.png" = proxy-no-auth; }; }; }