Merge branch 'dev'

This commit is contained in:
rasmus-kirk
2024-03-12 18:06:34 +01:00
13 changed files with 363 additions and 91 deletions
Generated
+15 -15
View File
@@ -8,11 +8,11 @@
]
},
"locked": {
"lastModified": 1705332421,
"narHash": "sha256-USpGLPme1IuqG78JNqSaRabilwkCyHmVWY0M9vYyqEA=",
"lastModified": 1708939976,
"narHash": "sha256-O5+nFozxz2Vubpdl1YZtPrilcIXPcRAjqNdNE8oCRoA=",
"owner": "numtide",
"repo": "devshell",
"rev": "83cb93d6d063ad290beee669f4badf9914cc16ec",
"rev": "5ddecd67edbd568ebe0a55905273e56cc82aabe3",
"type": "github"
},
"original": {
@@ -28,11 +28,11 @@
]
},
"locked": {
"lastModified": 1706830856,
"narHash": "sha256-a0NYyp+h9hlb7ddVz4LUn1vT/PLwqfrWYcHMvFB1xYg=",
"lastModified": 1709336216,
"narHash": "sha256-Dt/wOWeW6Sqm11Yh+2+t0dfEWxoMxGBvv3JpIocFl9E=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "b253292d9c0a5ead9bc98c4e9a26c6312e27d69f",
"rev": "f7b3c975cf067e56e7cda6cb098ebe3fb4d74ca2",
"type": "github"
},
"original": {
@@ -76,11 +76,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1708501555,
"narHash": "sha256-zJaF0RkdIPbh8LTmnpW/E7tZYpqIE+MePzlWwUNob4c=",
"lastModified": 1709386671,
"narHash": "sha256-VPqfBnIJ+cfa78pd4Y5Cr6sOWVW8GYHRVucxJGmRf8Q=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "b50a77c03d640716296021ad58950b1bb0345799",
"rev": "fa9a51752f1b5de583ad5213eb621be071806663",
"type": "github"
},
"original": {
@@ -122,11 +122,11 @@
]
},
"locked": {
"lastModified": 1708335038,
"narHash": "sha256-ETLZNFBVCabo7lJrpjD6cAbnE11eDOjaQnznmg/6hAE=",
"lastModified": 1709546977,
"narHash": "sha256-R0bi8zAWt1s1q7lSvwiFI8+kEL29rm4WtYTqPgjlEBs=",
"owner": "numtide",
"repo": "treefmt-nix",
"rev": "e504621290a1fd896631ddbc5e9c16f4366c9f65",
"rev": "e7a277c5d12bf570efa2427d9cfdb760b9a0512f",
"type": "github"
},
"original": {
@@ -142,11 +142,11 @@
]
},
"locked": {
"lastModified": 1709159289,
"narHash": "sha256-66eFi/SgygAMOLLLkH5oqwBiI4iE5Bj/kBJmmMhX8fg=",
"lastModified": 1709597689,
"narHash": "sha256-6pSgM6s2Rm2zAA/dYKAOK7wLNkzox5hBKOC5E5TJoO8=",
"owner": "Maroka-chan",
"repo": "VPN-Confinement",
"rev": "93804a1050d3699418f0f9472e9c5eca1aa8153d",
"rev": "2f5fffe81305e731593b1923acdf1c7653f1b17c",
"type": "github"
},
"original": {
+85
View File
@@ -0,0 +1,85 @@
{ config, pkgs, lib, ... }:
with lib;
let
cfg = config.util-nixarr.services.bazarr;
in
{
options = {
util-nixarr.services.bazarr = {
enable = mkEnableOption ("bazarr, a subtitle manager for Sonarr and Radarr");
openFirewall = mkOption {
type = types.bool;
default = false;
description = "Open ports in the firewall for the bazarr web interface.";
};
listenPort = mkOption {
type = types.port;
default = 6767;
description = "Port on which the bazarr web interface should listen";
};
dataDir = mkOption {
type = types.path;
default = "/var/lib/bazarr";
description = "State directory for bazarr";
};
user = mkOption {
type = types.str;
default = "bazarr";
description = "User account under which bazarr runs.";
};
group = mkOption {
type = types.str;
default = "bazarr";
description = "Group under which bazarr runs.";
};
};
};
config = mkIf cfg.enable {
systemd.tmpfiles.rules = [
"d '${cfg.dataDir}' 0700 bazarr root - -"
];
systemd.services.bazarr = {
description = "bazarr";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "simple";
User = cfg.user;
Group = cfg.group;
SyslogIdentifier = "bazarr";
ExecStart = pkgs.writeShellScript "start-bazarr" ''
${pkgs.bazarr}/bin/bazarr \
--config '${cfg.dataDir}' \
--port ${toString cfg.listenPort} \
--no-update True
'';
Restart = "on-failure";
};
};
networking.firewall = mkIf cfg.openFirewall {
allowedTCPPorts = [ cfg.listenPort ];
};
users.users = mkIf (cfg.user == "bazarr") {
bazarr = {
isSystemUser = true;
group = cfg.group;
};
};
users.groups = mkIf (cfg.group == "bazarr") {
bazarr = {};
};
};
}
+89
View File
@@ -0,0 +1,89 @@
{
config,
lib,
...
}:
with lib; let
cfg = config.nixarr.bazarr;
nixarr = config.nixarr;
in {
imports = [
./bazarr-module
];
options.nixarr.bazarr = {
enable = mkEnableOption "the bazarr service.";
stateDir = mkOption {
type = types.path;
default = "${nixarr.stateDir}/bazarr";
defaultText = literalExpression ''"''${nixarr.stateDir}/bazarr"'';
example = "/home/user/.local/share/nixarr/bazarr";
description = "The state directory for bazarr";
};
vpn.enable = mkOption {
type = types.bool;
default = false;
example = true;
description = ''
**Required options:** [`nixarr.vpn.enable`](#nixarr.vpn.enable)
Route Bazarr traffic through the VPN.
'';
};
};
config = mkIf cfg.enable {
assertions = [
{
assertion = cfg.vpn.enable -> nixarr.vpn.enable;
message = ''
The nixarr.bazarr.vpn.enable option requires the
nixarr.vpn.enable option to be set, but it was not.
'';
}
];
util-nixarr.services.bazarr = {
enable = cfg.enable;
user = "bazarr";
group = "media";
dataDir = cfg.stateDir;
};
# Enable and specify VPN namespace to confine service in.
systemd.services.bazarr.vpnconfinement = mkIf cfg.vpn.enable {
enable = true;
vpnnamespace = "wg";
};
# Port mappings
# TODO: openports
vpnnamespaces.wg = mkIf cfg.vpn.enable {
portMappings = [{ from = config.bazarr.listenPort; to = config.bazarr.listenPort; }];
};
services.nginx = mkIf cfg.vpn.enable {
enable = true;
recommendedTlsSettings = true;
recommendedOptimisation = true;
recommendedGzipSettings = true;
virtualHosts."127.0.0.1:${builtins.toString config.bazarr.listenPort}" = {
listen = [
{
addr = "0.0.0.0";
port = config.bazarr.listenPort;
}
];
locations."/" = {
recommendedProxySettings = true;
proxyWebsockets = true;
proxyPass = "http://192.168.15.1:${builtins.toString config.bazarr.listenPort}";
};
};
};
};
}
+120 -48
View File
@@ -6,9 +6,66 @@
}:
with lib; let
cfg = config.nixarr.ddns;
ddns-njalla = pkgs.writeShellApplication {
name = "ddns-njalla";
runtimeInputs = with pkgs; [ curl jq ];
# Thanks chatgpt...
text = ''
# Path to the JSON file
json_file="$1"
# Convert the JSON object into a series of tab-separated key-value pairs using jq
# - `to_entries[]`: Convert the object into an array of key-value pairs.
# - `[.key, .value]`: For each pair, create an array containing the key and the value.
# - `@tsv`: Convert the array to a tab-separated string.
# The output will be a series of lines, each containing a key and a value separated by a tab.
jq_command='to_entries[] | [.key, .value] | @tsv'
# Read the converted output line by line
# - `IFS=$'\t'`: Use the tab character as the field separator.
# - `read -r key val`: For each line, split it into `key` and `val` based on the tab separator.
while IFS=$'\t' read -r key val; do
# For each key-value pair, execute the curl command
# Replace `''${key}` and `''${val}` in the URL with the actual key and value.
curl -s "https://njal.la/update/?h=''${key}&k=''${val}&auto"
done < <(jq -r "$jq_command" "$json_file")
'';
};
in {
options.nixarr.ddns = {
njalla = {
vpn = {
enable = mkOption {
type = types.bool;
default = false;
example = true;
description = ''
**Required options:**
- [`nixarr.ddns.njalla.keysFile`](#nixarr.ddns.njalla.keysfile)
- [`nixarr.vpn.enable`](#nixarr.vpn.enable)
Whether or not to enable DDNS over VPN for a
[Njalla](https://njal.la/) domain. Setting this will point to
the public ip of your VPN. Useful if you're running services
over VPN and want a domain that points to the corresponding ip.
**Note:** You can enable both this and the regular njalla DDNS
service.
'';
};
keysFile = mkOption {
type = with types; nullOr path;
default = null;
example = "/data/.secret/njalla/keys-file.json";
description = ''
See [`nixarr.ddns.njalla.keysFile`](#nixarr.ddns.njalla.keysfile)
'';
};
};
enable = mkOption {
type = types.bool;
default = false;
@@ -60,60 +117,75 @@ in {
nixarr.ddns.njalla.keysFile option to be set, but it was not.
'';
}
{
assertion = cfg.njalla.vpn.enable -> (
cfg.njalla.vpn.keysFile != null &&
config.nixarr.vpn.enable
);
message = ''
The nixarr.ddns.njalla.enable option requires the
nixarr.vpn.enable option to be set, but it was not.
'';
}
];
systemd.timers = mkIf cfg.njalla.enable {
ddnsNjalla = {
description = "Timer for setting the Njalla DDNS records";
systemd.timers = mkMerge [
(mkIf cfg.njalla.enable {
ddnsNjalla = {
description = "Timer for setting the Njalla DDNS records";
timerConfig = {
OnBootSec = "30"; # Run 30 seconds after system boot
OnCalendar = "hourly";
Persistent = true; # Run service immediately if last window was missed
RandomizedDelaySec = "5min"; # Run service OnCalendar +- 5min
timerConfig = {
OnBootSec = "30"; # Run 30 seconds after system boot
OnCalendar = "hourly";
Persistent = true; # Run service immediately if last window was missed
RandomizedDelaySec = "5min"; # Run service OnCalendar +- 5min
};
wantedBy = ["multi-user.target"];
};
})
(mkIf cfg.njalla.vpn.enable {
ddnsNjallaVpn = {
description = "Timer for setting the Njalla DDNS records over VPN";
wantedBy = ["multi-user.target"];
};
};
timerConfig = {
OnBootSec = "30"; # Run 30 seconds after system boot
OnCalendar = "hourly";
Persistent = true; # Run service immediately if last window was missed
RandomizedDelaySec = "5min"; # Run service OnCalendar +- 5min
};
systemd.services = let
ddns-njalla = pkgs.writeShellApplication {
name = "ddns-njalla";
runtimeInputs = with pkgs; [ curl jq ];
# Thanks chatgpt...
text = ''
# Path to the JSON file
json_file="${cfg.njalla.keysFile}"
# Convert the JSON object into a series of tab-separated key-value pairs using jq
# - `to_entries[]`: Convert the object into an array of key-value pairs.
# - `[.key, .value]`: For each pair, create an array containing the key and the value.
# - `@tsv`: Convert the array to a tab-separated string.
# The output will be a series of lines, each containing a key and a value separated by a tab.
jq_command='to_entries[] | [.key, .value] | @tsv'
# Read the converted output line by line
# - `IFS=$'\t'`: Use the tab character as the field separator.
# - `read -r key val`: For each line, split it into `key` and `val` based on the tab separator.
while IFS=$'\t' read -r key val; do
# For each key-value pair, execute the curl command
# Replace `''${key}` and `''${val}` in the URL with the actual key and value.
curl -s "https://njal.la/update/?h=''${key}&k=''${val}&auto"
done < <(jq -r "$jq_command" "$json_file")
'';
};
in mkIf cfg.njalla.enable {
ddnsNjalla = {
description = "Sets the Njalla DDNS records";
serviceConfig = {
ExecStart = getExe ddns-njalla;
Type = "oneshot";
wantedBy = ["multi-user.target"];
};
};
};
})
];
systemd.services = mkMerge [
(mkIf cfg.njalla.enable {
ddnsNjalla = {
description = "Sets the Njalla DDNS records";
serviceConfig = {
ExecStart = ''${getExe ddns-njalla} "${cfg.njalla.keysFile}"'';
Type = "oneshot";
};
};
})
(mkIf (cfg.njalla.vpn.enable && config.nixarr.vpn.enable) {
ddnsNjallaVpn = {
description = "Sets the Njalla DDNS records over VPN";
vpnconfinement = {
enable = true;
vpnnamespace = "wg";
};
serviceConfig = {
ExecStart = ''${getExe ddns-njalla} "${cfg.njalla.vpn.keysFile}"'';
Type = "oneshot";
};
};
})
];
};
}
+5 -1
View File
@@ -244,7 +244,11 @@ in with lib; {
# Port mappings
# TODO: openports if expose.vpn
vpnnamespaces.wg = mkIf cfg.vpn.enable {
portMappings = [{ From = defaultPort; To = defaultPort; }];
portMappings = [{ from = defaultPort; to = defaultPort; }];
openVPNPorts = optional cfg.expose.vpn.enable {
port = cfg.expose.vpn.port;
protocol = "tcp";
};
};
};
}
+2 -1
View File
@@ -6,6 +6,7 @@
with lib; let
cfg = config.nixarr.lidarr;
nixarr = config.nixarr;
defaultPort = 8686;
in {
options.nixarr.lidarr = {
enable = mkEnableOption "the Lidarr service.";
@@ -61,7 +62,7 @@ in {
# Port mappings
# TODO: openports
vpnnamespaces.wg = mkIf cfg.vpn.enable {
portMappings = [{ From = defaultPort; To = defaultPort; }];
portMappings = [{ from = defaultPort; to = defaultPort; }];
};
services.nginx = mkIf cfg.vpn.enable {
+33 -9
View File
@@ -6,9 +6,18 @@
}:
with lib; let
cfg = config.nixarr;
list-unlinked = pkgs.writeShellApplication {
name = "list-unlinked";
runtimeInputs = with pkgs; [util-linux];
text = ''
find "$1" -type f -links 1 -exec du -h {} + | sort -h
'';
};
in {
imports = [
./jellyfin
./bazarr
./ddns
./radarr
./lidarr
@@ -45,6 +54,7 @@ in {
The following services are supported:
- [Jellyfin](#nixarr.jellyfin.enable)
- [Bazarr](#nixarr.bazarr.enable)
- [Lidarr](#nixarr.lidarr.enable)
- [Prowlarr](#nixarr.prowlarr.enable)
- [Radarr](#nixarr.radarr.enable)
@@ -56,6 +66,15 @@ in {
'';
};
mediaUsers = mkOption {
type = with types; listOf str;
default = [];
example = [ "user" ];
description = ''
Extra users to add to the media group.
'';
};
mediaDir = mkOption {
type = types.path;
default = "/data/media";
@@ -147,7 +166,7 @@ in {
];
users.groups = {
media = {};
media.members = cfg.mediaUsers;
streamer = {};
torrenter = {};
};
@@ -180,9 +199,18 @@ in {
"d '${cfg.mediaDir}/torrents/readarr' 0755 torrenter media - -"
];
environment.systemPackages = with pkgs; [
jdupes
list-unlinked
];
# TODO: wtf to do about openports
vpnnamespaces.wg = mkIf cfg.vpn.enable {
enable = true;
openVPNPorts = optional cfg.vpn.vpnTestService.enable {
port = cfg.vpn.vpnTestService.port;
protocol = "tcp";
};
accessibleFrom = [
"192.168.1.0/24"
"127.0.0.1"
@@ -191,8 +219,9 @@ in {
};
# TODO: openports
systemd.services.vpn-test-service = {
enable = cfg.vpn.vpnTestService.enable;
systemd.services.vpn-test-service = mkIf cfg.vpn.vpnTestService.enable {
enable = true;
vpnconfinement = {
enable = true;
vpnnamespace = "wg";
@@ -226,7 +255,7 @@ in {
./dnsleaktest.sh
'' + (if cfg.vpn.vpnTestService.port != null then ''
echo "starting netcat on port ${builtins.toString cfg.vpn.vpnTestService.port}:"
nc -vnlpu ${builtins.toString cfg.vpn.vpnTestService.port}
nc -vnlp ${builtins.toString cfg.vpn.vpnTestService.port}
'' else "");
};
in "${vpn-test}/bin/vpn-test";
@@ -234,11 +263,6 @@ in {
bindsTo = ["netns@wg.service"];
requires = ["network-online.target"];
after = ["wg.service"];
serviceConfig = {
#User = "torrenter";
NetworkNamespacePath = "/var/run/netns/wg";
BindReadOnlyPaths = ["/etc/netns/wg/resolv.conf:/etc/resolv.conf:norbind" "/data/test.file:/etc/test.file:norbind"];
};
};
};
}
+1 -1
View File
@@ -83,9 +83,9 @@ in {
};
# Port mappings
# TODO: openports
vpnnamespaces.wg = {
portMappings = [{ From = defaultPort; To = defaultPort; }];
openVPNPorts = map (x: { port = x; protocol = "both"; }) services.openssh.ports;
};
};
}
+1 -1
View File
@@ -64,7 +64,7 @@ in {
# Port mappings
vpnnamespaces.wg = mkIf cfg.vpn.enable {
portMappings = [{ From = defaultPort; To = defaultPort; }];
portMappings = [{ from = defaultPort; to = defaultPort; }];
};
services.nginx = mkIf cfg.vpn.enable {
+1 -1
View File
@@ -62,7 +62,7 @@ in {
# Port mappings
vpnnamespaces.wg = mkIf cfg.vpn.enable {
portMappings = [{ From = defaultPort; To = defaultPort; }];
portMappings = [{ from = defaultPort; to = defaultPort; }];
};
services.nginx = mkIf cfg.vpn.enable {
+1 -1
View File
@@ -60,7 +60,7 @@ in {
# Port mappings
vpnnamespaces.wg = mkIf cfg.vpn.enable {
portMappings = [{ From = defaultPort; To = defaultPort; }];
portMappings = [{ from = defaultPort; to = defaultPort; }];
};
services.nginx = mkIf cfg.vpn.enable {
+1 -1
View File
@@ -66,7 +66,7 @@ in {
# Port mappings
vpnnamespaces.wg = mkIf cfg.vpn.enable {
portMappings = [{ From = defaultPort; To = defaultPort; }];
portMappings = [{ from = defaultPort; to = defaultPort; }];
};
services.nginx = mkIf cfg.vpn.enable {
+9 -12
View File
@@ -224,19 +224,16 @@ in {
];
systemd.tmpfiles.rules = [
"d '${cfg.stateDir}' 0700 torrenter root - -"
"d '${cfg.stateDir}' 0750 torrenter torrenter - -"
# This is fixes a bug in nixpks (https://github.com/NixOS/nixpkgs/issues/291883)
"d '${cfg.stateDir}/.config/transmission-daemon' 0700 torrenter root - -"
] ++ (
if cfg-cross-seed.enable then
[ "d '${cfg-cross-seed.stateDir}' 0700 cross-seed root - -" ]
else []
);
"d '${cfg.stateDir}/.config/transmission-daemon' 0750 torrenter torrenter - -"
] ++ optional cfg-cross-seed.enable
"d '${cfg-cross-seed.stateDir}' 0700 cross-seed root - -";
util-nixarr.services.cross-seed = mkIf cfg-cross-seed.enable {
enable = true;
dataDir = cfg-cross-seed.stateDir;
#group = "media";
group = "torrenter";
settings = {
torrentDir = "${nixarr.mediaDir}/torrents";
outputDir = "${nixarr.mediaDir}/torrents/.cross-seed";
@@ -335,11 +332,11 @@ in {
};
# Port mappings
# TODO: open peerPort
vpnnamespaces.wg = mkIf cfg.vpn.enable {
portMappings = [{ From = cfg.uiPort; To = cfg.uiPort; }];
#openUdpPorts = [cfg.peerPort];
#openTcpPorts = [cfg.peerPort];
portMappings = [{ from = cfg.uiPort; to = cfg.uiPort; }];
openVPNPorts = [
{ port = cfg.peerPort; protocol = "both"; }
];
};
services.nginx = mkIf cfg.vpn.enable {