Removed vpn, using Maroka's instead, removes all containerization :')
This commit is contained in:
Generated
+36
-1
@@ -90,13 +90,30 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"nixpkgs_2": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1709218635,
|
||||||
|
"narHash": "sha256-nytX/MkfqeTD4z7bMq4QRXcHxO9B3vRo9tM6fMtPFA8=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "068d4db604958d05d0b46c47f79b507d84dbc069",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-23.11",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"devshell": "devshell",
|
"devshell": "devshell",
|
||||||
"flake-parts": "flake-parts",
|
"flake-parts": "flake-parts",
|
||||||
"flake-root": "flake-root",
|
"flake-root": "flake-root",
|
||||||
"nixpkgs": "nixpkgs",
|
"nixpkgs": "nixpkgs",
|
||||||
"treefmt-nix": "treefmt-nix"
|
"treefmt-nix": "treefmt-nix",
|
||||||
|
"vpnconfinement": "vpnconfinement"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"systems": {
|
"systems": {
|
||||||
@@ -133,6 +150,24 @@
|
|||||||
"repo": "treefmt-nix",
|
"repo": "treefmt-nix",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"vpnconfinement": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs_2"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1709159289,
|
||||||
|
"narHash": "sha256-66eFi/SgygAMOLLLkH5oqwBiI4iE5Bj/kBJmmMhX8fg=",
|
||||||
|
"owner": "Maroka-chan",
|
||||||
|
"repo": "VPN-Confinement",
|
||||||
|
"rev": "93804a1050d3699418f0f9472e9c5eca1aa8153d",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "Maroka-chan",
|
||||||
|
"repo": "VPN-Confinement",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"root": "root",
|
"root": "root",
|
||||||
|
|||||||
@@ -8,6 +8,10 @@
|
|||||||
|
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
|
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
|
||||||
|
vpnconfinement = {
|
||||||
|
url = "github:Maroka-chan/VPN-Confinement";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
};
|
||||||
|
|
||||||
flake-parts = {
|
flake-parts = {
|
||||||
url = "github:hercules-ci/flake-parts";
|
url = "github:hercules-ci/flake-parts";
|
||||||
@@ -25,15 +29,15 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = inputs @ {flake-parts, ...}:
|
outputs = inputs @ {flake-parts, vpnconfinement, nixpkgs, ...}:
|
||||||
flake-parts.lib.mkFlake {
|
flake-parts.lib.mkFlake {
|
||||||
inherit inputs;
|
inherit inputs;
|
||||||
}
|
} {
|
||||||
rec {
|
|
||||||
imports = with inputs; [
|
imports = with inputs; [
|
||||||
flake-root.flakeModule
|
flake-root.flakeModule
|
||||||
treefmt-nix.flakeModule
|
treefmt-nix.flakeModule
|
||||||
devshell.flakeModule
|
devshell.flakeModule
|
||||||
|
#vpnconfinement.nixosModules.default
|
||||||
];
|
];
|
||||||
systems = [
|
systems = [
|
||||||
"x86_64-linux"
|
"x86_64-linux"
|
||||||
@@ -41,7 +45,10 @@
|
|||||||
|
|
||||||
flake = {
|
flake = {
|
||||||
nixosModules = rec {
|
nixosModules = rec {
|
||||||
nixarr = import ./nixarr;
|
#vpnconfinement = vpnconfinement.nixosModules.default;
|
||||||
|
nixarr = (import ./nixarr vpnconfinement);
|
||||||
|
#imports = [ vpnconfinement.nixosModules.default ];
|
||||||
|
#nixarr.imports = [ vpnconfinement ];
|
||||||
default = nixarr;
|
default = nixarr;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,117 @@
|
|||||||
|
{
|
||||||
|
pkgs,
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
with lib; let
|
||||||
|
cfg = config.nixarr.ddns;
|
||||||
|
in {
|
||||||
|
options.nixarr.ddns = {
|
||||||
|
njalla = {
|
||||||
|
enable = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = ''
|
||||||
|
**Required options:**
|
||||||
|
|
||||||
|
- [`nixarr.ddns.njalla.keysFile`](#nixarr.ddns.njalla.keysfile)
|
||||||
|
|
||||||
|
Whether or not to enable DDNS for a [Njalla](https://njal.la/)
|
||||||
|
domain.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
keysFile = mkOption {
|
||||||
|
type = with types; nullOr path;
|
||||||
|
default = null;
|
||||||
|
description = ''
|
||||||
|
A path to a JSON-file containing key value pairs of domains and keys.
|
||||||
|
|
||||||
|
To get the keys, create a dynamic njalla record. Upon creation
|
||||||
|
you should see something like the following command suggested:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
curl "https://njal.la/update/?h=jellyfin.example.com&k=zeubesojOLgC2eJC&auto"
|
||||||
|
```
|
||||||
|
|
||||||
|
Then the JSON-file you pass here should contain:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"jellyfin.example.com": "zeubesojOLgC2eJC"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
You can, of course, add more key-value pairs than just one.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.njalla.enable {
|
||||||
|
assertions = [
|
||||||
|
{
|
||||||
|
assertion = cfg.njalla.enable -> cfg.njalla.keysFile != null;
|
||||||
|
message = ''
|
||||||
|
The nixarr.ddns.njalla.enable option requires the
|
||||||
|
nixarr.ddns.njalla.keysFile option to be set, but it was not.
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
systemd.timers = 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
|
||||||
|
};
|
||||||
|
|
||||||
|
wantedBy = ["multi-user.target"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
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";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
+69
-164
@@ -1,4 +1,4 @@
|
|||||||
{
|
vpnconfinement: {
|
||||||
config,
|
config,
|
||||||
lib,
|
lib,
|
||||||
pkgs,
|
pkgs,
|
||||||
@@ -8,7 +8,9 @@ with lib; let
|
|||||||
cfg = config.nixarr;
|
cfg = config.nixarr;
|
||||||
in {
|
in {
|
||||||
imports = [
|
imports = [
|
||||||
|
vpnconfinement.nixosModules.default
|
||||||
./jellyfin
|
./jellyfin
|
||||||
|
./ddns
|
||||||
./radarr
|
./radarr
|
||||||
./lidarr
|
./lidarr
|
||||||
./readarr
|
./readarr
|
||||||
@@ -70,46 +72,6 @@ in {
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
ddns.njalla = {
|
|
||||||
enable = mkOption {
|
|
||||||
type = types.bool;
|
|
||||||
default = false;
|
|
||||||
description = ''
|
|
||||||
**Required options:**
|
|
||||||
|
|
||||||
- [`nixarr.ddns.njalla.keysFile`](#nixarr.ddns.njalla.keysfile)
|
|
||||||
|
|
||||||
Whether or not to enable DDNS for a [Njalla](https://njal.la/)
|
|
||||||
domain.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
keysFile = mkOption {
|
|
||||||
type = with types; nullOr path;
|
|
||||||
default = null;
|
|
||||||
description = ''
|
|
||||||
A path to a JSON-file containing key value pairs of domains and keys.
|
|
||||||
|
|
||||||
To get the keys, create a dynamic njalla record. Upon creation
|
|
||||||
you should see something like the following command suggested:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
curl "https://njal.la/update/?h=jellyfin.example.com&k=zeubesojOLgC2eJC&auto"
|
|
||||||
```
|
|
||||||
|
|
||||||
Then the JSON-file you pass here should contain:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"jellyfin.example.com": "zeubesojOLgC2eJC"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
You can, of course, add more key-value pairs than just one.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
vpn = {
|
vpn = {
|
||||||
enable = mkOption {
|
enable = mkOption {
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
@@ -128,16 +90,6 @@ in {
|
|||||||
description = "The path to the wireguard configuration file.";
|
description = "The path to the wireguard configuration file.";
|
||||||
};
|
};
|
||||||
|
|
||||||
dnsServers = mkOption {
|
|
||||||
type = with types; nullOr (listOf str);
|
|
||||||
default = null;
|
|
||||||
description = ''
|
|
||||||
Extra DNS servers for the VPN. If your wg config has a DNS field,
|
|
||||||
then this should not be necessary.
|
|
||||||
'';
|
|
||||||
example = ["1.1.1.2"];
|
|
||||||
};
|
|
||||||
|
|
||||||
vpnTestService = {
|
vpnTestService = {
|
||||||
enable = mkEnableOption ''
|
enable = mkEnableOption ''
|
||||||
the vpn test service. Useful for testing DNS leaks or if the VPN
|
the vpn test service. Useful for testing DNS leaks or if the VPN
|
||||||
@@ -145,10 +97,11 @@ in {
|
|||||||
'';
|
'';
|
||||||
|
|
||||||
port = mkOption {
|
port = mkOption {
|
||||||
type = types.port;
|
type = with types; nullOr port;
|
||||||
default = 12300;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
The port that the vpn test service listens to.
|
The port that netcat listens to on the vpn test service. If set to
|
||||||
|
`null`, then netcat will not be started.
|
||||||
'';
|
'';
|
||||||
example = 58403;
|
example = 58403;
|
||||||
};
|
};
|
||||||
@@ -157,7 +110,7 @@ in {
|
|||||||
openTcpPorts = mkOption {
|
openTcpPorts = mkOption {
|
||||||
type = with types; listOf port;
|
type = with types; listOf port;
|
||||||
default = [];
|
default = [];
|
||||||
description = lib.mdDoc ''
|
description = ''
|
||||||
What TCP ports to allow traffic from. You might need this if you're
|
What TCP ports to allow traffic from. You might need this if you're
|
||||||
port forwarding on your VPN provider and you're setting up services
|
port forwarding on your VPN provider and you're setting up services
|
||||||
not covered in by this module that uses the VPN.
|
not covered in by this module that uses the VPN.
|
||||||
@@ -168,7 +121,7 @@ in {
|
|||||||
openUdpPorts = mkOption {
|
openUdpPorts = mkOption {
|
||||||
type = with types; listOf port;
|
type = with types; listOf port;
|
||||||
default = [];
|
default = [];
|
||||||
description = lib.mdDoc ''
|
description = ''
|
||||||
What UDP ports to allow traffic from. You might need this if you're
|
What UDP ports to allow traffic from. You might need this if you're
|
||||||
port forwarding on your VPN provider and you're setting up services
|
port forwarding on your VPN provider and you're setting up services
|
||||||
not covered in by this module that uses the VPN.
|
not covered in by this module that uses the VPN.
|
||||||
@@ -187,149 +140,101 @@ in {
|
|||||||
to be set, but it was not.
|
to be set, but it was not.
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
{
|
|
||||||
assertion = cfg.ddns.njalla.enable -> cfg.ddns.njalla.keysFile != null;
|
|
||||||
message = ''
|
|
||||||
The nixarr.ddns.njalla.enable option requires the
|
|
||||||
nixarr.ddns.njalla.keysFile option to be set, but it was not.
|
|
||||||
'';
|
|
||||||
}
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
# TODO: move this to modules, at least the "*Arrs"...
|
||||||
users.groups = {
|
users.groups = {
|
||||||
media.gid = 992;
|
media = {};
|
||||||
prowlarr = {};
|
|
||||||
streamer = {};
|
streamer = {};
|
||||||
torrenter = {};
|
torrenter = {};
|
||||||
};
|
};
|
||||||
# TODO: This is BAD. But seems necessary when using containers.
|
|
||||||
# The prefered solution is to just remove containerization.
|
|
||||||
# Look at https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/misc/ids.nix
|
|
||||||
# See also issue: https://github.com/rasmus-kirk/nixarr/issues/1
|
|
||||||
users.users = {
|
users.users = {
|
||||||
streamer = {
|
streamer = {
|
||||||
isSystemUser = true;
|
isSystemUser = true;
|
||||||
group = "streamer";
|
group = "streamer";
|
||||||
uid = lib.mkForce 316;
|
|
||||||
};
|
|
||||||
sonarr = {
|
|
||||||
isSystemUser = true;
|
|
||||||
group = "media";
|
|
||||||
uid = lib.mkForce 274;
|
|
||||||
};
|
|
||||||
radarr = {
|
|
||||||
isSystemUser = true;
|
|
||||||
group = "media";
|
|
||||||
uid = lib.mkForce 275;
|
|
||||||
};
|
|
||||||
lidarr = {
|
|
||||||
isSystemUser = true;
|
|
||||||
group = "media";
|
|
||||||
uid = lib.mkForce 306;
|
|
||||||
};
|
|
||||||
readarr = {
|
|
||||||
isSystemUser = true;
|
|
||||||
group = "media";
|
|
||||||
uid = lib.mkForce 309;
|
|
||||||
};
|
};
|
||||||
torrenter = {
|
torrenter = {
|
||||||
isSystemUser = true;
|
isSystemUser = true;
|
||||||
group = "torrenter";
|
group = "torrenter";
|
||||||
uid = lib.mkForce 70;
|
|
||||||
};
|
|
||||||
prowlarr = {
|
|
||||||
isSystemUser = true;
|
|
||||||
group = "prowlarr";
|
|
||||||
uid = lib.mkForce 293;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.tmpfiles.rules = [
|
systemd.tmpfiles.rules = [
|
||||||
# Media dirs
|
# Media dirs
|
||||||
"d '${cfg.mediaDir}' 0775 root media - -"
|
"d '${cfg.mediaDir}' 0775 root media - -"
|
||||||
"d '${cfg.mediaDir}/library' 0775 streamer media - -"
|
"d '${cfg.mediaDir}/library' 0775 streamer media - -"
|
||||||
"d '${cfg.mediaDir}/library/shows' 0775 streamer media - -"
|
"d '${cfg.mediaDir}/library/shows' 0775 streamer media - -"
|
||||||
"d '${cfg.mediaDir}/library/movies' 0775 streamer media - -"
|
"d '${cfg.mediaDir}/library/movies' 0775 streamer media - -"
|
||||||
"d '${cfg.mediaDir}/library/music' 0775 streamer media - -"
|
"d '${cfg.mediaDir}/library/music' 0775 streamer media - -"
|
||||||
"d '${cfg.mediaDir}/library/books' 0775 streamer media - -"
|
"d '${cfg.mediaDir}/library/books' 0775 streamer media - -"
|
||||||
"d '${cfg.mediaDir}/torrents' 0755 torrenter media - -"
|
"d '${cfg.mediaDir}/torrents' 0755 torrenter media - -"
|
||||||
"d '${cfg.mediaDir}/torrents/.incomplete' 0755 torrenter media - -"
|
"d '${cfg.mediaDir}/torrents/.incomplete' 0755 torrenter media - -"
|
||||||
"d '${cfg.mediaDir}/torrents/.watch' 0755 torrenter media - -"
|
"d '${cfg.mediaDir}/torrents/.watch' 0755 torrenter media - -"
|
||||||
"d '${cfg.mediaDir}/torrents/manual' 0755 torrenter media - -"
|
"d '${cfg.mediaDir}/torrents/manual' 0755 torrenter media - -"
|
||||||
"d '${cfg.mediaDir}/torrents/liadarr' 0755 torrenter media - -"
|
"d '${cfg.mediaDir}/torrents/liadarr' 0755 torrenter media - -"
|
||||||
"d '${cfg.mediaDir}/torrents/radarr' 0755 torrenter media - -"
|
"d '${cfg.mediaDir}/torrents/radarr' 0755 torrenter media - -"
|
||||||
"d '${cfg.mediaDir}/torrents/sonarr' 0755 torrenter media - -"
|
"d '${cfg.mediaDir}/torrents/sonarr' 0755 torrenter media - -"
|
||||||
"d '${cfg.mediaDir}/torrents/readarr' 0755 torrenter media - -"
|
"d '${cfg.mediaDir}/torrents/readarr' 0755 torrenter media - -"
|
||||||
];
|
];
|
||||||
|
|
||||||
util-nixarr.vpnnamespace = {
|
# TODO: wtf to do about openports
|
||||||
enable = cfg.vpn.enable;
|
vpnnamespaces.wg = {
|
||||||
|
enable = cfg.vpn.enable ;
|
||||||
accessibleFrom = [
|
accessibleFrom = [
|
||||||
"192.168.1.0/24"
|
"192.168.1.0/24"
|
||||||
"127.0.0.1"
|
"127.0.0.1"
|
||||||
];
|
];
|
||||||
dnsServers = cfg.vpn.dnsServers;
|
wireguardConfigFile = cfg.vpn.wgConf;
|
||||||
wireguardAddressPath = cfg.vpn.wgAddress;
|
|
||||||
wireguardConfigFile = if cfg.vpn.wgConf != null then cfg.vpn.wgConf else "";
|
|
||||||
vpnTestService = {
|
|
||||||
enable = cfg.vpn.vpnTestService.enable;
|
|
||||||
port = cfg.vpn.vpnTestService.port;
|
|
||||||
};
|
|
||||||
openTcpPorts = cfg.vpn.openTcpPorts;
|
|
||||||
openUdpPorts = cfg.vpn.openUdpPorts;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.timers = mkIf cfg.ddns.njalla.enable {
|
# TODO: openports
|
||||||
ddnsNjalla = {
|
systemd.services.vpn-test-service = {
|
||||||
description = "Timer for setting the Njalla DDNS records";
|
enable = cfg.vpn.vpnTestService.enable;
|
||||||
|
vpnconfinement = {
|
||||||
timerConfig = {
|
enable = true;
|
||||||
OnBootSec = "30"; # Run 30 seconds after system boot
|
vpnnamespace = "wg";
|
||||||
OnCalendar = "hourly";
|
|
||||||
Persistent = true; # Run service immediately if last window was missed
|
|
||||||
RandomizedDelaySec = "5min"; # Run service OnCalendar +- 5min
|
|
||||||
};
|
|
||||||
|
|
||||||
wantedBy = ["multi-user.target"];
|
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
systemd.services = let
|
script = let
|
||||||
ddns-njalla = pkgs.writeShellApplication {
|
vpn-test = pkgs.writeShellApplication {
|
||||||
name = "ddns-njalla";
|
name = "vpn-test";
|
||||||
|
|
||||||
runtimeInputs = with pkgs; [ curl jq ];
|
runtimeInputs = with pkgs; [util-linux unixtools.ping coreutils curl bash libressl netcat-gnu openresolv dig];
|
||||||
|
|
||||||
# Thanks chatgpt...
|
text = ''
|
||||||
text = ''
|
cd "$(mktemp -d)"
|
||||||
# Path to the JSON file
|
|
||||||
json_file="${cfg.ddns.njalla.keysFile}"
|
|
||||||
|
|
||||||
# Convert the JSON object into a series of tab-separated key-value pairs using jq
|
# Print resolv.conf
|
||||||
# - `to_entries[]`: Convert the object into an array of key-value pairs.
|
echo "/etc/resolv.conf contains:"
|
||||||
# - `[.key, .value]`: For each pair, create an array containing the key and the value.
|
cat /etc/resolv.conf
|
||||||
# - `@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
|
# Query resolvconf
|
||||||
# - `IFS=$'\t'`: Use the tab character as the field separator.
|
echo "resolvconf output:"
|
||||||
# - `read -r key val`: For each line, split it into `key` and `val` based on the tab separator.
|
resolvconf -l
|
||||||
while IFS=$'\t' read -r key val; do
|
echo ""
|
||||||
# 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.ddns.njalla.enable {
|
|
||||||
ddnsNjalla = {
|
|
||||||
description = "Sets the Njalla DDNS records";
|
|
||||||
|
|
||||||
serviceConfig = {
|
# Get ip
|
||||||
ExecStart = getExe ddns-njalla;
|
echo "Getting IP:"
|
||||||
Type = "oneshot";
|
curl -s ipinfo.io
|
||||||
|
|
||||||
|
echo -ne "DNS leak test:"
|
||||||
|
curl -s https://raw.githubusercontent.com/macvk/dnsleaktest/b03ab54d574adbe322ca48cbcb0523be720ad38d/dnsleaktest.sh -o dnsleaktest.sh
|
||||||
|
chmod +x dnsleaktest.sh
|
||||||
|
./dnsleaktest.sh
|
||||||
|
'' + (if cfg.vpn.vpnTestService.port != null then ''
|
||||||
|
echo "starting netcat on port ${builtins.toString cfg.vpn.vpnTestService.port}:"
|
||||||
|
nc -vnlp ${builtins.toString cfg.vpn.vpnTestService.port}
|
||||||
|
'' else "");
|
||||||
};
|
};
|
||||||
|
in "${vpn-test}/bin/vpn-test";
|
||||||
|
|
||||||
|
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"];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ let
|
|||||||
cfg = config.nixarr.jellyfin;
|
cfg = config.nixarr.jellyfin;
|
||||||
defaultPort = 8096;
|
defaultPort = 8096;
|
||||||
nixarr = config.nixarr;
|
nixarr = config.nixarr;
|
||||||
dnsServers = config.lib.vpn.dnsServers;
|
|
||||||
in with lib; {
|
in with lib; {
|
||||||
options.nixarr.jellyfin = {
|
options.nixarr.jellyfin = {
|
||||||
enable = mkEnableOption "the Jellyfin service.";
|
enable = mkEnableOption "the Jellyfin service.";
|
||||||
@@ -228,57 +227,16 @@ in with lib; {
|
|||||||
defaults.email = cfg.expose.https.acmeMail;
|
defaults.email = cfg.expose.https.acmeMail;
|
||||||
};
|
};
|
||||||
|
|
||||||
util-nixarr.vpnnamespace.portMappings = [
|
# Enable and specify VPN namespace to confine service in.
|
||||||
(
|
systemd.services.jellyfin.vpnconfinement = mkIf cfg.vpn.enable {
|
||||||
mkIf cfg.vpn.enable {
|
enable = true;
|
||||||
From = defaultPort;
|
vpnnamespace = "wg";
|
||||||
To = defaultPort;
|
|
||||||
}
|
|
||||||
)
|
|
||||||
];
|
|
||||||
|
|
||||||
systemd.services."container@jellyfin" = mkIf cfg.vpn.enable {
|
|
||||||
requires = ["wg.service"];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
containers.jellyfin = mkIf cfg.vpn.enable {
|
# Port mappings
|
||||||
autoStart = true;
|
# TODO: openports if expose.vpn
|
||||||
ephemeral = true;
|
vpnnamespaces.wg = mkIf cfg.vpn.enable {
|
||||||
extraFlags = ["--network-namespace-path=/var/run/netns/wg"];
|
portMappings = [{ From = defaultPort; To = defaultPort; }];
|
||||||
|
|
||||||
bindMounts = {
|
|
||||||
"${nixarr.mediaDir}/library".isReadOnly = false;
|
|
||||||
"${cfg.stateDir}".isReadOnly = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
config = {
|
|
||||||
users.groups.streamer = {
|
|
||||||
gid = config.users.groups.streamer.gid;
|
|
||||||
};
|
|
||||||
users.users.streamer = {
|
|
||||||
uid = lib.mkForce config.users.users.streamer.uid;
|
|
||||||
isSystemUser = true;
|
|
||||||
group = "streamer";
|
|
||||||
};
|
|
||||||
|
|
||||||
# Use systemd-resolved inside the container
|
|
||||||
# Workaround for bug https://github.com/NixOS/nixpkgs/issues/162686
|
|
||||||
networking.useHostResolvConf = lib.mkForce false;
|
|
||||||
services.resolved.enable = true;
|
|
||||||
networking.nameservers = dnsServers;
|
|
||||||
|
|
||||||
services.jellyfin = {
|
|
||||||
enable = true;
|
|
||||||
user = "streamer";
|
|
||||||
group = "streamer";
|
|
||||||
logDir = "${cfg.stateDir}/log";
|
|
||||||
cacheDir = "${cfg.stateDir}/cache";
|
|
||||||
dataDir = "${cfg.stateDir}/data";
|
|
||||||
configDir = "${cfg.stateDir}/config";
|
|
||||||
};
|
|
||||||
|
|
||||||
system.stateVersion = "23.11";
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
}:
|
}:
|
||||||
with lib; let
|
with lib; let
|
||||||
cfg = config.nixarr.lidarr;
|
cfg = config.nixarr.lidarr;
|
||||||
dnsServers = config.lib.vpn.dnsServers;
|
|
||||||
nixarr = config.nixarr;
|
nixarr = config.nixarr;
|
||||||
in {
|
in {
|
||||||
options.nixarr.lidarr = {
|
options.nixarr.lidarr = {
|
||||||
@@ -50,53 +49,16 @@ in {
|
|||||||
dataDir = cfg.stateDir;
|
dataDir = cfg.stateDir;
|
||||||
};
|
};
|
||||||
|
|
||||||
util-nixarr.vpnnamespace.portMappings = [
|
# Enable and specify VPN namespace to confine service in.
|
||||||
(
|
systemd.services.lidarr.vpnconfinement = mkIf cfg.vpn.enable {
|
||||||
mkIf cfg.vpn.enable {
|
enable = true;
|
||||||
From = defaultPort;
|
vpnnamespace = "wg";
|
||||||
To = defaultPort;
|
|
||||||
}
|
|
||||||
)
|
|
||||||
];
|
|
||||||
|
|
||||||
systemd.services."container@lidarr" = mkIf cfg.vpn.enable {
|
|
||||||
requires = ["wg.service"];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
containers.lidarr = mkIf cfg.vpn.enable {
|
# Port mappings
|
||||||
autoStart = true;
|
# TODO: openports
|
||||||
ephemeral = true;
|
vpnnamespaces.wg = mkIf cfg.vpn.enable {
|
||||||
extraFlags = ["--network-namespace-path=/var/run/netns/wg"];
|
portMappings = [{ From = defaultPort; To = defaultPort; }];
|
||||||
|
|
||||||
bindMounts = {
|
|
||||||
"${nixarr.mediaDir}".isReadOnly = false;
|
|
||||||
"${cfg.stateDir}".isReadOnly = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
config = {
|
|
||||||
users.groups.media = {
|
|
||||||
gid = config.users.groups.media.gid;
|
|
||||||
};
|
|
||||||
users.users.lidarr = {
|
|
||||||
uid = lib.mkForce config.users.users.lidarr.uid;
|
|
||||||
isSystemUser = true;
|
|
||||||
group = "media";
|
|
||||||
};
|
|
||||||
|
|
||||||
# Use systemd-resolved inside the container
|
|
||||||
# Workaround for bug https://github.com/NixOS/nixpkgs/issues/162686
|
|
||||||
networking.useHostResolvConf = lib.mkForce false;
|
|
||||||
services.resolved.enable = true;
|
|
||||||
networking.nameservers = dnsServers;
|
|
||||||
|
|
||||||
services.lidarr = {
|
|
||||||
enable = true;
|
|
||||||
group = "media";
|
|
||||||
dataDir = "${cfg.stateDir}";
|
|
||||||
};
|
|
||||||
|
|
||||||
system.stateVersion = "23.11";
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
services.nginx = mkIf cfg.vpn.enable {
|
services.nginx = mkIf cfg.vpn.enable {
|
||||||
|
|||||||
@@ -75,19 +75,16 @@ in {
|
|||||||
''
|
''
|
||||||
] else [];
|
] else [];
|
||||||
|
|
||||||
util-nixarr.vpnnamespace = {
|
# Enable and specify VPN namespace to confine service in.
|
||||||
portMappings = builtins.map (x: { From = x; To = x; }) config.services.openssh.ports;
|
systemd.services.openssh.vpnconfinement = {
|
||||||
openUdpPorts = config.services.openssh.ports;
|
enable = true;
|
||||||
openTcpPorts = config.services.openssh.ports;
|
vpnnamespace = "wg";
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.services.openssh = {
|
# Port mappings
|
||||||
bindsTo = [ "netns@wg.service" ];
|
# TODO: openports
|
||||||
requires = [ "network-online.target" ];
|
vpnnamespaces.wg = {
|
||||||
after = [ "wg.service" ];
|
portMappings = [{ From = defaultPort; To = defaultPort; }];
|
||||||
serviceConfig = {
|
|
||||||
NetworkNamespacePath = "/var/run/netns/wg";
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-40
@@ -6,7 +6,6 @@
|
|||||||
}:
|
}:
|
||||||
with lib; let
|
with lib; let
|
||||||
defaultPort = 9696;
|
defaultPort = 9696;
|
||||||
dnsServers = config.lib.vpn.dnsServers;
|
|
||||||
nixarr = config.nixarr;
|
nixarr = config.nixarr;
|
||||||
cfg = config.nixarr.prowlarr;
|
cfg = config.nixarr.prowlarr;
|
||||||
in {
|
in {
|
||||||
@@ -49,51 +48,22 @@ in {
|
|||||||
"d '${cfg.stateDir}' 0700 prowlarr root - -"
|
"d '${cfg.stateDir}' 0700 prowlarr root - -"
|
||||||
];
|
];
|
||||||
|
|
||||||
util-nixarr.services.prowlarr = mkIf (!cfg.vpn.enable) {
|
users.groups.prowlarr = {};
|
||||||
|
|
||||||
|
util-nixarr.services.prowlarr = {
|
||||||
enable = true;
|
enable = true;
|
||||||
dataDir = cfg.stateDir;
|
dataDir = cfg.stateDir;
|
||||||
};
|
};
|
||||||
|
|
||||||
util-nixarr.vpnnamespace.portMappings = [
|
# Enable and specify VPN namespace to confine service in.
|
||||||
(
|
systemd.services.prowlarr.vpnconfinement = mkIf cfg.vpn.enable {
|
||||||
mkIf cfg.vpn.enable {
|
enable = true;
|
||||||
From = defaultPort;
|
vpnnamespace = "wg";
|
||||||
To = defaultPort;
|
|
||||||
}
|
|
||||||
)
|
|
||||||
];
|
|
||||||
|
|
||||||
systemd.services."container@prowlarr" = mkIf cfg.vpn.enable {
|
|
||||||
requires = ["wg.service"];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
containers.prowlarr = mkIf cfg.vpn.enable {
|
# Port mappings
|
||||||
autoStart = true;
|
vpnnamespaces.wg = mkIf cfg.vpn.enable {
|
||||||
ephemeral = true;
|
portMappings = [{ From = defaultPort; To = defaultPort; }];
|
||||||
extraFlags = ["--network-namespace-path=/var/run/netns/wg"];
|
|
||||||
bindMounts."${cfg.stateDir}".isReadOnly = false;
|
|
||||||
|
|
||||||
config = {
|
|
||||||
users.groups.prowlarr = {};
|
|
||||||
users.users.prowlarr = {
|
|
||||||
uid = lib.mkForce config.users.users.prowlarr.uid;
|
|
||||||
isSystemUser = true;
|
|
||||||
group = "prowlarr";
|
|
||||||
};
|
|
||||||
|
|
||||||
# Use systemd-resolved inside the container
|
|
||||||
# Workaround for bug https://github.com/NixOS/nixpkgs/issues/162686
|
|
||||||
networking.useHostResolvConf = lib.mkForce false;
|
|
||||||
services.resolved.enable = true;
|
|
||||||
networking.nameservers = dnsServers;
|
|
||||||
|
|
||||||
util-nixarr.services.prowlarr = {
|
|
||||||
enable = true;
|
|
||||||
dataDir = cfg.stateDir;
|
|
||||||
};
|
|
||||||
|
|
||||||
system.stateVersion = "23.11";
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
services.nginx = mkIf cfg.vpn.enable {
|
services.nginx = mkIf cfg.vpn.enable {
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ with lib; let
|
|||||||
cfg = config.nixarr.radarr;
|
cfg = config.nixarr.radarr;
|
||||||
defaultPort = 7878;
|
defaultPort = 7878;
|
||||||
nixarr = config.nixarr;
|
nixarr = config.nixarr;
|
||||||
dnsServers = config.lib.vpn.dnsServers;
|
|
||||||
in {
|
in {
|
||||||
options.nixarr.radarr = {
|
options.nixarr.radarr = {
|
||||||
enable = mkEnableOption "Enable the Radarr service.";
|
enable = mkEnableOption "Enable the Radarr service.";
|
||||||
@@ -45,60 +44,22 @@ in {
|
|||||||
"d '${cfg.stateDir}' 0700 radarr root - -"
|
"d '${cfg.stateDir}' 0700 radarr root - -"
|
||||||
];
|
];
|
||||||
|
|
||||||
services.radarr = mkIf (!cfg.vpn.enable) {
|
services.radarr = {
|
||||||
enable = cfg.enable;
|
enable = cfg.enable;
|
||||||
user = "radarr";
|
user = "radarr";
|
||||||
group = "media";
|
group = "media";
|
||||||
dataDir = cfg.stateDir;
|
dataDir = cfg.stateDir;
|
||||||
};
|
};
|
||||||
|
|
||||||
util-nixarr.vpnnamespace.portMappings = [
|
# Enable and specify VPN namespace to confine service in.
|
||||||
(
|
systemd.services.radarr.vpnconfinement = mkIf cfg.vpn.enable {
|
||||||
mkIf cfg.vpn.enable {
|
enable = true;
|
||||||
From = defaultPort;
|
vpnnamespace = "wg";
|
||||||
To = defaultPort;
|
|
||||||
}
|
|
||||||
)
|
|
||||||
];
|
|
||||||
|
|
||||||
systemd.services."container@radarr" = mkIf cfg.vpn.enable {
|
|
||||||
requires = ["wg.service"];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
containers.radarr = mkIf cfg.vpn.enable {
|
# Port mappings
|
||||||
autoStart = true;
|
vpnnamespaces.wg = mkIf cfg.vpn.enable {
|
||||||
ephemeral = true;
|
portMappings = [{ From = defaultPort; To = defaultPort; }];
|
||||||
extraFlags = ["--network-namespace-path=/var/run/netns/wg"];
|
|
||||||
|
|
||||||
bindMounts = {
|
|
||||||
"${nixarr.mediaDir}".isReadOnly = false;
|
|
||||||
"${cfg.stateDir}".isReadOnly = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
config = {
|
|
||||||
users.groups.media = {
|
|
||||||
gid = config.users.groups.media.gid;
|
|
||||||
};
|
|
||||||
users.users.radarr = {
|
|
||||||
uid = lib.mkForce config.users.users.radarr.uid;
|
|
||||||
isSystemUser = true;
|
|
||||||
group = "media";
|
|
||||||
};
|
|
||||||
|
|
||||||
# Use systemd-resolved inside the container
|
|
||||||
# Workaround for bug https://github.com/NixOS/nixpkgs/issues/162686
|
|
||||||
networking.useHostResolvConf = lib.mkForce false;
|
|
||||||
services.resolved.enable = true;
|
|
||||||
networking.nameservers = dnsServers;
|
|
||||||
|
|
||||||
services.radarr = {
|
|
||||||
enable = true;
|
|
||||||
group = "media";
|
|
||||||
dataDir = cfg.stateDir;
|
|
||||||
};
|
|
||||||
|
|
||||||
system.stateVersion = "23.11";
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
services.nginx = mkIf cfg.vpn.enable {
|
services.nginx = mkIf cfg.vpn.enable {
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
with lib; let
|
with lib; let
|
||||||
cfg = config.nixarr.readarr;
|
cfg = config.nixarr.readarr;
|
||||||
nixarr = config.nixarr;
|
nixarr = config.nixarr;
|
||||||
dnsServers = config.lib.vpn.dnsServers;
|
|
||||||
in {
|
in {
|
||||||
options.nixarr.readarr = {
|
options.nixarr.readarr = {
|
||||||
enable = mkEnableOption "Enable the Readarr service";
|
enable = mkEnableOption "Enable the Readarr service";
|
||||||
@@ -50,53 +49,15 @@ in {
|
|||||||
dataDir = cfg.stateDir;
|
dataDir = cfg.stateDir;
|
||||||
};
|
};
|
||||||
|
|
||||||
util-nixarr.vpnnamespace.portMappings = [
|
# Enable and specify VPN namespace to confine service in.
|
||||||
(
|
systemd.services.readarr.vpnconfinement = mkIf cfg.vpn.enable {
|
||||||
mkIf cfg.vpn.enable {
|
enable = true;
|
||||||
From = defaultPort;
|
vpnnamespace = "wg";
|
||||||
To = defaultPort;
|
|
||||||
}
|
|
||||||
)
|
|
||||||
];
|
|
||||||
|
|
||||||
systemd.services."container@readarr" = mkIf cfg.vpn.enable {
|
|
||||||
requires = ["wg.service"];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
containers.readarr = mkIf cfg.vpn.enable {
|
# Port mappings
|
||||||
autoStart = true;
|
vpnnamespaces.wg = mkIf cfg.vpn.enable {
|
||||||
ephemeral = true;
|
portMappings = [{ From = defaultPort; To = defaultPort; }];
|
||||||
extraFlags = ["--network-namespace-path=/var/run/netns/wg"];
|
|
||||||
|
|
||||||
bindMounts = {
|
|
||||||
"${nixarr.mediaDir}".isReadOnly = false;
|
|
||||||
"${cfg.stateDir}".isReadOnly = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
config = {
|
|
||||||
users.groups.media = {
|
|
||||||
gid = config.users.groups.media.gid;
|
|
||||||
};
|
|
||||||
users.users.readarr = {
|
|
||||||
uid = lib.mkForce config.users.users.readarr.uid;
|
|
||||||
isSystemUser = true;
|
|
||||||
group = "media";
|
|
||||||
};
|
|
||||||
|
|
||||||
# Use systemd-resolved inside the container
|
|
||||||
# Workaround for bug https://github.com/NixOS/nixpkgs/issues/162686
|
|
||||||
networking.useHostResolvConf = lib.mkForce false;
|
|
||||||
services.resolved.enable = true;
|
|
||||||
networking.nameservers = dnsServers;
|
|
||||||
|
|
||||||
services.readarr = {
|
|
||||||
enable = true;
|
|
||||||
group = "media";
|
|
||||||
dataDir = "${cfg.stateDir}";
|
|
||||||
};
|
|
||||||
|
|
||||||
system.stateVersion = "23.11";
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
services.nginx = mkIf cfg.vpn.enable {
|
services.nginx = mkIf cfg.vpn.enable {
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ with lib; let
|
|||||||
cfg = config.nixarr.sonarr;
|
cfg = config.nixarr.sonarr;
|
||||||
defaultPort = 8989;
|
defaultPort = 8989;
|
||||||
nixarr = config.nixarr;
|
nixarr = config.nixarr;
|
||||||
dnsServers = config.lib.vpn.dnsServers;
|
|
||||||
in {
|
in {
|
||||||
options.nixarr.sonarr = {
|
options.nixarr.sonarr = {
|
||||||
enable = mkOption {
|
enable = mkOption {
|
||||||
@@ -49,60 +48,22 @@ in {
|
|||||||
"d '${cfg.stateDir}' 0700 sonarr root - -"
|
"d '${cfg.stateDir}' 0700 sonarr root - -"
|
||||||
];
|
];
|
||||||
|
|
||||||
services.sonarr = mkIf (!cfg.vpn.enable) {
|
services.sonarr = {
|
||||||
enable = cfg.enable;
|
enable = cfg.enable;
|
||||||
user = "sonarr";
|
user = "sonarr";
|
||||||
group = "media";
|
group = "media";
|
||||||
dataDir = cfg.stateDir;
|
dataDir = cfg.stateDir;
|
||||||
};
|
};
|
||||||
|
|
||||||
util-nixarr.vpnnamespace.portMappings = [
|
# Enable and specify VPN namespace to confine service in.
|
||||||
(mkIf cfg.vpn.enable {
|
systemd.services.sonarr.vpnconfinement = mkIf cfg.vpn.enable {
|
||||||
From = defaultPort;
|
enable = true;
|
||||||
To = defaultPort;
|
vpnnamespace = "wg";
|
||||||
})
|
|
||||||
];
|
|
||||||
|
|
||||||
systemd.services."container@sonarr" = mkIf cfg.vpn.enable {
|
|
||||||
requires = ["wg.service"];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
containers.sonarr = mkIf cfg.vpn.enable {
|
# Port mappings
|
||||||
autoStart = true;
|
vpnnamespaces.wg = mkIf cfg.vpn.enable {
|
||||||
ephemeral = true;
|
portMappings = [{ From = defaultPort; To = defaultPort; }];
|
||||||
extraFlags = ["--network-namespace-path=/var/run/netns/wg"];
|
|
||||||
|
|
||||||
bindMounts = {
|
|
||||||
"${nixarr.mediaDir}".isReadOnly = false;
|
|
||||||
"${cfg.stateDir}".isReadOnly = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
config = {
|
|
||||||
users.groups.media = {
|
|
||||||
gid = config.users.groups.media.gid;
|
|
||||||
};
|
|
||||||
users.users.sonarr = {
|
|
||||||
uid = lib.mkForce config.users.users.sonarr.uid;
|
|
||||||
isSystemUser = true;
|
|
||||||
group = "media";
|
|
||||||
};
|
|
||||||
|
|
||||||
# Use systemd-resolved inside the container
|
|
||||||
# Workaround for bug https://github.com/NixOS/nixpkgs/issues/162686
|
|
||||||
networking.useHostResolvConf = lib.mkForce false;
|
|
||||||
services.resolved.enable = true;
|
|
||||||
networking.nameservers = dnsServers;
|
|
||||||
|
|
||||||
users.groups.media = {};
|
|
||||||
|
|
||||||
services.sonarr = {
|
|
||||||
enable = cfg.enable;
|
|
||||||
group = "media";
|
|
||||||
dataDir = cfg.stateDir;
|
|
||||||
};
|
|
||||||
|
|
||||||
system.stateVersion = "23.11";
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
services.nginx = mkIf cfg.vpn.enable {
|
services.nginx = mkIf cfg.vpn.enable {
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ in {
|
|||||||
|
|
||||||
users.users = mkIf (cfg.user == "cross-seed") {
|
users.users = mkIf (cfg.user == "cross-seed") {
|
||||||
cross-seed = {
|
cross-seed = {
|
||||||
|
isSystemUser = true;
|
||||||
group = cfg.group;
|
group = cfg.group;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
+18
-115
@@ -7,7 +7,6 @@
|
|||||||
with lib; let
|
with lib; let
|
||||||
cfg = config.nixarr.transmission;
|
cfg = config.nixarr.transmission;
|
||||||
nixarr = config.nixarr;
|
nixarr = config.nixarr;
|
||||||
dnsServers = config.lib.vpn.dnsServers;
|
|
||||||
cfg-cross-seed = config.nixarr.transmission.privateTrackers.cross-seed;
|
cfg-cross-seed = config.nixarr.transmission.privateTrackers.cross-seed;
|
||||||
transmissionCrossSeedScript = with builtins; pkgs.writeShellApplication {
|
transmissionCrossSeedScript = with builtins; pkgs.writeShellApplication {
|
||||||
name = "mk-cross-seed-credentials";
|
name = "mk-cross-seed-credentials";
|
||||||
@@ -198,7 +197,7 @@ in {
|
|||||||
];
|
];
|
||||||
|
|
||||||
systemd.tmpfiles.rules = [
|
systemd.tmpfiles.rules = [
|
||||||
"d '${cfg.stateDir}' 0700 torrenter root - -"
|
"d '${cfg.stateDir}' 0700 torrenter root - -"
|
||||||
# This is fixes a bug in nixpks (https://github.com/NixOS/nixpkgs/issues/291883)
|
# This is fixes a bug in nixpks (https://github.com/NixOS/nixpkgs/issues/291883)
|
||||||
"d '${cfg.stateDir}/.config/transmission-daemon' 0700 torrenter root - -"
|
"d '${cfg.stateDir}/.config/transmission-daemon' 0700 torrenter root - -"
|
||||||
] ++ (
|
] ++ (
|
||||||
@@ -230,7 +229,7 @@ in {
|
|||||||
)];
|
)];
|
||||||
};
|
};
|
||||||
|
|
||||||
services.transmission = mkIf (!cfg.vpn.enable) {
|
services.transmission = {
|
||||||
enable = true;
|
enable = true;
|
||||||
user = "torrenter";
|
user = "torrenter";
|
||||||
group = "torrenter";
|
group = "torrenter";
|
||||||
@@ -250,10 +249,11 @@ in {
|
|||||||
watch-dir-enabled = true;
|
watch-dir-enabled = true;
|
||||||
watch-dir = "${nixarr.mediaDir}/torrents/.watch";
|
watch-dir = "${nixarr.mediaDir}/torrents/.watch";
|
||||||
|
|
||||||
rpc-bind-address = "127.0.0.1";
|
rpc-bind-address = if cfg.vpn.enable then "192.168.15.1" else "127.0.0.1";
|
||||||
rpc-port = cfg.uiPort;
|
rpc-port = cfg.uiPort;
|
||||||
rpc-whitelist-enabled = true;
|
# TODO: fix this for ssh tunneling...
|
||||||
rpc-whitelist = "192.168.15.1,127.0.0.1";
|
rpc-whitelist-enabled = false;
|
||||||
|
rpc-whitelist = "192.168.15.1,127.0.0.1,192.168.1.*,192.168.0.*";
|
||||||
rpc-authentication-required = false;
|
rpc-authentication-required = false;
|
||||||
|
|
||||||
blocklist-enabled = true;
|
blocklist-enabled = true;
|
||||||
@@ -269,8 +269,8 @@ in {
|
|||||||
anti-brute-force-enabled = true;
|
anti-brute-force-enabled = true;
|
||||||
anti-brute-force-threshold = 10;
|
anti-brute-force-threshold = 10;
|
||||||
|
|
||||||
script-torrent-done-enabled = true;
|
script-torrent-done-enabled = cfg-cross-seed.enable;
|
||||||
script-torrent-done-filename = getExe transmissionCrossSeedScript;
|
script-torrent-done-filename = if cfg-cross-seed.enable then transmissionCrossSeedScript else null;
|
||||||
|
|
||||||
message-level =
|
message-level =
|
||||||
if cfg.messageLevel == "none"
|
if cfg.messageLevel == "none"
|
||||||
@@ -292,115 +292,18 @@ in {
|
|||||||
// cfg.extraSettings;
|
// cfg.extraSettings;
|
||||||
};
|
};
|
||||||
|
|
||||||
util-nixarr.vpnnamespace = mkIf cfg.vpn.enable {
|
# Enable and specify VPN namespace to confine service in.
|
||||||
portMappings = [
|
systemd.services.transmission.vpnconfinement = mkIf cfg.vpn.enable {
|
||||||
{
|
enable = true;
|
||||||
From = cfg.uiPort;
|
vpnnamespace = "wg";
|
||||||
To = cfg.uiPort;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
openUdpPorts = [cfg.peerPort];
|
|
||||||
openTcpPorts = [cfg.peerPort];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.services."container@transmission" = mkIf cfg.vpn.enable {
|
# Port mappings
|
||||||
requires = ["wg.service"];
|
# TODO: open peerPort
|
||||||
};
|
vpnnamespaces.wg = mkIf cfg.vpn.enable {
|
||||||
|
portMappings = [{ From = cfg.uiPort; To = cfg.uiPort; }];
|
||||||
containers.transmission = mkIf cfg.vpn.enable {
|
#openUdpPorts = [cfg.peerPort];
|
||||||
autoStart = true;
|
#openTcpPorts = [cfg.peerPort];
|
||||||
ephemeral = true;
|
|
||||||
extraFlags = ["--network-namespace-path=/var/run/netns/wg"];
|
|
||||||
|
|
||||||
bindMounts = {
|
|
||||||
"${nixarr.mediaDir}/torrents".isReadOnly = false;
|
|
||||||
"/var/lib/transmission" = {
|
|
||||||
hostPath = cfg.stateDir;
|
|
||||||
isReadOnly = false;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config = {
|
|
||||||
users.groups.torrenter = {
|
|
||||||
gid = config.users.groups.torrenter.gid;
|
|
||||||
};
|
|
||||||
users.users.torrenter = {
|
|
||||||
uid = lib.mkForce config.users.users.torrenter.uid;
|
|
||||||
isSystemUser = true;
|
|
||||||
group = "torrenter";
|
|
||||||
};
|
|
||||||
|
|
||||||
# Use systemd-resolved inside the container
|
|
||||||
# Workaround for bug https://github.com/NixOS/nixpkgs/issues/162686
|
|
||||||
networking.useHostResolvConf = lib.mkForce false;
|
|
||||||
services.resolved.enable = true;
|
|
||||||
networking.nameservers = dnsServers;
|
|
||||||
|
|
||||||
systemd.services.transmission.serviceConfig = {
|
|
||||||
RootDirectoryStartOnly = lib.mkForce false;
|
|
||||||
RootDirectory = lib.mkForce "";
|
|
||||||
};
|
|
||||||
|
|
||||||
services.transmission = {
|
|
||||||
enable = true;
|
|
||||||
user = "torrenter";
|
|
||||||
group = "torrenter";
|
|
||||||
webHome =
|
|
||||||
if cfg.flood.enable
|
|
||||||
then pkgs.flood-for-transmission
|
|
||||||
else null;
|
|
||||||
package = pkgs.transmission_4;
|
|
||||||
openRPCPort = true;
|
|
||||||
openPeerPorts = true;
|
|
||||||
settings =
|
|
||||||
{
|
|
||||||
download-dir = "${nixarr.mediaDir}/torrents";
|
|
||||||
incomplete-dir-enabled = true;
|
|
||||||
incomplete-dir = "${nixarr.mediaDir}/torrents/.incomplete";
|
|
||||||
watch-dir-enabled = true;
|
|
||||||
watch-dir = "${nixarr.mediaDir}/torrents/.watch";
|
|
||||||
|
|
||||||
rpc-bind-address = "192.168.15.1";
|
|
||||||
rpc-port = cfg.uiPort;
|
|
||||||
rpc-whitelist-enabled = false;
|
|
||||||
rpc-whitelist = "192.168.15.1,127.0.0.1";
|
|
||||||
rpc-authentication-required = false;
|
|
||||||
|
|
||||||
blocklist-enabled = true;
|
|
||||||
blocklist-url = "https://github.com/Naunter/BT_BlockLists/raw/master/bt_blocklists.gz";
|
|
||||||
|
|
||||||
peer-port = cfg.peerPort;
|
|
||||||
dht-enabled = !cfg.privateTrackers.disableDhtPex;
|
|
||||||
pex-enabled = !cfg.privateTrackers.disableDhtPex;
|
|
||||||
utp-enabled = false;
|
|
||||||
encryption = 1;
|
|
||||||
port-forwarding-enabled = false;
|
|
||||||
|
|
||||||
anti-brute-force-enabled = true;
|
|
||||||
anti-brute-force-threshold = 10;
|
|
||||||
|
|
||||||
# 0 = None, 1 = Critical, 2 = Error, 3 = Warn, 4 = Info, 5 = Debug, 6 = Trace
|
|
||||||
message-level = 3;
|
|
||||||
}
|
|
||||||
// cfg.extraSettings;
|
|
||||||
};
|
|
||||||
|
|
||||||
environment.systemPackages = with pkgs; [
|
|
||||||
curl
|
|
||||||
wget
|
|
||||||
util-linux
|
|
||||||
unixtools.ping
|
|
||||||
coreutils
|
|
||||||
curl
|
|
||||||
bash
|
|
||||||
libressl
|
|
||||||
netcat-gnu
|
|
||||||
openresolv
|
|
||||||
dig
|
|
||||||
];
|
|
||||||
|
|
||||||
system.stateVersion = "23.11";
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
services.nginx = mkIf cfg.vpn.enable {
|
services.nginx = mkIf cfg.vpn.enable {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
./upnp
|
./upnp
|
||||||
./vpnNamespace
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,369 +0,0 @@
|
|||||||
# Thank you Maroka-chan <3
|
|
||||||
{
|
|
||||||
lib,
|
|
||||||
pkgs,
|
|
||||||
config,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
with builtins;
|
|
||||||
with lib; let
|
|
||||||
cfg = config.util-nixarr.vpnnamespace;
|
|
||||||
in {
|
|
||||||
options.util-nixarr.vpnnamespace = {
|
|
||||||
enable = mkEnableOption ''
|
|
||||||
Whether to enable the VPN namespace.
|
|
||||||
|
|
||||||
To access the namespace a veth pair is used to
|
|
||||||
connect the vpn namespace and the default namespace
|
|
||||||
through a linux bridge. One end of the pair is
|
|
||||||
connected to the linux bridge on the default namespace.
|
|
||||||
The other end is connected to the vpn namespace.
|
|
||||||
|
|
||||||
Systemd services can be run within the namespace by
|
|
||||||
adding these options:
|
|
||||||
|
|
||||||
bindsTo = [ "netns@wg.service" ];
|
|
||||||
requires = [ "network-online.target" ];
|
|
||||||
after = [ "wg.service" ];
|
|
||||||
serviceConfig = {
|
|
||||||
NetworkNamespacePath = "/var/run/netns/wg";
|
|
||||||
};
|
|
||||||
'';
|
|
||||||
|
|
||||||
accessibleFrom = mkOption {
|
|
||||||
type = types.listOf types.str;
|
|
||||||
default = [];
|
|
||||||
description = lib.mdDoc ''
|
|
||||||
Subnets or specific addresses that the namespace should be accessible to.
|
|
||||||
'';
|
|
||||||
example = [
|
|
||||||
"10.0.2.0/24"
|
|
||||||
"192.168.1.27"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
namespaceAddress = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "192.168.15.1";
|
|
||||||
description = lib.mdDoc ''
|
|
||||||
The address of the veth interface connected to the vpn namespace.
|
|
||||||
|
|
||||||
This is the address used to reach the vpn namespace from other
|
|
||||||
namespaces connected to the linux bridge.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
bridgeAddress = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "192.168.15.5";
|
|
||||||
description = lib.mdDoc ''
|
|
||||||
The address of the linux bridge on the default namespace.
|
|
||||||
|
|
||||||
The linux bridge sits on the default namespace and
|
|
||||||
needs an address to make communication between the
|
|
||||||
default namespace and other namespaces on the
|
|
||||||
bridge possible.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
wireguardAddressPath = mkOption {
|
|
||||||
type = types.path;
|
|
||||||
default = "";
|
|
||||||
description = lib.mdDoc ''
|
|
||||||
The address for the wireguard interface.
|
|
||||||
It is a path to a file containing the address.
|
|
||||||
This is done so the whole wireguard config can be specified
|
|
||||||
in a secret file.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
wireguardConfigFile = mkOption {
|
|
||||||
type = types.path;
|
|
||||||
default = "/etc/wireguard/wg0.conf";
|
|
||||||
description = lib.mdDoc ''
|
|
||||||
Path to the wireguard config to use.
|
|
||||||
|
|
||||||
Note that this _is_ a wg-quick config.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
portMappings = mkOption {
|
|
||||||
type = with types; listOf (attrsOf port);
|
|
||||||
default = [];
|
|
||||||
description = lib.mdDoc ''
|
|
||||||
A list of pairs mapping a port from the host to a port in the namespace.
|
|
||||||
'';
|
|
||||||
example = [
|
|
||||||
{
|
|
||||||
From = 80;
|
|
||||||
To = 80;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
dnsServers = mkOption {
|
|
||||||
type = with types; nullOr (listOf str);
|
|
||||||
default = [];
|
|
||||||
description = lib.mdDoc ''
|
|
||||||
DNS servers to append to any found in the wg-quick config file.
|
|
||||||
'';
|
|
||||||
example = ["1.1.1.2"];
|
|
||||||
};
|
|
||||||
|
|
||||||
openTcpPorts = mkOption {
|
|
||||||
type = with types; listOf port;
|
|
||||||
default = [];
|
|
||||||
description = lib.mdDoc ''
|
|
||||||
What TCP ports to allow incoming traffic from. You need this if
|
|
||||||
you're port forwarding on your VPN provider.
|
|
||||||
'';
|
|
||||||
example = [46382 38473];
|
|
||||||
};
|
|
||||||
|
|
||||||
openUdpPorts = mkOption {
|
|
||||||
type = with types; listOf port;
|
|
||||||
default = [];
|
|
||||||
description = lib.mdDoc ''
|
|
||||||
What UDP ports to allow incoming traffic from. You need this if
|
|
||||||
you're port forwarding on your VPN provider.
|
|
||||||
'';
|
|
||||||
example = [46382 38473];
|
|
||||||
};
|
|
||||||
|
|
||||||
vpnTestService = {
|
|
||||||
enable = mkEnableOption "Enable the vpn test service.";
|
|
||||||
|
|
||||||
port = mkOption {
|
|
||||||
type = types.port;
|
|
||||||
default = [12300];
|
|
||||||
description = lib.mdDoc ''
|
|
||||||
The port that the vpn test service listens to.
|
|
||||||
'';
|
|
||||||
example = [58403];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config = let
|
|
||||||
headMay = list:
|
|
||||||
if list == []
|
|
||||||
then null
|
|
||||||
else head list;
|
|
||||||
# Checks if string is ipv4, from SO, hope it works well
|
|
||||||
# https://stackoverflow.com/questions/53497/regular-expression-that-matches-valid-ipv6-addresses
|
|
||||||
isIpv4 = address: let
|
|
||||||
pat = "((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])?/?[0-9]?[0-9]";
|
|
||||||
regex = match pat address;
|
|
||||||
in
|
|
||||||
regex != null;
|
|
||||||
# Checks if string is ipv6, from SO, hope it works well
|
|
||||||
# https://stackoverflow.com/questions/53497/regular-expression-that-matches-valid-ipv6-addresses
|
|
||||||
isIpv6 = address: let
|
|
||||||
pat = "(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))";
|
|
||||||
regex = match pat address;
|
|
||||||
in
|
|
||||||
regex != null;
|
|
||||||
isIp = ip: (isIpv4 ip || isIpv6 ip);
|
|
||||||
in
|
|
||||||
mkIf cfg.enable {
|
|
||||||
lib.vpn = {
|
|
||||||
dnsServers = let
|
|
||||||
lines = split "\n" (readFile cfg.wireguardConfigFile);
|
|
||||||
dnsLine = headMay (filter (x: typeOf x == "string" && match ".*DNS.*" x != null) lines);
|
|
||||||
in
|
|
||||||
if dnsLine == null
|
|
||||||
then []
|
|
||||||
else let
|
|
||||||
ipsUnsplit = head (match "DNS ?=(.*)" dnsLine);
|
|
||||||
in
|
|
||||||
if ipsUnsplit == null
|
|
||||||
then []
|
|
||||||
else let
|
|
||||||
ips = filter (x: typeOf x == "string") (split "," ipsUnsplit);
|
|
||||||
ipsNoSpaces = map (replaceStrings [" "] [""]) ips;
|
|
||||||
correctIps = filter isIp ipsNoSpaces;
|
|
||||||
in
|
|
||||||
assert (correctIps != []) || abort "There must be at least 1 DNS server set."; correctIps;
|
|
||||||
};
|
|
||||||
|
|
||||||
boot.kernel.sysctl."net.ipv4.ip_forward" = 1;
|
|
||||||
|
|
||||||
systemd.services = {
|
|
||||||
"netns@" = {
|
|
||||||
description = "%I network namespace";
|
|
||||||
before = ["network.target"];
|
|
||||||
serviceConfig = {
|
|
||||||
Type = "oneshot";
|
|
||||||
RemainAfterExit = true;
|
|
||||||
ExecStart = "${pkgs.iproute2}/bin/ip netns add %I";
|
|
||||||
ExecStop = "${pkgs.iproute2}/bin/ip netns del %I";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
wg = {
|
|
||||||
description = "wg network interface";
|
|
||||||
bindsTo = ["netns@wg.service"];
|
|
||||||
requires = ["network-online.target"];
|
|
||||||
after = ["netns@wg.service"];
|
|
||||||
wantedBy = ["multi-user.target"];
|
|
||||||
|
|
||||||
serviceConfig = let
|
|
||||||
lines = split "\n" (readFile cfg.wireguardConfigFile);
|
|
||||||
addrLine = headMay (filter (x: typeOf x == "string" && match ".*Address.*" x != null) lines);
|
|
||||||
in
|
|
||||||
if addrLine == null
|
|
||||||
then []
|
|
||||||
else let
|
|
||||||
ipsUnsplit = head (match "Address ?=(.*)" addrLine);
|
|
||||||
in
|
|
||||||
if ipsUnsplit == null
|
|
||||||
then []
|
|
||||||
else let
|
|
||||||
ips = filter (x: typeOf x == "string") (split "," ipsUnsplit);
|
|
||||||
ipsNoSpaces = map (replaceStrings [" "] [""]) ips;
|
|
||||||
wgIpv4Address = headMay (filter isIpv4 ipsNoSpaces);
|
|
||||||
|
|
||||||
vpn-namespace = pkgs.writeShellApplication {
|
|
||||||
name = "vpn-namespace";
|
|
||||||
|
|
||||||
runtimeInputs = with pkgs; [iproute2 wireguard-tools iptables];
|
|
||||||
|
|
||||||
text =
|
|
||||||
''
|
|
||||||
# Set up the wireguard interface
|
|
||||||
tmpdir=$(mktemp -d)
|
|
||||||
cat ${cfg.wireguardConfigFile} > "$tmpdir/wg.conf"
|
|
||||||
|
|
||||||
# Get dns servers
|
|
||||||
grep "DNS =" "$tmpdir/wg.conf" | sed 's/DNS =//g' | sed 's/,/\n/g' | sed 's/ //g' | sed 's/^/nameserver: /g' > "$tmpdir/resolv.conf"
|
|
||||||
|
|
||||||
ip link add wg0 type wireguard
|
|
||||||
ip link set wg0 netns wg
|
|
||||||
ip -n wg address add "${wgIpv4Address}" dev wg0
|
|
||||||
ip netns exec wg wg setconf wg0 <(wg-quick strip "$tmpdir/wg.conf")
|
|
||||||
ip -n wg link set wg0 up
|
|
||||||
ip -n wg route add default dev wg0
|
|
||||||
|
|
||||||
# Start the loopback interface
|
|
||||||
ip -n wg link set dev lo up
|
|
||||||
|
|
||||||
# Create a bridge
|
|
||||||
ip link add v-net-0 type bridge
|
|
||||||
ip addr add ${cfg.bridgeAddress}/24 dev v-net-0
|
|
||||||
ip link set dev v-net-0 up
|
|
||||||
|
|
||||||
# Set up veth pair to link namespace with host network
|
|
||||||
ip link add veth-vpn-br type veth peer name veth-vpn netns wg
|
|
||||||
ip link set veth-vpn-br master v-net-0
|
|
||||||
|
|
||||||
ip -n wg addr add ${cfg.namespaceAddress}/24 dev veth-vpn
|
|
||||||
ip -n wg link set dev veth-vpn up
|
|
||||||
|
|
||||||
echo "setting dns"
|
|
||||||
# DNS test, see:
|
|
||||||
# https://www.man7.org/linux/man-pages/man8/wg-quick.8.html
|
|
||||||
# Absolutely no luck...
|
|
||||||
#echo "nameserver 1.1.1.1" | ip netns exec wg resolvconf -a wg0 -m 0 -x
|
|
||||||
|
|
||||||
echo "Hello test"
|
|
||||||
''
|
|
||||||
# Add routes to make the namespace accessible
|
|
||||||
+ strings.concatMapStrings (
|
|
||||||
x:
|
|
||||||
"ip -n wg route add ${x} via ${cfg.bridgeAddress}" + "\n"
|
|
||||||
)
|
|
||||||
cfg.accessibleFrom
|
|
||||||
# Add prerouting rules
|
|
||||||
+ strings.concatMapStrings (
|
|
||||||
x:
|
|
||||||
"iptables -t nat -A PREROUTING -p tcp --dport ${builtins.toString x.From} -j DNAT --to-destination ${cfg.namespaceAddress}:${builtins.toString x.To}"
|
|
||||||
+ "\n"
|
|
||||||
)
|
|
||||||
cfg.portMappings
|
|
||||||
# Allow VPN TCP ports
|
|
||||||
+ strings.concatMapStrings (
|
|
||||||
x:
|
|
||||||
"ip netns exec wg iptables -I INPUT -p tcp --dport ${builtins.toString x} -j ACCEPT"
|
|
||||||
+ "\n"
|
|
||||||
)
|
|
||||||
cfg.openTcpPorts
|
|
||||||
# Allow VPN UDP ports
|
|
||||||
+ strings.concatMapStrings (
|
|
||||||
x:
|
|
||||||
"ip netns exec wg iptables -I INPUT -p udp --dport ${builtins.toString x} -j ACCEPT"
|
|
||||||
+ "\n"
|
|
||||||
)
|
|
||||||
cfg.openUdpPorts;
|
|
||||||
};
|
|
||||||
in
|
|
||||||
assert (wgIpv4Address != null) || abort "No address found in config file."; {
|
|
||||||
Type = "oneshot";
|
|
||||||
RemainAfterExit = true;
|
|
||||||
ExecStart = "${vpn-namespace}/bin/vpn-namespace";
|
|
||||||
|
|
||||||
ExecStopPost = with pkgs;
|
|
||||||
writers.writeBash "wg-down" (''
|
|
||||||
${iproute2}/bin/ip -n wg route del default dev wg0
|
|
||||||
${iproute2}/bin/ip -n wg link del wg0
|
|
||||||
${iproute2}/bin/ip -n wg link del veth-vpn
|
|
||||||
${iproute2}/bin/ip link del v-net-0
|
|
||||||
|
|
||||||
# DNS test, see:
|
|
||||||
# https://www.man7.org/linux/man-pages/man8/wg-quick.8.html
|
|
||||||
#${iproute2}/bin/ip netns exec wg resolvconf -d wg0
|
|
||||||
''
|
|
||||||
# Delete prerouting rules
|
|
||||||
+ strings.concatMapStrings (x: "${iptables}/bin/iptables -t nat -D PREROUTING -p tcp --dport ${builtins.toString x.From} -j DNAT --to-destination ${cfg.namespaceAddress}:${builtins.toString x.To}" + "\n") cfg.portMappings);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
vpn-test-service = {
|
|
||||||
enable = cfg.vpnTestService.enable;
|
|
||||||
|
|
||||||
script = let
|
|
||||||
vpn-test = pkgs.writeShellApplication {
|
|
||||||
name = "vpn-test";
|
|
||||||
|
|
||||||
runtimeInputs = with pkgs; [util-linux unixtools.ping coreutils curl bash libressl netcat-gnu openresolv dig];
|
|
||||||
|
|
||||||
text = ''
|
|
||||||
cd "$(mktemp -d)"
|
|
||||||
|
|
||||||
# Print resolv.conf
|
|
||||||
echo "/etc/resolv.conf contains:"
|
|
||||||
cat /etc/resolv.conf
|
|
||||||
|
|
||||||
# Query resolvconf
|
|
||||||
echo "resolvconf output:"
|
|
||||||
resolvconf -l
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Get ip
|
|
||||||
echo "Getting IP:"
|
|
||||||
curl -s ipinfo.io
|
|
||||||
|
|
||||||
cat /etc/test.file
|
|
||||||
|
|
||||||
echo -ne "DNS leak test:"
|
|
||||||
curl -s https://raw.githubusercontent.com/macvk/dnsleaktest/b03ab54d574adbe322ca48cbcb0523be720ad38d/dnsleaktest.sh -o dnsleaktest.sh
|
|
||||||
chmod +x dnsleaktest.sh
|
|
||||||
./dnsleaktest.sh
|
|
||||||
|
|
||||||
echo "starting netcat on port ${builtins.toString cfg.vpnTestService.port}:"
|
|
||||||
nc -vnlp ${builtins.toString cfg.vpnTestService.port}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
in "${vpn-test}/bin/vpn-test";
|
|
||||||
|
|
||||||
bindsTo = ["netns@wg.service"];
|
|
||||||
requires = ["network-online.target"];
|
|
||||||
after = ["wg.service"];
|
|
||||||
serviceConfig = {
|
|
||||||
User = "prowlarr";
|
|
||||||
NetworkNamespacePath = "/var/run/netns/wg";
|
|
||||||
BindReadOnlyPaths = ["/etc/netns/wg/resolv.conf:/etc/resolv.conf:norbind" "/data/test.file:/etc/test.file:norbind"];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user