From b272b984275ef0ff37352e4398fca145930c8895 Mon Sep 17 00:00:00 2001 From: Nick Date: Mon, 24 Nov 2025 03:14:44 -0600 Subject: [PATCH] feat: started working on torrent VM --- modules/config/instances/config/torrent.nix | 54 +++++++ modules/home/cli/utilities/rqbit/default.nix | 11 -- modules/nixos/guests/defenseio/default.nix | 8 +- modules/nixos/guests/torrent/default.nix | 141 +++++++++++++++++++ modules/nixos/guests/torrent/rqbit.nix | 116 +++++++++++++++ secrets/secrets.yaml | 6 +- 6 files changed, 318 insertions(+), 18 deletions(-) create mode 100755 modules/config/instances/config/torrent.nix delete mode 100644 modules/home/cli/utilities/rqbit/default.nix create mode 100755 modules/nixos/guests/torrent/default.nix create mode 100755 modules/nixos/guests/torrent/rqbit.nix diff --git a/modules/config/instances/config/torrent.nix b/modules/config/instances/config/torrent.nix new file mode 100755 index 0000000..684774f --- /dev/null +++ b/modules/config/instances/config/torrent.nix @@ -0,0 +1,54 @@ +{ moduleFunctions }: +let + inherit (moduleFunctions.instancesFunctions) + domain0 + sslPath + varPath + mntPath + secretPath + ; + label = "Rqbit"; + name = "rqbit"; + subdomain = "share"; + domain = "${subdomain}.${domain0}"; + secrets = "${secretPath}/${name}"; + ssl = "${sslPath}/${domain}"; +in +{ + label = label; + name = name; + short = label; + domains = { + url0 = domain; + }; + subdomain = name; + tags = [ + name + "rqbit" + "torrent" + "p2p" + ]; + interface = { + id = "vm-${name}"; + mac = "02:00:00:00:56:07"; + idUser = "vmuser-${name}"; + macUser = "02:00:00:00:00:07"; + ip = "192.168.50.117"; + gate = "192.168.50.1"; + ssh = 2207; + }; + ssl = { + path = ssl; + cert = "${ssl}/fullchain.pem"; + key = "${ssl}/key.pem"; + }; + varPaths = { + path0 = "${varPath}/${name}"; + }; + mntPaths = { + path0 = "${mntPath}/${name}"; + }; + secretPaths = { + path0 = secrets; + }; +} diff --git a/modules/home/cli/utilities/rqbit/default.nix b/modules/home/cli/utilities/rqbit/default.nix deleted file mode 100644 index 13e2a8b..0000000 --- a/modules/home/cli/utilities/rqbit/default.nix +++ /dev/null @@ -1,11 +0,0 @@ -{ - pkgs, - ... -}: -{ - home.packages = builtins.attrValues { - inherit (pkgs) - rqbit - ; - }; -} diff --git a/modules/nixos/guests/defenseio/default.nix b/modules/nixos/guests/defenseio/default.nix index ede06dc..b935f57 100755 --- a/modules/nixos/guests/defenseio/default.nix +++ b/modules/nixos/guests/defenseio/default.nix @@ -41,11 +41,11 @@ in autostart = true; config = let - ceresCpu = 40; + ceresCpu = 35; erisCpu = 5; marsCpu = 18; - deimosCpu = 5; - phobosCpu = 5; + deimosCpu = 4; + phobosCpu = 4; macAddress = "02:00:00:00:00:${macOctet}"; workers = deviceLogic ceresCpu erisCpu marsCpu deimosCpu phobosCpu; @@ -78,7 +78,7 @@ in num = num: (num * 1024); ceresRam = num 50; erisRam = num 7; - marsRam = num 22; + marsRam = num 30; deimosRam = num 7; phobosRam = num 7; in diff --git a/modules/nixos/guests/torrent/default.nix b/modules/nixos/guests/torrent/default.nix new file mode 100755 index 0000000..a608b35 --- /dev/null +++ b/modules/nixos/guests/torrent/default.nix @@ -0,0 +1,141 @@ +{ + config, + flake, + pkgs, + ... +}: +let + inherit (flake.config.people) user0; + inherit (flake.config.services) instances; + serviceCfg = instances.torrent; + host = instances.torrent; +in +{ + microvm.vms.${serviceCfg.name} = { + autostart = true; + config = { + system.stateVersion = "25.05"; + + networking.firewall.allowedTCPPorts = [ + 22 + 80 + ]; + + services = { + rqbit = { + enable = true; + dataDir = "/var/lib/rqbit/downloads"; + listenAddress = "0.0.0.0"; + openFirewall = true; + extraArgs = [ ]; + }; + + openssh = { + enable = true; + settings.PasswordAuthentication = false; + }; + }; + + users.users.root.openssh.authorizedKeys.keys = flake.config.people.users.${user0}.sshKeys; + + systemd = { + network = { + enable = true; + networks."10-enp" = { + matchConfig.Name = "enp0s5"; + addresses = [ { Address = "${serviceCfg.interface.ip}/24"; } ]; + gateway = [ serviceCfg.interface.gate ]; + }; + }; + tmpfiles.rules = [ + "d ${serviceCfg.varPaths.path0} 755 ${serviceCfg.name} ${serviceCfg.name} -" + ]; + }; + + microvm = { + vcpu = 4; + mem = 1024 * 4; + hypervisor = "qemu"; + interfaces = [ + { + type = "tap"; + id = serviceCfg.interface.id; + mac = serviceCfg.interface.mac; + } + ]; + + shares = [ + { + source = "/nix/store"; + mountPoint = "/nix/.ro-store"; + tag = "ro-store"; + proto = "virtiofs"; + } + { + mountPoint = "/var/lib/${serviceCfg.name}"; + proto = "virtiofs"; + source = serviceCfg.mntPaths.path0; + tag = "${serviceCfg.name}_data"; + } + { + mountPoint = "/run/secrets"; + proto = "virtiofs"; + source = "/run/secrets/${serviceCfg.name}"; + tag = "host_secrets"; + } + + ]; + }; + environment.systemPackages = [ ]; + }; + }; + + services = { + caddy = { + virtualHosts = { + "${host}" = { + extraConfig = '' + basic_auth { + {$CADDY_AUTH_USER} {$CADDY_AUTH_PASSWORD_HASH} + } + + reverse_proxy ${serviceCfg.interface.ip}:${toString serviceCfg.ports.port0} { + header_up X-Real-IP {remote_host} + } + + tls ${serviceCfg.ssl.cert} ${serviceCfg.ssl.key} + + encode zstd gzip + ''; + }; + }; + }; + }; + + sops.secrets = { + "caddy/${serviceCfg.name}-auth" = { + owner = "caddy"; + group = "caddy"; + mode = "0400"; + }; + }; + + security.acme.certs.${host} = { + dnsProvider = instances.web.dns.provider1; + environmentFile = config.sops.secrets."dns/${instances.web.dns.provider1}".path; + }; + + systemd = { + services.caddy = { + serviceConfig = { + EnvironmentFile = config.sops.secrets."caddy/${serviceCfg.name}-auth".path; + }; + }; + tmpfiles.rules = [ + "d ${serviceCfg.mntPaths.path0} 0755 microvm wheel - -" + "d ${serviceCfg.secretPaths.path0}/caddy 755 caddy caddy -" + "d /var/log/caddy 755 caddy caddy -" + + ]; + }; +} diff --git a/modules/nixos/guests/torrent/rqbit.nix b/modules/nixos/guests/torrent/rqbit.nix new file mode 100755 index 0000000..d1fbd8b --- /dev/null +++ b/modules/nixos/guests/torrent/rqbit.nix @@ -0,0 +1,116 @@ +{ + config, + lib, + pkgs, + ... +}: + +with lib; + +let + cfg = config.services.rqbit; +in +{ + options.services.rqbit = { + enable = mkEnableOption "rqbit BitTorrent client"; + + package = mkOption { + type = types.package; + default = pkgs.rqbit; + defaultText = literalExpression "pkgs.rqbit"; + description = "The rqbit package to use."; + }; + + dataDir = mkOption { + type = types.path; + default = "/var/lib/rqbit"; + description = "Directory to store downloaded torrents."; + }; + + listenAddress = mkOption { + type = types.str; + default = "127.0.0.1"; + description = "IP address to listen on for the web UI and API."; + }; + + listenPort = mkOption { + type = types.port; + default = 3030; + description = "Port for the web UI and API."; + }; + + openFirewall = mkOption { + type = types.bool; + default = false; + description = "Open the firewall for the web UI port."; + }; + + user = mkOption { + type = types.str; + default = "rqbit"; + description = "User account under which rqbit runs."; + }; + + group = mkOption { + type = types.str; + default = "rqbit"; + description = "Group under which rqbit runs."; + }; + + extraArgs = mkOption { + type = types.listOf types.str; + default = [ ]; + description = "Extra command-line arguments to pass to rqbit."; + example = literalExpression ''[ "--upnp" "--enable-upnp-server" ]''; + }; + }; + + config = mkIf cfg.enable { + systemd.services.rqbit = { + description = "rqbit BitTorrent Client"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = { + Type = "simple"; + User = cfg.user; + Group = cfg.group; + + Environment = [ + "XDG_CACHE_HOME=/var/lib/rqbit/.cache" + "XDG_DATA_HOME=/var/lib/rqbit/.local/share" + ]; + + ExecStart = '' + ${cfg.package}/bin/rqbit \ + --http-api-listen-addr ${cfg.listenAddress}:${toString cfg.listenPort} \ + ${concatStringsSep " " cfg.extraArgs} \ + server start ${cfg.dataDir} + ''; + Restart = "on-failure"; + + StateDirectory = "rqbit"; + NoNewPrivileges = true; + PrivateTmp = true; + ProtectSystem = "strict"; + ReadWritePaths = [ cfg.dataDir ]; + }; + }; + + users.users = mkIf (cfg.user == "rqbit") { + rqbit = { + isSystemUser = true; + group = cfg.group; + description = "rqbit BitTorrent client user"; + }; + }; + + users.groups = mkIf (cfg.group == "rqbit") { + rqbit = { }; + }; + + networking.firewall = mkIf cfg.openFirewall { + allowedTCPPorts = [ cfg.listenPort ]; + }; + }; +} diff --git a/secrets/secrets.yaml b/secrets/secrets.yaml index 4f0df35..2286068 100755 --- a/secrets/secrets.yaml +++ b/secrets/secrets.yaml @@ -47,7 +47,7 @@ glance-jellyfin: ENC[AES256_GCM,data:ozdDKgAWkA88J2j8RtiOP/aQPAt/neUOSlAZF20g510 opencloud: projectenv: ENC[AES256_GCM,data:+XCd3xScfxCN1Zl5L+4RAOjpmMPhVLSBtqH2nkEUpXhssy5EU82qAanNmqwiIJ1VrYXYovuu3XOwRKY3Ub1nsR5h1S0KUCwav2zmFKVopxF/5jVNIk6qR8Ggz/fAa1YQSW+SAnrtRGvP0Q1SERlCgnH4isVxNvWPyWCZKIgiX2Enu7hVwsJXKLYDomRWt47zzXNUzw50aFn7xPtXE/AYbMPBa+FweCrCfkaQ6i6jPvkdc6VBYTqIanD0908wB2SJA+1xvY7bYgRVB17/4a/9DuUN5J4xU84TOW7EFkvC/hWhlhC58GqQrOFyAgTP4YJHKGbLVKPlc4fcNMh5+pENpPG2fRDElCaLoJcYe6sYhaCDSegpDR/U9bgzKirnCu/hmdG+NQ3sGK/C89JL2kZT+tVT1u5JWnKGOGvLGQm73QUmnssDZVd8ubNsnd57W7siqAXY3+DN46yLrGgmTfHTRi4x2DKF8VCD9jXOxWsyoLvKYDyz09H9dI72xlCtSmcrFAt7bY7uEAWutrPCf3Kh/gq6oFUAPBEwfqhgnpgGA1vyA6o4zhxl4Rqye5YZMx2uNkxdA4wmk9KB/e7BVR/P04TSXoAV931OX7bnlw3XjSw5NTPEPnpmwZ3VPRGGkz171RiQQp+CkwUr35+DdwFrGazuv3wlwAhM19h9SRn8jikrw6PPGVehYp8mB/FhpNgqV0nM2DfjaBqE3yMfDzXH5b92t4Q=,iv:6mlHq6yh03x/FbZNu+A9QBoV6ALX1rRWuL13ItJWriI=,tag:tK6Ek2fzgPPWT8WCeU1Frw==,type:str] caddy: - prompter-auth: ENC[AES256_GCM,data:uEj6gruCfcIRoCQY9eNcOka+PAIIhAlKnI+ehZ88aZo90tINcxZ7ZvKqlTJr4rt5o+EO7rvRJcYH/s8/+piszFyxSa64Rtq5KdAjfHnRm0QM8q/2JIHnZsQC3fPz1S177WPs/c3Eydh4VeVe,iv:ZOru4ABFgIy9DoTlMl3InSf8zM1ERNpbRNLN6vy97Jc=,tag:5v3w7kvFQCEPBjchE8K0cw==,type:str] + rqbit-auth: ENC[AES256_GCM,data:f1RMi9uGdWP1hGZOzszC87oAhxJ12q55/XFvxQu80nxu1Zn+MfaBVYXi9imtBnaj2tONQ8/zEDsa4xCTRkr5lPCqrCYJ52UM55w+IO9YWQj9BJSF46SloLFJ8tezze4rNBbE0//ptzXGWWCo,iv:Tm7QDocZlPsz+eR48AEhAYCUgw8N0dvhP5n/TvNRVQI=,tag:k9YDt8sSnRksxKScDf11+A==,type:str] comfyui-auth: ENC[AES256_GCM,data:7VTXoRxnD0NyVCFRAjHaZswEUsFuQd/ZIwVfqGPmNNV87hn6CBYWvxvcPPFwe+uw7BmKMt+I66DyKx5ydYENTWxPocyT/rFdgdtWwNoenj+JwsUzegmMbEiH2HCZdiwKj0h1lo142mtA6zkc,iv:xT5XHCj8D4dyvglstE2oqo92fLdscCkaNMux43hJ7nQ=,tag:HgU9wAmjPvfoDXgnorB5yA==,type:str] wifi-home: ENC[AES256_GCM,data:5NYSCUyalDf7gZF7WaRQJCo=,iv:RkVZKsmVEBg5M28DSkBD41673iLM+dqDAAhSwjqejck=,tag:QQ17VSWOnU0bGglZq6455Q==,type:str] firefly-iii: @@ -70,7 +70,7 @@ sops: bXBOa1VSakoyaWxpODJEOU11QUZCaUEK8Ch9Ten3DdrPHF1DTH2qei85AlHUOaLD aNfzakake7ej+MxJYdKEU0bcWofNMKzIlZa2uM10KZSENDP8d8qlig== -----END AGE ENCRYPTED FILE----- - lastmodified: "2025-11-22T08:22:22Z" - mac: ENC[AES256_GCM,data:aGtZuHEsxcUZCfMdiYoX0oHd71XNIEG5UgxtoSqIr1ICqnjGV1hrNeLu+coSslkvYjAteYkgDBk8lHiO1kBY7G3d9fn0cRnR7wpgcaiFDCPaKdjXlrZmDdbsN+4NF62Y1LkclvGOWGEvM4pR+HxnNxK3nVEU0e10TaZ0r9/b0+o=,iv:MCid50yHr9Sk8hzsbu8wBQwW4vnERxaCEuivq1TUvhA=,tag:T7F2lS5lWY7zncWOY4VSbA==,type:str] + lastmodified: "2025-11-24T08:50:25Z" + mac: ENC[AES256_GCM,data:bBYF/In0Wx1YVA39RRwR1sHyLlZTw+AhuSdHTevaqk5s55hyLk5Bk7Z1y/JPQiARezzoRC3tVkLI1Chuhj3IGyo34EoYUesKsvg99Gy1Y3K94VbqoeFub/nOE/Kgm6g2okyfx3jAgQ8HnLTHA4YS/u6reR77U+Engf6ASCuMNnc=,iv:wlsvXcpcgB9zTcZAjkhaIdulSM1ReaNPcQyn1HHAxAU=,tag:8JwOPmMady60wGMpM8mqmQ==,type:str] unencrypted_suffix: _unencrypted version: 3.11.0