1 { config, lib, pkgs, ... }:
6 cfg = config.services.libreddit;
8 args = concatStringsSep " " ([
9 "--port ${toString cfg.port}"
10 "--address ${cfg.address}"
15 services.libreddit = {
16 enable = mkEnableOption (lib.mdDoc "Private front-end for Reddit");
20 example = "127.0.0.1";
22 description = lib.mdDoc "The address to listen on";
29 description = lib.mdDoc "The port to listen on";
32 openFirewall = mkOption {
35 description = lib.mdDoc "Open ports in the firewall for the libreddit web interface";
41 config = mkIf cfg.enable {
42 systemd.services.libreddit = {
43 description = "Private front-end for Reddit";
44 wantedBy = [ "multi-user.target" ];
45 after = [ "network.target" ];
48 ExecStart = "${pkgs.libreddit}/bin/libreddit ${args}";
49 AmbientCapabilities = lib.mkIf (cfg.port < 1024) [ "CAP_NET_BIND_SERVICE" ];
50 Restart = "on-failure";
53 CapabilityBoundingSet = if (cfg.port < 1024) then [ "CAP_NET_BIND_SERVICE" ] else [ "" ];
55 LockPersonality = true;
56 MemoryDenyWriteExecute = true;
57 PrivateDevices = true;
58 # A private user cannot have process capabilities on the host's user
59 # namespace and thus CAP_NET_BIND_SERVICE has no effect.
60 PrivateUsers = (cfg.port >= 1024);
63 ProtectControlGroups = true;
65 ProtectHostname = true;
66 ProtectKernelLogs = true;
67 ProtectKernelModules = true;
68 ProtectKernelTunables = true;
69 ProtectProc = "invisible";
70 RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
71 RestrictNamespaces = true;
72 RestrictRealtime = true;
73 RestrictSUIDSGID = true;
74 SystemCallArchitectures = "native";
75 SystemCallFilter = [ "@system-service" "~@privileged" "~@resources" ];
80 networking.firewall = mkIf cfg.openFirewall {
81 allowedTCPPorts = [ cfg.port ];