Skip to content

Commit 799fc1d

Browse files
committed
add vpn bypass for Starr services
1 parent 9aba659 commit 799fc1d

3 files changed

Lines changed: 110 additions & 23 deletions

File tree

modules/arr-common/mkArrServiceModule.nix

Lines changed: 43 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,18 @@ in {
2525
{
2626
enable = mkEnableOption "${capitalizedName}";
2727

28+
vpn = {
29+
enable = mkOption {
30+
type = types.bool;
31+
default = false;
32+
description = ''
33+
Whether to route ${capitalizedName} traffic through the VPN.
34+
When false (default), ${capitalizedName} bypasses the VPN to prevent Cloudflare and image provider blocks.
35+
When true, ${capitalizedName} routes through the VPN (requires nixflix.mullvad.enable = true).
36+
'';
37+
};
38+
};
39+
2840
config = mkOption {
2941
type =
3042
arrConfigModule
@@ -80,6 +92,14 @@ in {
8092
};
8193

8294
config = mkIf (nixflix.enable && cfg.enable) {
95+
# Assertion: VPN routing requires Mullvad to be enabled
96+
assertions = [
97+
{
98+
assertion = cfg.vpn.enable -> config.nixflix.mullvad.enable;
99+
message = "Cannot enable VPN routing for ${capitalizedName} (nixflix.${serviceName}.vpn.enable = true) when Mullvad VPN is disabled. Please set nixflix.mullvad.enable = true.";
100+
}
101+
];
102+
83103
# Set pattern-based defaults
84104
nixflix.${serviceName}.config = {
85105
apiKeyPath = mkDefault null;
@@ -233,16 +253,29 @@ in {
233253

234254
# Ensure main service (radarr.service, etc.) starts after
235255
# directories are created and configured dependencies
236-
${serviceName} = {
237-
after =
238-
["nixflix-setup-dirs.service"]
239-
++ (optional config.services.postgresql.enable "postgresql-ready.target")
240-
++ (optional config.nixflix.mullvad.enable "mullvad-config.service");
241-
requires =
242-
["nixflix-setup-dirs.service"]
243-
++ (optional config.services.postgresql.enable "postgresql-ready.target");
244-
wants = optional config.nixflix.mullvad.enable "mullvad-config.service";
245-
};
256+
${serviceName} =
257+
{
258+
after =
259+
["nixflix-setup-dirs.service"]
260+
++ (optional (cfg.config.apiKeyPath != null && cfg.config.hostConfig.passwordPath != null) "${serviceName}-env.service")
261+
++ (optional config.services.postgresql.enable "postgresql-ready.target")
262+
++ (optional config.nixflix.mullvad.enable "mullvad-config.service");
263+
requires =
264+
["nixflix-setup-dirs.service"]
265+
++ (optional (cfg.config.apiKeyPath != null && cfg.config.hostConfig.passwordPath != null) "${serviceName}-env.service")
266+
++ (optional config.services.postgresql.enable "postgresql-ready.target");
267+
wants = optional config.nixflix.mullvad.enable "mullvad-config.service";
268+
}
269+
// optionalAttrs (cfg.config.apiKeyPath != null && cfg.config.hostConfig.passwordPath != null) {
270+
serviceConfig.EnvironmentFile = "/run/${serviceName}/env";
271+
}
272+
// optionalAttrs (config.nixflix.mullvad.enable && !cfg.vpn.enable) {
273+
# Bypass VPN by wrapping with mullvad-exclude
274+
serviceConfig.ExecStart = mkForce (pkgs.writeShellScript "${serviceName}-vpn-bypass" ''
275+
exec /run/wrappers/bin/mullvad-exclude ${getExe config.services.${serviceName}.package} \
276+
-nobrowser -data='${stateDir}'
277+
'');
278+
};
246279
}
247280
# Only create config and rootfolders services if apiKeyPath is configured
248281
// optionalAttrs (cfg.config.apiKeyPath != null && cfg.config.hostConfig.passwordPath != null) {
@@ -271,18 +304,6 @@ in {
271304
'';
272305
};
273306

274-
${serviceName} = {
275-
after =
276-
["${serviceName}-env.service" "nixflix-setup-dirs.service"]
277-
++ (optional config.services.postgresql.enable "postgresql-ready.target")
278-
++ (optional config.nixflix.mullvad.enable "mullvad-config.service");
279-
requires =
280-
["${serviceName}-env.service" "nixflix-setup-dirs.service"]
281-
++ (optional config.services.postgresql.enable "postgresql-ready.target");
282-
wants = optional config.nixflix.mullvad.enable "mullvad-config.service";
283-
serviceConfig.EnvironmentFile = "/run/${serviceName}/env";
284-
};
285-
286307
# Configure service via API
287308
"${serviceName}-config" = mkArrHostConfigService serviceName cfg.config;
288309
}

modules/mullvad.nix

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ in {
7474

7575
services.mullvad-vpn = {
7676
enable = true;
77-
enableExcludeWrapper = false;
77+
enableExcludeWrapper = true;
7878
package = mullvadPkg;
7979
};
8080

tests/unit-tests/default.nix

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,4 +111,70 @@ in {
111111
hasAllServices = systemdUnits ? prowlarr && systemdUnits ? prowlarr-config && systemdUnits ? prowlarr-indexers;
112112
in
113113
assertTest "prowlarr-service-generation" hasAllServices;
114+
115+
# Test that prowlarr with indexers generates correct systemd units
116+
sabnzbd-service-generation = let
117+
config = evalConfig [
118+
{
119+
nixflix = {
120+
enable = true;
121+
sabnzbd = {
122+
enable = true;
123+
downloadsDir = "/downloads/usenet";
124+
apiKeyPath = pkgs.writeText "sabnzbd-apikey" "testapikey123456789abcdef";
125+
nzbKeyPath = pkgs.writeText "sabnzbd-nzbkey" "testnzbkey123456789abcdef";
126+
environmentSecrets = [
127+
{
128+
env = "EWEKA_USERNAME";
129+
path = pkgs.writeText "eweka-username" "testuser";
130+
}
131+
{
132+
env = "EWEKA_PASSWORD";
133+
path = pkgs.writeText "eweka-password" "testpass123";
134+
}
135+
];
136+
settings = {
137+
port = 8080;
138+
host = "127.0.0.1";
139+
url_base = "/sabnzbd";
140+
ignore_samples = true;
141+
direct_unpack = false;
142+
article_tries = 5;
143+
servers = [
144+
{
145+
name = "TestServer";
146+
host = "news.example.com";
147+
port = 563;
148+
username = "$EWEKA_USERNAME";
149+
password = "$EWEKA_PASSWORD";
150+
connections = 10;
151+
ssl = true;
152+
priority = 0;
153+
}
154+
];
155+
categories = [
156+
{
157+
name = "tv";
158+
dir = "tv";
159+
priority = 0;
160+
pp = 3;
161+
script = "None";
162+
}
163+
{
164+
name = "movies";
165+
dir = "movies";
166+
priority = 1;
167+
pp = 2;
168+
script = "None";
169+
}
170+
];
171+
};
172+
};
173+
};
174+
}
175+
];
176+
systemdUnits = config.config.systemd.services;
177+
hasAllServices = systemdUnits ? sabnzbd && systemdUnits ? sabnzbd-config;
178+
in
179+
assertTest "prowlarr-service-generation" hasAllServices;
114180
}

0 commit comments

Comments
 (0)