1{
2 config,
3 pkgs,
4 lib,
5 ...
6}:
7let
8 cfg = config.services.jackett;
9
10in
11{
12 options = {
13 services.jackett = {
14 enable = lib.mkEnableOption "Jackett, API support for your favorite torrent trackers";
15
16 port = lib.mkOption {
17 default = 9117;
18 type = lib.types.port;
19 description = ''
20 Port serving the web interface
21 '';
22 };
23
24 dataDir = lib.mkOption {
25 type = lib.types.str;
26 default = "/var/lib/jackett/.config/Jackett";
27 description = "The directory where Jackett stores its data files.";
28 };
29
30 openFirewall = lib.mkOption {
31 type = lib.types.bool;
32 default = false;
33 description = "Open ports in the firewall for the Jackett web interface.";
34 };
35
36 user = lib.mkOption {
37 type = lib.types.str;
38 default = "jackett";
39 description = "User account under which Jackett runs.";
40 };
41
42 group = lib.mkOption {
43 type = lib.types.str;
44 default = "jackett";
45 description = "Group under which Jackett runs.";
46 };
47
48 package = lib.mkPackageOption pkgs "jackett" { };
49 };
50 };
51
52 config = lib.mkIf cfg.enable {
53 systemd.tmpfiles.rules = [
54 "d '${cfg.dataDir}' 0700 ${cfg.user} ${cfg.group} - -"
55 ];
56
57 systemd.services.jackett = {
58 description = "Jackett";
59 after = [ "network.target" ];
60 wantedBy = [ "multi-user.target" ];
61
62 serviceConfig = {
63 Type = "simple";
64 User = cfg.user;
65 Group = cfg.group;
66 ExecStart = "${cfg.package}/bin/Jackett --NoUpdates --Port ${toString cfg.port} --DataFolder '${cfg.dataDir}'";
67 Restart = "on-failure";
68
69 # Sandboxing
70 CapabilityBoundingSet = [
71 "CAP_NET_BIND_SERVICE"
72 ];
73 ExecPaths = [
74 "${builtins.storeDir}"
75 ];
76 LockPersonality = true;
77 NoExecPaths = [
78 "/"
79 ];
80 NoNewPrivileges = true;
81 PrivateDevices = true;
82 PrivateMounts = true;
83 PrivateTmp = true;
84 PrivateUsers = true;
85 ProtectClock = true;
86 ProtectControlGroups = true;
87 ProtectHostname = true;
88 ProtectKernelLogs = true;
89 ProtectKernelModules = true;
90 ProtectKernelTunables = true;
91 ProtectProc = "invisible";
92 ProtectSystem = "strict";
93 ReadWritePaths = [
94 cfg.dataDir
95 ];
96 RemoveIPC = true;
97 RestrictAddressFamilies = [
98 "AF_INET"
99 "AF_INET6"
100 ];
101 RestrictNamespaces = true;
102 RestrictRealtime = true;
103 RestrictSUIDSGID = true;
104 SystemCallArchitectures = "native";
105 SystemCallFilter = [
106 "@system-service"
107 "~@clock"
108 "~@cpu-emulation"
109 "~@debug"
110 "~@obsolete"
111 "~@reboot"
112 "~@module"
113 "~@mount"
114 "~@swap"
115 ];
116 UMask = "0077";
117 };
118 };
119
120 networking.firewall = lib.mkIf cfg.openFirewall {
121 allowedTCPPorts = [ cfg.port ];
122 };
123
124 users.users = lib.mkIf (cfg.user == "jackett") {
125 jackett = {
126 group = cfg.group;
127 home = cfg.dataDir;
128 uid = config.ids.uids.jackett;
129 };
130 };
131
132 users.groups = lib.mkIf (cfg.group == "jackett") {
133 jackett.gid = config.ids.gids.jackett;
134 };
135 };
136}