format
This commit is contained in:
Generated
+192
@@ -0,0 +1,192 @@
|
|||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"devshell": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1705332421,
|
||||||
|
"narHash": "sha256-USpGLPme1IuqG78JNqSaRabilwkCyHmVWY0M9vYyqEA=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "devshell",
|
||||||
|
"rev": "83cb93d6d063ad290beee669f4badf9914cc16ec",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "devshell",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-parts": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs-lib": [
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1706830856,
|
||||||
|
"narHash": "sha256-a0NYyp+h9hlb7ddVz4LUn1vT/PLwqfrWYcHMvFB1xYg=",
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "flake-parts",
|
||||||
|
"rev": "b253292d9c0a5ead9bc98c4e9a26c6312e27d69f",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "flake-parts",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-root": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1692742795,
|
||||||
|
"narHash": "sha256-f+Y0YhVCIJ06LemO+3Xx00lIcqQxSKJHXT/yk1RTKxw=",
|
||||||
|
"owner": "srid",
|
||||||
|
"repo": "flake-root",
|
||||||
|
"rev": "d9a70d9c7a5fd7f3258ccf48da9335e9b47c3937",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "srid",
|
||||||
|
"repo": "flake-root",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1701680307,
|
||||||
|
"narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"home-manager": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1708294481,
|
||||||
|
"narHash": "sha256-DZtxmeb4OR7iCaKUUuq05ADV2rX8WReZEF7Tq//W0+Y=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "home-manager",
|
||||||
|
"rev": "a54e05bc12d88ff2df941d0dc1183cb5235fa438",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "home-manager",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1708118438,
|
||||||
|
"narHash": "sha256-kk9/0nuVgA220FcqH/D2xaN6uGyHp/zoxPNUmPCMmEE=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "5863c27340ba4de8f83e7e3c023b9599c3cb3c80",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs-flood": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1701810456,
|
||||||
|
"narHash": "sha256-jOl3DMrDgJYZeE/w5p7zQe+Ift7R307mXG/tyhH8WHE=",
|
||||||
|
"owner": "3JlOy-PYCCKUi",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "aff5b3aa1a95876fd426ab024d68ab2d87b0ebbd",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "3JlOy-PYCCKUi",
|
||||||
|
"ref": "flood-module",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs_2": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1708407374,
|
||||||
|
"narHash": "sha256-EECzarm+uqnNDCwaGg/ppXCO11qibZ1iigORShkkDf0=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "f33dd27a47ebdf11dc8a5eb05e7c8fbdaf89e73f",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nixos",
|
||||||
|
"ref": "nixpkgs-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"devshell": "devshell",
|
||||||
|
"flake-parts": "flake-parts",
|
||||||
|
"flake-root": "flake-root",
|
||||||
|
"home-manager": "home-manager",
|
||||||
|
"nixpkgs": "nixpkgs_2",
|
||||||
|
"nixpkgs-flood": "nixpkgs-flood",
|
||||||
|
"treefmt-nix": "treefmt-nix"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"treefmt-nix": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1708335038,
|
||||||
|
"narHash": "sha256-ETLZNFBVCabo7lJrpjD6cAbnE11eDOjaQnznmg/6hAE=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "treefmt-nix",
|
||||||
|
"rev": "e504621290a1fd896631ddbc5e9c16f4366c9f65",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "treefmt-nix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
description = "Kirk nix modules";
|
description = "The servarr.enable nixos module";
|
||||||
|
|
||||||
nixConfig = {
|
nixConfig = {
|
||||||
extra-substituters = ["https://nix-community.cachix.org"];
|
extra-substituters = ["https://nix-community.cachix.org"];
|
||||||
@@ -46,12 +46,8 @@
|
|||||||
|
|
||||||
flake = {
|
flake = {
|
||||||
nixosModules = rec {
|
nixosModules = rec {
|
||||||
kirk = import ./nixos;
|
servarr = import ./servarr;
|
||||||
default = kirk;
|
default = servarr;
|
||||||
};
|
|
||||||
homeManagerModules = rec {
|
|
||||||
kirk = import ./home-manager;
|
|
||||||
default = kirk;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -71,8 +67,8 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
packages = {
|
packages = {
|
||||||
docs = pkgs.callPackage ./mkDocs.nix { inherit inputs; };
|
docs = pkgs.callPackage ./mkDocs.nix {inherit inputs;};
|
||||||
hugo = pkgs.callPackage ./mkHugo.nix { inherit inputs; };
|
hugo = pkgs.callPackage ./mkHugo.nix {inherit inputs;};
|
||||||
};
|
};
|
||||||
|
|
||||||
devshells.default = {
|
devshells.default = {
|
||||||
@@ -89,20 +85,4 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
# outputs = {
|
|
||||||
# self,
|
|
||||||
# }: {
|
|
||||||
# nixosModules.kirk = import ./nixos;
|
|
||||||
# nixosModules.default = self.nixosModules.kirk;
|
|
||||||
#
|
|
||||||
# homeManagerModules.kirk = import ./home-manager;
|
|
||||||
# homeManagerModules.default = self.homeManagerModules.kirk;
|
|
||||||
#
|
|
||||||
# # TODO: Find a way to generate documentation from modules using the same
|
|
||||||
# # tools as nixos. See ./mkDocs.nix
|
|
||||||
#
|
|
||||||
# #packages.x86_64-linux.mkdocs = {};
|
|
||||||
# #defaultPackage.x86_64-linux = self.packages.x86_64-linux.report;
|
|
||||||
# };
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,7 +55,6 @@
|
|||||||
optionsDocNixos = nixosOptionsDoc {
|
optionsDocNixos = nixosOptionsDoc {
|
||||||
inherit (evalNixos) options;
|
inherit (evalNixos) options;
|
||||||
};
|
};
|
||||||
|
|
||||||
in
|
in
|
||||||
# create a derivation for capturing the markdown output
|
# create a derivation for capturing the markdown output
|
||||||
runCommand "options-doc.md" {} ''
|
runCommand "options-doc.md" {} ''
|
||||||
|
|||||||
+11
-12
@@ -1,12 +1,11 @@
|
|||||||
{ pkgs, ... }:
|
{pkgs, ...}:
|
||||||
|
pkgs.writeShellApplication {
|
||||||
pkgs.writeShellApplication {
|
name = "my-script";
|
||||||
name = "my-script";
|
runtimeInputs = with pkgs; [hugo];
|
||||||
runtimeInputs = with pkgs; [ hugo ];
|
text = ''
|
||||||
text = ''
|
cat hugo/content/header.md result/home.md | sed "s/DATE-TIMESTAMP/$(date -u +%Y-%m-%d)/g" > hugo/content/home-manager/index.md
|
||||||
cat hugo/content/header.md result/home.md | sed "s/DATE-TIMESTAMP/$(date -u +%Y-%m-%d)/g" > hugo/content/home-manager/index.md
|
cat hugo/content/header.md result/nixos.md | sed "s/DATE-TIMESTAMP/$(date -u +%Y-%m-%d)/g" > hugo/content/nixos/index.md
|
||||||
cat hugo/content/header.md result/nixos.md | sed "s/DATE-TIMESTAMP/$(date -u +%Y-%m-%d)/g" > hugo/content/nixos/index.md
|
cd hugo
|
||||||
cd hugo
|
hugo
|
||||||
hugo
|
'';
|
||||||
'';
|
}
|
||||||
}
|
|
||||||
|
|||||||
+4
-3
@@ -14,6 +14,7 @@ in {
|
|||||||
./sonarr
|
./sonarr
|
||||||
./prowlarr
|
./prowlarr
|
||||||
./transmission
|
./transmission
|
||||||
|
../util
|
||||||
];
|
];
|
||||||
|
|
||||||
options.kirk.servarr = {
|
options.kirk.servarr = {
|
||||||
@@ -71,7 +72,7 @@ in {
|
|||||||
Extra DNS servers for the VPN. If your wg config has a DNS field,
|
Extra DNS servers for the VPN. If your wg config has a DNS field,
|
||||||
then this should not be necessary.
|
then this should not be necessary.
|
||||||
'';
|
'';
|
||||||
example = [ "1.1.1.2" ];
|
example = ["1.1.1.2"];
|
||||||
};
|
};
|
||||||
|
|
||||||
vpnTestService = {
|
vpnTestService = {
|
||||||
@@ -95,7 +96,7 @@ in {
|
|||||||
if you're port forwarding on your VPN provider and you're setting
|
if you're port forwarding on your VPN provider and you're setting
|
||||||
up services that is not covered in by this module.
|
up services that is not covered in by this module.
|
||||||
'';
|
'';
|
||||||
example = [ 46382 38473 ];
|
example = [46382 38473];
|
||||||
};
|
};
|
||||||
|
|
||||||
openUdpPorts = mkOption {
|
openUdpPorts = mkOption {
|
||||||
@@ -106,7 +107,7 @@ in {
|
|||||||
if you're port forwarding on your VPN provider and you're setting
|
if you're port forwarding on your VPN provider and you're setting
|
||||||
up services that is not covered in by this module.
|
up services that is not covered in by this module.
|
||||||
'';
|
'';
|
||||||
example = [ 46382 38473 ];
|
example = [46382 38473];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -48,90 +48,95 @@ in {
|
|||||||
#assert (!(cfg.useVpn && cfg.nginx.enable)) || abort "useVpn not compatible with nginx.enable.";
|
#assert (!(cfg.useVpn && cfg.nginx.enable)) || abort "useVpn not compatible with nginx.enable.";
|
||||||
#assert (cfg.nginx.enable -> (cfg.nginx.domainName != null && cfg.nginx.acmeMail != null)) || abort "Both nginx.domain and nginx.acmeMail needs to be set if nginx.enable is set.";
|
#assert (cfg.nginx.enable -> (cfg.nginx.domainName != null && cfg.nginx.acmeMail != null)) || abort "Both nginx.domain and nginx.acmeMail needs to be set if nginx.enable is set.";
|
||||||
mkIf cfg.enable
|
mkIf cfg.enable
|
||||||
{
|
{
|
||||||
services.jellyfin.enable = cfg.enable;
|
services.jellyfin.enable = cfg.enable;
|
||||||
|
|
||||||
networking.firewall.allowedTCPPorts = if cfg.nginx.enable then [
|
networking.firewall.allowedTCPPorts =
|
||||||
80 # http
|
if cfg.nginx.enable
|
||||||
443 # https
|
then [
|
||||||
] else [];
|
80 # http
|
||||||
|
443 # https
|
||||||
|
]
|
||||||
|
else [];
|
||||||
|
|
||||||
services.nginx = mkIf (cfg.nginx.enable || cfg.useVpn) {
|
services.nginx = mkIf (cfg.nginx.enable || cfg.useVpn) {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|
||||||
recommendedTlsSettings = true;
|
recommendedTlsSettings = true;
|
||||||
recommendedOptimisation = true;
|
recommendedOptimisation = true;
|
||||||
recommendedGzipSettings = true;
|
recommendedGzipSettings = true;
|
||||||
|
|
||||||
virtualHosts."${builtins.replaceStrings ["\n"] [""] cfg.nginx.domainName}" = mkIf cfg.nginx.enable {
|
virtualHosts."${builtins.replaceStrings ["\n"] [""] cfg.nginx.domainName}" = mkIf cfg.nginx.enable {
|
||||||
enableACME = true;
|
enableACME = true;
|
||||||
forceSSL = true;
|
forceSSL = true;
|
||||||
locations."/" = {
|
locations."/" = {
|
||||||
recommendedProxySettings = true;
|
recommendedProxySettings = true;
|
||||||
proxyWebsockets = true;
|
proxyWebsockets = true;
|
||||||
proxyPass = "http://127.0.0.1:${builtins.toString defaultPort}";
|
proxyPass = "http://127.0.0.1:${builtins.toString defaultPort}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
virtualHosts."127.0.0.1:${builtins.toString defaultPort}" = mkIf cfg.useVpn {
|
||||||
|
listen = [
|
||||||
|
{
|
||||||
|
addr = "0.0.0.0";
|
||||||
|
port = defaultPort;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
locations."/" = {
|
||||||
|
recommendedProxySettings = true;
|
||||||
|
proxyWebsockets = true;
|
||||||
|
proxyPass = "http://192.168.15.1:${builtins.toString defaultPort}";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
virtualHosts."127.0.0.1:${builtins.toString defaultPort}" = mkIf cfg.useVpn {
|
security.acme = mkIf cfg.nginx.enable {
|
||||||
listen = [
|
acceptTerms = true;
|
||||||
{
|
defaults.email = cfg.nginx.acmeMail;
|
||||||
addr = "0.0.0.0";
|
};
|
||||||
port = defaultPort;
|
|
||||||
|
kirk.vpnnamespace.portMappings = [
|
||||||
|
(
|
||||||
|
mkIf cfg.useVpn {
|
||||||
|
From = defaultPort;
|
||||||
|
To = defaultPort;
|
||||||
}
|
}
|
||||||
];
|
)
|
||||||
locations."/" = {
|
];
|
||||||
recommendedProxySettings = true;
|
|
||||||
proxyWebsockets = true;
|
containers.jellyfin = mkIf cfg.useVpn {
|
||||||
proxyPass = "http://192.168.15.1:${builtins.toString defaultPort}";
|
autoStart = true;
|
||||||
|
ephemeral = true;
|
||||||
|
extraFlags = ["--network-namespace-path=/var/run/netns/wg"];
|
||||||
|
|
||||||
|
bindMounts = {
|
||||||
|
"${servarr.mediaDir}/library".isReadOnly = false;
|
||||||
|
"${cfg.stateDir}".isReadOnly = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
users.groups.jellyfin = {};
|
||||||
|
users.users.jellyfin = {
|
||||||
|
uid = lib.mkForce config.users.users.jellyfin.uid;
|
||||||
|
isSystemUser = true;
|
||||||
|
group = "jellyfin";
|
||||||
|
};
|
||||||
|
|
||||||
|
# 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;
|
||||||
|
group = "jellyfin";
|
||||||
|
dataDir = "${cfg.stateDir}";
|
||||||
|
};
|
||||||
|
|
||||||
|
system.stateVersion = "23.11";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
security.acme = mkIf cfg.nginx.enable {
|
|
||||||
acceptTerms = true;
|
|
||||||
defaults.email = cfg.nginx.acmeMail;
|
|
||||||
};
|
|
||||||
|
|
||||||
kirk.vpnnamespace.portMappings = [(
|
|
||||||
mkIf cfg.useVpn {
|
|
||||||
From = defaultPort;
|
|
||||||
To = defaultPort;
|
|
||||||
}
|
|
||||||
)];
|
|
||||||
|
|
||||||
containers.jellyfin = mkIf cfg.useVpn {
|
|
||||||
autoStart = true;
|
|
||||||
ephemeral = true;
|
|
||||||
extraFlags = [ "--network-namespace-path=/var/run/netns/wg" ];
|
|
||||||
|
|
||||||
bindMounts = {
|
|
||||||
"${servarr.mediaDir}/library".isReadOnly = false;
|
|
||||||
"${cfg.stateDir}".isReadOnly = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
config = {
|
|
||||||
users.groups.jellyfin = {};
|
|
||||||
users.users.jellyfin = {
|
|
||||||
uid = lib.mkForce config.users.users.jellyfin.uid;
|
|
||||||
isSystemUser = true;
|
|
||||||
group = "jellyfin";
|
|
||||||
};
|
|
||||||
|
|
||||||
# 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;
|
|
||||||
group = "jellyfin";
|
|
||||||
dataDir = "${cfg.stateDir}";
|
|
||||||
};
|
|
||||||
|
|
||||||
system.stateVersion = "23.11";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,17 +35,19 @@ in {
|
|||||||
dataDir = cfg.stateDir;
|
dataDir = cfg.stateDir;
|
||||||
};
|
};
|
||||||
|
|
||||||
kirk.vpnnamespace.portMappings = [(
|
kirk.vpnnamespace.portMappings = [
|
||||||
mkIf cfg.useVpn {
|
(
|
||||||
From = defaultPort;
|
mkIf cfg.useVpn {
|
||||||
To = defaultPort;
|
From = defaultPort;
|
||||||
}
|
To = defaultPort;
|
||||||
)];
|
}
|
||||||
|
)
|
||||||
|
];
|
||||||
|
|
||||||
containers.lidarr= mkIf cfg.useVpn {
|
containers.lidarr = mkIf cfg.useVpn {
|
||||||
autoStart = true;
|
autoStart = true;
|
||||||
ephemeral = true;
|
ephemeral = true;
|
||||||
extraFlags = [ "--network-namespace-path=/var/run/netns/wg" ];
|
extraFlags = ["--network-namespace-path=/var/run/netns/wg"];
|
||||||
|
|
||||||
bindMounts = {
|
bindMounts = {
|
||||||
"${servarr.mediaDir}".isReadOnly = false;
|
"${servarr.mediaDir}".isReadOnly = false;
|
||||||
|
|||||||
@@ -39,17 +39,19 @@ in {
|
|||||||
openFirewall = true;
|
openFirewall = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
kirk.vpnnamespace.portMappings = [(
|
kirk.vpnnamespace.portMappings = [
|
||||||
mkIf cfg.useVpn {
|
(
|
||||||
From = defaultPort;
|
mkIf cfg.useVpn {
|
||||||
To = defaultPort;
|
From = defaultPort;
|
||||||
}
|
To = defaultPort;
|
||||||
)];
|
}
|
||||||
|
)
|
||||||
|
];
|
||||||
|
|
||||||
containers.prowlarr = mkIf cfg.useVpn {
|
containers.prowlarr = mkIf cfg.useVpn {
|
||||||
autoStart = true;
|
autoStart = true;
|
||||||
ephemeral = true;
|
ephemeral = true;
|
||||||
extraFlags = [ "--network-namespace-path=/var/run/netns/wg" ];
|
extraFlags = ["--network-namespace-path=/var/run/netns/wg"];
|
||||||
|
|
||||||
bindMounts = {
|
bindMounts = {
|
||||||
"/var/lib/prowlarr" = {
|
"/var/lib/prowlarr" = {
|
||||||
|
|||||||
@@ -39,17 +39,19 @@ in {
|
|||||||
dataDir = cfg.stateDir;
|
dataDir = cfg.stateDir;
|
||||||
};
|
};
|
||||||
|
|
||||||
kirk.vpnnamespace.portMappings = [(
|
kirk.vpnnamespace.portMappings = [
|
||||||
mkIf cfg.useVpn {
|
(
|
||||||
From = defaultPort;
|
mkIf cfg.useVpn {
|
||||||
To = defaultPort;
|
From = defaultPort;
|
||||||
}
|
To = defaultPort;
|
||||||
)];
|
}
|
||||||
|
)
|
||||||
|
];
|
||||||
|
|
||||||
containers.radarr= mkIf cfg.useVpn {
|
containers.radarr = mkIf cfg.useVpn {
|
||||||
autoStart = true;
|
autoStart = true;
|
||||||
ephemeral = true;
|
ephemeral = true;
|
||||||
extraFlags = [ "--network-namespace-path=/var/run/netns/wg" ];
|
extraFlags = ["--network-namespace-path=/var/run/netns/wg"];
|
||||||
|
|
||||||
bindMounts = {
|
bindMounts = {
|
||||||
"${servarr.mediaDir}".isReadOnly = false;
|
"${servarr.mediaDir}".isReadOnly = false;
|
||||||
@@ -103,6 +105,5 @@ in {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,17 +35,19 @@ in {
|
|||||||
dataDir = cfg.stateDir;
|
dataDir = cfg.stateDir;
|
||||||
};
|
};
|
||||||
|
|
||||||
kirk.vpnnamespace.portMappings = [(
|
kirk.vpnnamespace.portMappings = [
|
||||||
mkIf cfg.useVpn {
|
(
|
||||||
From = defaultPort;
|
mkIf cfg.useVpn {
|
||||||
To = defaultPort;
|
From = defaultPort;
|
||||||
}
|
To = defaultPort;
|
||||||
)];
|
}
|
||||||
|
)
|
||||||
|
];
|
||||||
|
|
||||||
containers.readarr = mkIf cfg.useVpn {
|
containers.readarr = mkIf cfg.useVpn {
|
||||||
autoStart = true;
|
autoStart = true;
|
||||||
ephemeral = true;
|
ephemeral = true;
|
||||||
extraFlags = [ "--network-namespace-path=/var/run/netns/wg" ];
|
extraFlags = ["--network-namespace-path=/var/run/netns/wg"];
|
||||||
|
|
||||||
bindMounts = {
|
bindMounts = {
|
||||||
"${servarr.mediaDir}".isReadOnly = false;
|
"${servarr.mediaDir}".isReadOnly = false;
|
||||||
@@ -99,6 +101,5 @@ in {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
# TODO: Dir creation and file permissions in nix
|
# TODO: Dir creation and file permissions in nix
|
||||||
{
|
{
|
||||||
pkgs,
|
|
||||||
config,
|
config,
|
||||||
lib,
|
lib,
|
||||||
...
|
...
|
||||||
@@ -49,7 +48,7 @@ in {
|
|||||||
containers.sonarr = mkIf cfg.useVpn {
|
containers.sonarr = mkIf cfg.useVpn {
|
||||||
autoStart = true;
|
autoStart = true;
|
||||||
ephemeral = true;
|
ephemeral = true;
|
||||||
extraFlags = [ "--network-namespace-path=/var/run/netns/wg" ];
|
extraFlags = ["--network-namespace-path=/var/run/netns/wg"];
|
||||||
|
|
||||||
bindMounts = {
|
bindMounts = {
|
||||||
"${servarr.mediaDir}".isReadOnly = false;
|
"${servarr.mediaDir}".isReadOnly = false;
|
||||||
|
|||||||
@@ -67,47 +67,54 @@ in {
|
|||||||
enable = true;
|
enable = true;
|
||||||
group = "media";
|
group = "media";
|
||||||
#home = cfg.stateDir;
|
#home = cfg.stateDir;
|
||||||
webHome = if cfg.useFlood then pkgs.flood-for-transmission else null;
|
webHome =
|
||||||
|
if cfg.useFlood
|
||||||
|
then pkgs.flood-for-transmission
|
||||||
|
else null;
|
||||||
package = pkgs.transmission_4;
|
package = pkgs.transmission_4;
|
||||||
openRPCPort = true;
|
openRPCPort = true;
|
||||||
openPeerPorts = true;
|
openPeerPorts = true;
|
||||||
settings = {
|
settings =
|
||||||
download-dir = "${servarr.mediaDir}/torrents";
|
{
|
||||||
incomplete-dir-enabled = true;
|
download-dir = "${servarr.mediaDir}/torrents";
|
||||||
incomplete-dir = "${servarr.mediaDir}/torrents/.incomplete";
|
incomplete-dir-enabled = true;
|
||||||
watch-dir-enabled = true;
|
incomplete-dir = "${servarr.mediaDir}/torrents/.incomplete";
|
||||||
watch-dir = "${servarr.mediaDir}/torrents/.watch";
|
watch-dir-enabled = true;
|
||||||
|
watch-dir = "${servarr.mediaDir}/torrents/.watch";
|
||||||
|
|
||||||
rpc-port = cfg.uiPort;
|
rpc-port = cfg.uiPort;
|
||||||
rpc-whitelist-enabled = true;
|
rpc-whitelist-enabled = true;
|
||||||
rpc-whitelist = "192.168.15.1,127.0.0.1";
|
rpc-whitelist = "192.168.15.1,127.0.0.1";
|
||||||
rpc-authentication-required = true;
|
rpc-authentication-required = true;
|
||||||
|
|
||||||
blocklist-enabled = true;
|
blocklist-enabled = true;
|
||||||
blocklist-url = "https://github.com/Naunter/BT_BlockLists/raw/master/bt_blocklists.gz";
|
blocklist-url = "https://github.com/Naunter/BT_BlockLists/raw/master/bt_blocklists.gz";
|
||||||
|
|
||||||
encryption = 1;
|
encryption = 1;
|
||||||
utp-enabled = true;
|
utp-enabled = true;
|
||||||
port-forwarding-enabled = false;
|
port-forwarding-enabled = false;
|
||||||
|
|
||||||
anti-brute-force-enabled = true;
|
anti-brute-force-enabled = true;
|
||||||
anti-brute-force-threshold = 10;
|
anti-brute-force-threshold = 10;
|
||||||
} // cfg.extraConfig;
|
}
|
||||||
|
// cfg.extraConfig;
|
||||||
};
|
};
|
||||||
|
|
||||||
kirk.vpnnamespace = mkIf cfg.useVpn {
|
kirk.vpnnamespace = mkIf cfg.useVpn {
|
||||||
portMappings = [{
|
portMappings = [
|
||||||
From = cfg.uiPort;
|
{
|
||||||
To = cfg.uiPort;
|
From = cfg.uiPort;
|
||||||
}];
|
To = cfg.uiPort;
|
||||||
openUdpPorts = [ cfg.peerPort ];
|
}
|
||||||
openTcpPorts = [ cfg.peerPort ];
|
];
|
||||||
|
openUdpPorts = [cfg.peerPort];
|
||||||
|
openTcpPorts = [cfg.peerPort];
|
||||||
};
|
};
|
||||||
|
|
||||||
containers.transmission = mkIf cfg.useVpn {
|
containers.transmission = mkIf cfg.useVpn {
|
||||||
autoStart = true;
|
autoStart = true;
|
||||||
ephemeral = true;
|
ephemeral = true;
|
||||||
extraFlags = [ "--network-namespace-path=/var/run/netns/wg" ];
|
extraFlags = ["--network-namespace-path=/var/run/netns/wg"];
|
||||||
|
|
||||||
bindMounts = {
|
bindMounts = {
|
||||||
"${servarr.mediaDir}/torrents".isReadOnly = false;
|
"${servarr.mediaDir}/torrents".isReadOnly = false;
|
||||||
@@ -142,39 +149,44 @@ in {
|
|||||||
enable = true;
|
enable = true;
|
||||||
# This is maybe wrong, too afraid to fix it lol
|
# This is maybe wrong, too afraid to fix it lol
|
||||||
group = "media";
|
group = "media";
|
||||||
webHome = if cfg.useFlood then pkgs.flood-for-transmission else null;
|
webHome =
|
||||||
|
if cfg.useFlood
|
||||||
|
then pkgs.flood-for-transmission
|
||||||
|
else null;
|
||||||
package = pkgs.transmission_4;
|
package = pkgs.transmission_4;
|
||||||
openRPCPort = true;
|
openRPCPort = true;
|
||||||
openPeerPorts = true;
|
openPeerPorts = true;
|
||||||
settings = {
|
settings =
|
||||||
download-dir = "${servarr.mediaDir}/torrents";
|
{
|
||||||
incomplete-dir-enabled = true;
|
download-dir = "${servarr.mediaDir}/torrents";
|
||||||
incomplete-dir = "${servarr.mediaDir}/torrents/.incomplete";
|
incomplete-dir-enabled = true;
|
||||||
watch-dir-enabled = true;
|
incomplete-dir = "${servarr.mediaDir}/torrents/.incomplete";
|
||||||
watch-dir = "${servarr.mediaDir}/torrents/.watch";
|
watch-dir-enabled = true;
|
||||||
|
watch-dir = "${servarr.mediaDir}/torrents/.watch";
|
||||||
|
|
||||||
rpc-bind-address = "192.168.15.1";
|
rpc-bind-address = "192.168.15.1";
|
||||||
rpc-port = cfg.uiPort;
|
rpc-port = cfg.uiPort;
|
||||||
rpc-whitelist-enabled = false;
|
rpc-whitelist-enabled = false;
|
||||||
rpc-whitelist = "192.168.15.1,127.0.0.1";
|
rpc-whitelist = "192.168.15.1,127.0.0.1";
|
||||||
rpc-authentication-required = false;
|
rpc-authentication-required = false;
|
||||||
|
|
||||||
blocklist-enabled = true;
|
blocklist-enabled = true;
|
||||||
blocklist-url = "https://github.com/Naunter/BT_BlockLists/raw/master/bt_blocklists.gz";
|
blocklist-url = "https://github.com/Naunter/BT_BlockLists/raw/master/bt_blocklists.gz";
|
||||||
|
|
||||||
peer-port = cfg.peerPort;
|
peer-port = cfg.peerPort;
|
||||||
dht-enabled = true;
|
dht-enabled = true;
|
||||||
pex-enabled = true;
|
pex-enabled = true;
|
||||||
utp-enabled = false;
|
utp-enabled = false;
|
||||||
encryption = 1;
|
encryption = 1;
|
||||||
port-forwarding-enabled = false;
|
port-forwarding-enabled = false;
|
||||||
|
|
||||||
anti-brute-force-enabled = true;
|
anti-brute-force-enabled = true;
|
||||||
anti-brute-force-threshold = 10;
|
anti-brute-force-threshold = 10;
|
||||||
|
|
||||||
# 0 = None, 1 = Critical, 2 = Error, 3 = Warn, 4 = Info, 5 = Debug, 6 = Trace
|
# 0 = None, 1 = Critical, 2 = Error, 3 = Warn, 4 = Info, 5 = Debug, 6 = Trace
|
||||||
message-level = 3;
|
message-level = 3;
|
||||||
} // cfg.extraConfig;
|
}
|
||||||
|
// cfg.extraConfig;
|
||||||
};
|
};
|
||||||
|
|
||||||
environment.systemPackages = with pkgs; [
|
environment.systemPackages = with pkgs; [
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./fonts
|
||||||
|
./foot
|
||||||
|
./fzf
|
||||||
|
./git
|
||||||
|
./gruvboxTheme
|
||||||
|
./helix
|
||||||
|
./homeManagerScripts
|
||||||
|
./jiten
|
||||||
|
./joshuto
|
||||||
|
./kakoune
|
||||||
|
./ssh
|
||||||
|
./terminalTools
|
||||||
|
./userDirs
|
||||||
|
./zathura
|
||||||
|
./zsh
|
||||||
|
];
|
||||||
|
}
|
||||||
+14
-13
@@ -17,7 +17,7 @@ in {
|
|||||||
description = lib.mdDoc ''
|
description = lib.mdDoc ''
|
||||||
What TCP ports to open using UPNP.
|
What TCP ports to open using UPNP.
|
||||||
'';
|
'';
|
||||||
example = [ 46382 38473 ];
|
example = [46382 38473];
|
||||||
};
|
};
|
||||||
|
|
||||||
openUdpPorts = mkOption {
|
openUdpPorts = mkOption {
|
||||||
@@ -26,7 +26,7 @@ in {
|
|||||||
description = lib.mdDoc ''
|
description = lib.mdDoc ''
|
||||||
What UDP ports to open using UPNP.
|
What UDP ports to open using UPNP.
|
||||||
'';
|
'';
|
||||||
example = [ 46382 38473 ];
|
example = [46382 38473];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -71,21 +71,22 @@ in {
|
|||||||
runtimeInputs = with pkgs; [miniupnpc];
|
runtimeInputs = with pkgs; [miniupnpc];
|
||||||
|
|
||||||
text = (
|
text = (
|
||||||
strings.concatMapStrings (x: "upnpc -r ${builtins.toString x} UDP" + "\n") cfg.openUpdPorts ++
|
strings.concatMapStrings (x: "upnpc -r ${builtins.toString x} UDP" + "\n") cfg.openUpdPorts
|
||||||
strings.concatMapStrings (x: "upnpc -r ${builtins.toString x} TCP" + "\n") cfg.openTcpPorts ++
|
++ strings.concatMapStrings (x: "upnpc -r ${builtins.toString x} TCP" + "\n") cfg.openTcpPorts
|
||||||
''echo "Successfully requested upnp ports to be opened".''
|
++ ''echo "Successfully requested upnp ports to be opened".''
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
in mkIf cfg.upnp.enable {
|
in
|
||||||
enable = true;
|
mkIf cfg.upnp.enable {
|
||||||
description = "Sets port on router";
|
enable = true;
|
||||||
script = "${upnp-ports}/bin/upnp-ports";
|
description = "Sets port on router";
|
||||||
|
script = "${upnp-ports}/bin/upnp-ports";
|
||||||
|
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
User = "root";
|
User = "root";
|
||||||
Type = "oneshot";
|
Type = "oneshot";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
timers = {
|
timers = {
|
||||||
upnpc = mkIf cfg.upnp.enable {
|
upnpc = mkIf cfg.upnp.enable {
|
||||||
|
|||||||
+251
-222
@@ -1,39 +1,45 @@
|
|||||||
{ lib, pkgs, config, ... }:
|
{
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}:
|
||||||
# Thanks to Maroka-chan...
|
# Thanks to Maroka-chan...
|
||||||
# TODO: Make it so you can make multiple namespaces by giving a list of
|
# TODO: Make it so you can make multiple namespaces by giving a list of
|
||||||
# objects with settings as attributes. Also add an option to enable whether
|
# objects with settings as attributes. Also add an option to enable whether
|
||||||
# the namespace should use a vpn or not.
|
# the namespace should use a vpn or not.
|
||||||
with builtins;
|
with builtins;
|
||||||
with lib;
|
with lib; let
|
||||||
let
|
|
||||||
cfg = config.kirk.vpnnamespace;
|
cfg = config.kirk.vpnnamespace;
|
||||||
in {
|
in {
|
||||||
options.kirk.vpnnamespace = {
|
options.kirk.vpnnamespace = {
|
||||||
enable = mkEnableOption (lib.mdDoc "VPN Namespace") // {
|
enable =
|
||||||
description = lib.mdDoc ''
|
mkEnableOption (lib.mdDoc "VPN Namespace")
|
||||||
Whether to enable the VPN namespace.
|
// {
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
Whether to enable the VPN namespace.
|
||||||
|
|
||||||
To access the namespace a veth pair is used to
|
To access the namespace a veth pair is used to
|
||||||
connect the vpn namespace and the default namespace
|
connect the vpn namespace and the default namespace
|
||||||
through a linux bridge. One end of the pair is
|
through a linux bridge. One end of the pair is
|
||||||
connected to the linux bridge on the default namespace.
|
connected to the linux bridge on the default namespace.
|
||||||
The other end is connected to the vpn namespace.
|
The other end is connected to the vpn namespace.
|
||||||
|
|
||||||
Systemd services can be run within the namespace by
|
Systemd services can be run within the namespace by
|
||||||
adding these options:
|
adding these options:
|
||||||
|
|
||||||
bindsTo = [ "netns@wg.service" ];
|
bindsTo = [ "netns@wg.service" ];
|
||||||
requires = [ "network-online.target" ];
|
requires = [ "network-online.target" ];
|
||||||
after = [ "wg.service" ];
|
after = [ "wg.service" ];
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
NetworkNamespacePath = "/var/run/netns/wg";
|
NetworkNamespacePath = "/var/run/netns/wg";
|
||||||
};
|
};
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
accessibleFrom = mkOption {
|
accessibleFrom = mkOption {
|
||||||
type = types.listOf types.str;
|
type = types.listOf types.str;
|
||||||
default = [ ];
|
default = [];
|
||||||
description = lib.mdDoc ''
|
description = lib.mdDoc ''
|
||||||
Subnets or specific addresses that the namespace should be accessible to.
|
Subnets or specific addresses that the namespace should be accessible to.
|
||||||
'';
|
'';
|
||||||
@@ -94,10 +100,12 @@ in {
|
|||||||
description = lib.mdDoc ''
|
description = lib.mdDoc ''
|
||||||
A list of pairs mapping a port from the host to a port in the namespace.
|
A list of pairs mapping a port from the host to a port in the namespace.
|
||||||
'';
|
'';
|
||||||
example = [{
|
example = [
|
||||||
From = 80;
|
{
|
||||||
To = 80;
|
From = 80;
|
||||||
}];
|
To = 80;
|
||||||
|
}
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
dnsServers = mkOption {
|
dnsServers = mkOption {
|
||||||
@@ -106,7 +114,7 @@ in {
|
|||||||
description = lib.mdDoc ''
|
description = lib.mdDoc ''
|
||||||
YOUR VPN WILL LEAK IF THIS IS NOT SET. The dns address of your vpn.
|
YOUR VPN WILL LEAK IF THIS IS NOT SET. The dns address of your vpn.
|
||||||
'';
|
'';
|
||||||
example = [ "1.1.1.2" ];
|
example = ["1.1.1.2"];
|
||||||
};
|
};
|
||||||
|
|
||||||
openTcpPorts = mkOption {
|
openTcpPorts = mkOption {
|
||||||
@@ -116,7 +124,7 @@ in {
|
|||||||
What TCP ports to allow incoming traffic from. You need this if
|
What TCP ports to allow incoming traffic from. You need this if
|
||||||
you're port forwarding on your VPN provider.
|
you're port forwarding on your VPN provider.
|
||||||
'';
|
'';
|
||||||
example = [ 46382 38473 ];
|
example = [46382 38473];
|
||||||
};
|
};
|
||||||
|
|
||||||
openUdpPorts = mkOption {
|
openUdpPorts = mkOption {
|
||||||
@@ -126,7 +134,7 @@ in {
|
|||||||
What UDP ports to allow incoming traffic from. You need this if
|
What UDP ports to allow incoming traffic from. You need this if
|
||||||
you're port forwarding on your VPN provider.
|
you're port forwarding on your VPN provider.
|
||||||
'';
|
'';
|
||||||
example = [ 46382 38473 ];
|
example = [46382 38473];
|
||||||
};
|
};
|
||||||
|
|
||||||
vpnTestService = {
|
vpnTestService = {
|
||||||
@@ -134,214 +142,235 @@ in {
|
|||||||
|
|
||||||
port = mkOption {
|
port = mkOption {
|
||||||
type = types.port;
|
type = types.port;
|
||||||
default = [ 12300 ];
|
default = [12300];
|
||||||
description = lib.mdDoc ''
|
description = lib.mdDoc ''
|
||||||
The port that the vpn test service listens to.
|
The port that the vpn test service listens to.
|
||||||
'';
|
'';
|
||||||
example = [ 58403 ];
|
example = [58403];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config =
|
config = let
|
||||||
let
|
headMay = list:
|
||||||
headMay = list: if list == [] then null else head list;
|
if list == []
|
||||||
# Checks if string is ipv4, from SO, hope it works well
|
then null
|
||||||
# https://stackoverflow.com/questions/53497/regular-expression-that-matches-valid-ipv6-addresses
|
else head list;
|
||||||
isIpv4 = address:
|
# Checks if string is ipv4, from SO, hope it works well
|
||||||
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]";
|
# https://stackoverflow.com/questions/53497/regular-expression-that-matches-valid-ipv6-addresses
|
||||||
regex = match pat address;
|
isIpv4 = address: let
|
||||||
in regex != null;
|
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]";
|
||||||
# Checks if string is ipv6, from SO, hope it works well
|
regex = match pat address;
|
||||||
# https://stackoverflow.com/questions/53497/regular-expression-that-matches-valid-ipv6-addresses
|
in
|
||||||
isIpv6 = address:
|
regex != null;
|
||||||
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]))";
|
# Checks if string is ipv6, from SO, hope it works well
|
||||||
regex = match pat address;
|
# https://stackoverflow.com/questions/53497/regular-expression-that-matches-valid-ipv6-addresses
|
||||||
in regex != null;
|
isIpv6 = address: let
|
||||||
isIp = ip: (isIpv4 ip || isIpv6 ip);
|
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
|
in
|
||||||
mkIf cfg.enable {
|
mkIf cfg.enable {
|
||||||
lib.vpn = {
|
lib.vpn = {
|
||||||
dnsServers =
|
dnsServers = let
|
||||||
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 = [ "netns@wg.service" ];
|
|
||||||
|
|
||||||
serviceConfig = let
|
|
||||||
lines = split "\n" (readFile cfg.wireguardConfigFile);
|
lines = split "\n" (readFile cfg.wireguardConfigFile);
|
||||||
addrLine = headMay (filter (x: typeOf x == "string" && match ".*Address.*" x != null) lines);
|
dnsLine = headMay (filter (x: typeOf x == "string" && match ".*DNS.*" x != null) lines);
|
||||||
in if addrLine == null then [] else let
|
in
|
||||||
ipsUnsplit = head (match "Address ?=(.*)" addrLine);
|
if dnsLine == null
|
||||||
in if ipsUnsplit == null then [] else let
|
then []
|
||||||
ips = filter (x: typeOf x == "string") (split "," ipsUnsplit);
|
else let
|
||||||
ipsNoSpaces = map (replaceStrings [" "] [""]) ips;
|
ipsUnsplit = head (match "DNS ?=(.*)" dnsLine);
|
||||||
wgIpv4Address = headMay (filter isIpv4 ipsNoSpaces);
|
in
|
||||||
|
if ipsUnsplit == null
|
||||||
vpn-namespace = pkgs.writeShellApplication {
|
then []
|
||||||
name = "vpn-namespace";
|
else let
|
||||||
|
ips = filter (x: typeOf x == "string") (split "," ipsUnsplit);
|
||||||
runtimeInputs = with pkgs; [ iproute2 wireguard-tools iptables ];
|
ipsNoSpaces = map (replaceStrings [" "] [""]) ips;
|
||||||
|
correctIps = filter isIp ipsNoSpaces;
|
||||||
text = ''
|
in
|
||||||
# Set up the wireguard interface
|
assert (correctIps != []) || abort "There must be at least 1 DNS server set."; correctIps;
|
||||||
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 = {
|
boot.kernel.sysctl."net.ipv4.ip_forward" = 1;
|
||||||
enable = cfg.vpnTestService.enable;
|
|
||||||
|
|
||||||
script = let
|
systemd.services = {
|
||||||
vpn-test = pkgs.writeShellApplication {
|
"netns@" = {
|
||||||
name = "vpn-test";
|
description = "%I network namespace";
|
||||||
|
before = ["network.target"];
|
||||||
runtimeInputs = with pkgs; [ util-linux unixtools.ping coreutils curl bash libressl netcat-gnu openresolv dig ];
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
text = ''
|
RemainAfterExit = true;
|
||||||
cd "$(mktemp -d)"
|
ExecStart = "${pkgs.iproute2}/bin/ip netns add %I";
|
||||||
|
ExecStop = "${pkgs.iproute2}/bin/ip netns del %I";
|
||||||
# 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" ];
|
wg = {
|
||||||
requires = [ "network-online.target" ];
|
description = "wg network interface";
|
||||||
after = [ "wg.service" ];
|
bindsTo = ["netns@wg.service"];
|
||||||
serviceConfig = {
|
requires = ["network-online.target"];
|
||||||
User="prowlarr";
|
after = ["netns@wg.service"];
|
||||||
NetworkNamespacePath = "/var/run/netns/wg";
|
wantedBy = ["netns@wg.service"];
|
||||||
BindReadOnlyPaths=["/etc/netns/wg/resolv.conf:/etc/resolv.conf:norbind" "/data/test.file:/etc/test.file:norbind"];
|
|
||||||
|
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