at 23.11-pre 2.8 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 cfg = config.services.libreddit; 7 8 args = concatStringsSep " " ([ 9 "--port ${toString cfg.port}" 10 "--address ${cfg.address}" 11 ]); 12in 13{ 14 options = { 15 services.libreddit = { 16 enable = mkEnableOption (lib.mdDoc "Private front-end for Reddit"); 17 18 package = mkOption { 19 type = types.package; 20 default = pkgs.libreddit; 21 defaultText = literalExpression "pkgs.libreddit"; 22 description = lib.mdDoc "Libreddit package to use."; 23 }; 24 25 address = mkOption { 26 default = "0.0.0.0"; 27 example = "127.0.0.1"; 28 type = types.str; 29 description = lib.mdDoc "The address to listen on"; 30 }; 31 32 port = mkOption { 33 default = 8080; 34 example = 8000; 35 type = types.port; 36 description = lib.mdDoc "The port to listen on"; 37 }; 38 39 openFirewall = mkOption { 40 type = types.bool; 41 default = false; 42 description = lib.mdDoc "Open ports in the firewall for the libreddit web interface"; 43 }; 44 45 }; 46 }; 47 48 config = mkIf cfg.enable { 49 systemd.services.libreddit = { 50 description = "Private front-end for Reddit"; 51 wantedBy = [ "multi-user.target" ]; 52 after = [ "network.target" ]; 53 serviceConfig = { 54 DynamicUser = true; 55 ExecStart = "${cfg.package}/bin/libreddit ${args}"; 56 AmbientCapabilities = lib.mkIf (cfg.port < 1024) [ "CAP_NET_BIND_SERVICE" ]; 57 Restart = "on-failure"; 58 RestartSec = "2s"; 59 # Hardening 60 CapabilityBoundingSet = if (cfg.port < 1024) then [ "CAP_NET_BIND_SERVICE" ] else [ "" ]; 61 DeviceAllow = [ "" ]; 62 LockPersonality = true; 63 MemoryDenyWriteExecute = true; 64 PrivateDevices = true; 65 # A private user cannot have process capabilities on the host's user 66 # namespace and thus CAP_NET_BIND_SERVICE has no effect. 67 PrivateUsers = (cfg.port >= 1024); 68 ProcSubset = "pid"; 69 ProtectClock = true; 70 ProtectControlGroups = true; 71 ProtectHome = true; 72 ProtectHostname = true; 73 ProtectKernelLogs = true; 74 ProtectKernelModules = true; 75 ProtectKernelTunables = true; 76 ProtectProc = "invisible"; 77 RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ]; 78 RestrictNamespaces = true; 79 RestrictRealtime = true; 80 RestrictSUIDSGID = true; 81 SystemCallArchitectures = "native"; 82 SystemCallFilter = [ "@system-service" "~@privileged" "~@resources" ]; 83 UMask = "0077"; 84 }; 85 }; 86 87 networking.firewall = mkIf cfg.openFirewall { 88 allowedTCPPorts = [ cfg.port ]; 89 }; 90 }; 91}