blob: 2d2c5910966ae23d358c16606fb8934992376dce (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
|
# This module defines a service which runs a headless qBittorrent instance
{
config,
options,
lib,
pkgs,
...
}: let
defaultUser = "qbittorrent";
defaultGroup = "qbittorrent";
cfg = config.services.qbittorrent;
in {
options.services.qbittorrent = {
enable = lib.mkEnableOption "headless qBittorrent instance";
port = lib.mkOption {
description = "The port on which to serve the WebUI.";
type = lib.types.port;
default = 8080;
};
openFirewall = lib.mkOption {
description = ''
Open holes in the firewall so clients on LAN can connect to the web
interface. You must set up port forwarding if you want it accessable
from the wider internet.
'';
type = lib.types.bool;
default = false;
};
profile = lib.mkOption {
description = ''
The directory where qBittorrent should store it's data files. Note that
these are for qBittorrent itself, not the files it downloads. Those are
controlled through the configuration option `XXX`.
'';
type = lib.types.path;
default = "/var/lib/qBittorrent";
};
user = lib.mkOption {
description = ''
The user to run the qBittorrent service as.
The user is not automatically created if it is changed from the default value.
'';
type = lib.types.str;
default = defaultUser;
};
group = lib.mkOption {
description = ''
The group to run the qBittorrent service as.
The group is not automatically created if it is changed from the default value.
'';
type = lib.types.str;
default = defaultGroup;
};
package = lib.mkOption {
description = "qBittorrent package to use";
type = lib.types.package;
default = pkgs.qbittorrent-nox;
};
settings = lib.mkOption rec {
description = ''
An attribute set whose values overrides the ones specified in
`qBittorrent.conf`.
These values are applied on top of the existing configuration when the
service starts. This is a necessary compromise between determinism and
usability, as qBittorrent also saves all kinds of gunk in the
configuration file.
'';
type = lib.types.attrs;
default = {
LegalNotice = {
Accepted = false;
};
};
apply = lib.recursiveUpdate default;
example = {
LegalNotice = {
Accepted = true;
};
Preferences = {
"Connection\\PortRangeMin" = 20082;
"Downloads\\SavePath" = "/mnt";
"WebUI\\UseUPnP" = false;
};
};
};
};
config = lib.mkIf cfg.enable {
# Create the user/group if required.
users.users = lib.mkIf (cfg.user == defaultUser) {
${defaultUser} = {
description = "Runs ${options.services.qbittorrent.enable.description}";
group = cfg.group;
isSystemUser = true;
};
};
users.groups = lib.mkIf (cfg.group == defaultGroup) {
${defaultGroup} = {};
};
# Set up a service to run qBittorrent
# See: https://github.com/qbittorrent/qBittorrent/blob/615b76f78c8ab92ad57bed42fc4266950c9f0251/dist/unix/systemd/qbittorrent-nox%40.service.in
systemd.services.qbittorrent = {
enable = true;
unitConfig = {
Wants = ["network-online.target"];
After = ["local-fs.target" "network-online.target" "nss-lookup.target"];
};
serviceConfig = {
Type = "simple";
User = cfg.user;
Group = cfg.group;
PrivateTmp = false;
ExecStartPre = let
format = pkgs.formats.ini {};
settingsFile = format.generate "qBittorrent.conf" cfg.settings;
configPath = "${cfg.profile}/qBittorrent/config/qBittorrent.conf";
start-pre-script = pkgs.writeShellScript "qbittorrent-start-pre" ''
set -ue
# Create data directory if it doesn't exist
if ! test -d ${cfg.profile}; then
echo "Creating initial qBittorrent data directory in: ${cfg.profile}"
install -d -m 0755 -o ${cfg.user} -g ${cfg.group} ${cfg.profile}/qBittorrent/config/
fi
# Force-apply configuration.
${pkgs.crudini}/bin/crudini --ini-options=nospace --merge ${configPath} <${settingsFile}
'';
in
# Requires full permissions to create data directory, hence the "!".
"!${start-pre-script}";
ExecStart = pkgs.writeShellScript "qbittorrent-start" ''
exec ${cfg.package}/bin/qbittorrent-nox --webui-port=${toString cfg.port} --profile=${cfg.profile}
'';
TimeoutStopSec = 1800;
# Set as low-priority
IOSchedulingClass = "idle";
IOSchedulingPriority = "7";
};
wantedBy = ["multi-user.target"];
};
networking.firewall = lib.mkIf cfg.openFirewall {
allowedTCPPorts = [cfg.port];
};
};
}
|