diff --git a/machines/galadriel/configuration.nix b/machines/galadriel/configuration.nix index b81d402..ffedcb6 100644 --- a/machines/galadriel/configuration.nix +++ b/machines/galadriel/configuration.nix @@ -16,6 +16,7 @@ ./zfs.nix ./backup.nix ../../services/smb.nix + ../../services/qbittorrent.nix #../../services/stableDiffusion.nix #../../services/freshrrs.nix #../../services/torrent.nix diff --git a/modules/qbittorrent-nox.nix b/modules/qbittorrent-nox.nix new file mode 100644 index 0000000..fb1e1fa --- /dev/null +++ b/modules/qbittorrent-nox.nix @@ -0,0 +1,484 @@ +{ config, lib, pkgs, options, ... }: + +let + cfg = config.services.qbittorrent-nox; + cfgPath = "/var/lib/qbittorrent/.config/qBittorrent/qBittorrent.conf"; + path = "/var/lib/qbittorrent"; + + configurationFile = lib.writeText "${cfgPath}" '' + [Application] + FileLogger\Age=${toString cfg.Filelogger.age} + FileLogger\AgeType=${toString cfg.Filelogger.ageType} + FileLogger\Backup=${toString cfg.Filelogger.backup} + FileLogger\DeleteOld=${toString cfg.Filelogger.deleteOld} + FileLogger\Enabled=${toString cfg.Filelogger.enable} + FileLogger\MaxSizeBytes=${toString cfg.Filelogger.maxSizeBytes} + FileLogger\Path=${cfg.Filelogger.path} + MemoryWorkingSetLimit=${toString cfg.MemoryWorkingSetLimit} + + [BitTorrent] + Session\AddExtensionToIncompleteFiles=${toString cfg.AddExtensionToIncompleteFiles} + Session\AlternativeGlobalDLSpeedLimit=${toString cfg.AlternativeGlobalDLSpeedLimit} + Session\AlternativeGlobalUPSpeedLimit=${toString cfg.AlternativeGlobalUPSpeedLimit} + Session\AnonymousModeEnabled=${toString cfg.AnonymousModeEnabled} + Session\BTProtocol=${cfg.BTProtocol} + Session\BandwidthSchedulerEnabled=${toString cfg.BandwidthSchedulerEnabled} + Session\DefaultSavePath=${cfg.DefaultSavePath} + Session\Encryption=${ lib.mkIf cfg.Encryption "1" "0" } + Session\ExcludedFileNames=${cfg.ExcludedFileNames} + Session\FinishedTorrentExportDirectory=${cfg.FinishedTorrentExportDirectory} + Session\GlobalDLSpeedLimit=${toString cfg.GlobalDLSpeedLimit} + Session\GlobalMaxRatio=${toString cfg.GlobalMaxRatio} + Session\GlobalUPSpeedLimit=${toString cfg.GlobalUPSpeedLimit} + Session\I2P\Enabled=${toString cfg.I2PEnabled} + Session\IgnoreLimitsOnLAN=${toString cfg.IgnoreLimitsOnLAN} + Session\IncludeOverheadInLimits=${toString cfg.IncludeOverheadInLimits} + Session\Interface=${cfg.Interface} + Session\InterfaceAddress=${cfg.InterfaceAddress} + Session\InterfaceName=${cfg.InterfaceName} + Session\LSDEnabled=${toString cfg.LSDEnabled} + Session\MaxActiveCheckingTorrents=${toString cfg.MaxActiveCheckingTorrents} + Session\MaxRatioAction=${toString cfg.MaxRatioAction} + Session\Port=${toString cfg.Port} + Session\Preallocation=${toString cfg.Preallocation} + Session\QueueingSystemEnabled=${toString cfg.QueueingSystemEnabled} + Session\SubcategoriesEnabled=${toString cfg.SubcategoriesEnabled} + Session\Tags=${cfg.Tags} + Session\TempPath=${cfg.TempPath} + Session\TempPathEnabled=${toString cfg.TempPathEnabled} + Session\TorrentExportDirectory=${cfg.TorrentExportDirectory} + Session\UseAlternativeGlobalSpeedLimit=${toString cfg.UseAlternativeGlobalSpeedLimit} + + [Core] + AutoDeleteAddedTorrentFile=${cfg.AutoDeleteAddedTorrentFile} + + [LegalNotice] + Accepted=${toString cfg.Accepted} + + [Meta] + MigrationVersion=${toString cfg.MigrationVersion} + + [Network] + PortForwardingEnabled=${toString cfg.PortForwardingEnabled} + + [Preferences] + General\Locale=${cfg.GeneralLocale} + MailNotification\req_auth=${toString cfg.MailNotificationReqAuth} + Scheduler\days=${cfg.SchedulerDays} + Scheduler\end_time=${cfg.SchedulerEndTime} + WebUI\AuthSubnetWhitelist=${cfg.WebUIAuthSubnetWhitelist} + WebUI\AuthSubnetWhitelistEnabled=${toString cfg.WebUIAuthSubnetWhitelistEnabled} + WebUI\Port=${toString cfg.WebUIPort} + WebUI\UseUPnP=${toString cfg.WebUIUseUPnP} + + [RSS] + AutoDownloader\DownloadRepacks=${toString cfg.AutoDownloaderDownloadRepacks} + AutoDownloader\EnableProcessing=${toString cfg.AutoDownloaderEnableProcessing} + AutoDownloader\SmartEpisodeFilter=${cfg.AutoDownloaderSmartEpisodeFilter} + Session\EnableProcessing=${toString cfg.SessionEnableProcessing} + ''; +in +{ + options.services.qbittorrent-nox = { + enable = lib.mkEnableOption { + default = false; + description = "Enable qbittorrent-nox service."; + }; + + openFirewall = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Whether to open the qbittorrent-nox port in the firewall."; + }; + + user = lib.mkOption { + type = lib.types.str; + default = "qbittorrent"; + description = "User to run qbittorrent-nox as."; + }; + + group = lib.mkOption { + type = lib.types.str; + default = "qbittorrent"; + description = "Group to run qbittorrent-nox as."; + }; + + # FileLogger + Filelogger.enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Whether to enable the file logger."; + }; + Filelogger.age = lib.mkOption { + type = lib.types.int; + default = 1; + description = "Age of the log file."; + }; + Filelogger.ageType = lib.mkOption { + type = lib.types.int; + default = 1; + description = "Age type of the log file."; + }; + Filelogger.backup = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Whether to backup the log file."; + }; + Filelogger.deleteOld = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Whether to delete old log files."; + }; + Filelogger.maxSizeBytes = lib.mkOption { + type = lib.types.int; + default = 66560; + description = "Max size of the log file in bytes."; + }; + Filelogger.path = lib.mkOption { + type = lib.types.str; + default = "${path}/.qbittorrent/logs"; + description = "Path to the log file."; + }; + + MemoryWorkingSetLimit = lib.mkOption { + type = lib.types.int; + default = 8192; + description = "Memory working set limit."; + }; + + # BitTorrent + AddExtensionToIncompleteFiles = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Add extension to incomplete files."; + }; + + AlternativeGlobalDLSpeedLimit = lib.mkOption { + type = lib.types.int; + default = 1000; + description = "Alternative global download speed limit."; + }; + + AlternativeGlobalUPSpeedLimit = lib.mkOption { + type = lib.types.int; + default = 1000; + description = "Alternative global upload speed limit."; + }; + + AnonymousModeEnabled = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Enable anonymous mode."; + }; + + BTProtocol = lib.mkOption { + type = lib.types.str; + default = "Both"; + description = "BitTorrent protocol."; + }; + + BandwidthSchedulerEnabled = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Enable bandwidth scheduler."; + }; + + DefaultSavePath = lib.mkOption { + type = lib.types.str; + default = "${path}"; + description = "Default save path."; + }; + + Encryption = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Enable encryption."; + }; + + ExcludedFileNames = lib.mkOption { + type = lib.types.str; + default = ""; + description = "Excluded file names."; + }; + + FinishedTorrentExportDirectory = lib.mkOption { + type = lib.types.str; + default = "${path}"; + description = "Finished torrent export directory."; + }; + + GlobalDLSpeedLimit = lib.mkOption { + type = lib.types.int; + default = 0; + description = "Global download speed limit."; + }; + + GlobalMaxRatio = lib.mkOption { + type = lib.types.float; + default = 0; + description = "Global max ratio."; + }; + + GlobalUPSpeedLimit = lib.mkOption { + type = lib.types.int; + default = 0; + description = "Global upload speed limit."; + }; + + I2PEnabled = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Enable I2P."; + }; + + IgnoreLimitsOnLAN = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Ignore limits on LAN."; + }; + + IncludeOverheadInLimits = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Include overhead in limits."; + }; + + Interface = lib.mkOption { + type = lib.types.str; + default = ""; + example = "tun0"; + description = "Interface."; + }; + + InterfaceAddress = lib.mkOption { + type = lib.types.str; + example = ""; + default = "10.0.0.0"; + description = "Interface address."; + }; + + InterfaceName = lib.mkOption { + type = lib.types.str; + default = ""; + example = "tun0"; + description = "Interface name."; + }; + + LSDEnabled = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Enable LSD."; + }; + + MaxActiveCheckingTorrents = lib.mkOption { + type = lib.types.int; + default = 15; + description = "Max active checking torrents."; + }; + + MaxRatioAction = lib.mkOption { + type = lib.types.int; + default = 1; + description = "Max ratio action."; + }; + + Port = lib.mkOption { + type = lib.types.int; + default = 4132; + description = "Port for bittorrent"; + }; + + Preallocation = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Preallocation of storage."; + }; + + QueueingSystemEnabled = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Enable queueing system."; + }; + + SubcategoriesEnabled = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Enable subcategories."; + }; + + Tags = lib.mkOption { + type = lib.types.str; + default = ""; + description = "Tags"; + }; + + TempPath = lib.mkOption { + type = lib.types.str; + default = "${path}/temp"; + description = "Temporary path."; + }; + + TempPathEnabled = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Enable temporary path."; + }; + + TorrentExportDirectory = lib.mkOption { + type = lib.types.str; + default = "${path}/torrents"; + description = "Torrent export directory."; + }; + + UseAlternativeGlobalSpeedLimit = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Use alternative global speed limit."; + }; + + # Core + AutoDeleteAddedTorrentFile = lib.mkOption { + type = lib.types.str; + default = "Never"; + description = "Auto delete added torrent file."; + }; + + # LegalNotice + Accepted = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Accepted legal notice."; + }; + + # Meta + MigrationVersion = lib.mkOption { + type = lib.types.int; + default = 6; + description = "Migration version."; + }; + + # Network + PortForwardingEnabled = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Enable port forwarding."; + }; + + # Preferences + GeneralLocale = lib.mkOption { + type = lib.types.str; + default = "en"; + description = "General locale."; + }; + + MailNotificationReqAuth = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Mail notification requires authentication."; + }; + + SchedulerDays = lib.mkOption { + type = lib.types.str; + default = "Weekday"; + description = "Scheduler days."; + }; + + SchedulerEndTime = lib.mkOption { + type = lib.types.str; + default = "@Variant(\\0\\0\\0\\xf\\x5%q\\xa0)"; + description = "Scheduler end time."; + }; + + WebUIAuthSubnetWhitelist = lib.mkOption { + type = lib.types.str; + default = ""; + example = "192.168.1.0/24, 10.0.0.0/24"; + description = "WebUI auth subnet whitelist."; + }; + + WebUIAuthSubnetWhitelistEnabled = lib.mkOption { + type = lib.types.bool; + default = false; + description = "WebUI auth subnet whitelist enabled."; + }; + + WebUIPort = lib.mkOption { + type = lib.types.int; + default = 8080; + description = "WebUI port."; + }; + + WebUIUseUPnP = lib.mkOption { + type = lib.types.bool; + default = false; + description = "WebUI use UPnP."; + }; + + # RSS + AutoDownloaderDownloadRepacks = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Auto downloader download repacks."; + }; + + AutoDownloaderEnableProcessing = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Auto downloader enable processing."; + }; + + AutoDownloaderSmartEpisodeFilter = lib.mkOption { + type = lib.types.str; + default = "s(\\d+)e(\\d+), (\\d+)x(\\d+), \"(\\d{4}[.\\-]\\d{1,2}[.\\-]\\d{1,2})\", \"(\\d{1,2}[.\\-]\\d{1,2}[.\\-]\\d{4})\""; + example = "s(\\d+)e(\\d+), (\\d+)x(\\d+), \"(\\d{4}[.\\-]\\d{1,2}[.\\-]\\d{1,2})\", \"(\\d{1,2}[.\\-]\\d{1,2}[.\\-]\\d{4})\""; + description = "Auto downloader smart episode filter."; + }; + + SessionEnableProcessing = lib.mkOption { + type = lib.types.bool; + default = false; + description = "RSS Session enable processing."; + }; + + configFile = lib.mkOption { + type = lib.types.path; + default = "${cfgPath}"; + description = "Path to qbittorrent-nox configuration file."; + }; + + }; + + config = lib.mkIf cfg.enable { + + networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [ cfg.Port cfg.WebUIPort ]; + networking.firewall.allowedUDPPorts = lib.mkIf cfg.openFirewall [ cfg.Port cfg.WebUIPort]; + + users.users = lib.mkIf (cfg.user == "qbittorrent") { + qbittorrent = { + isSystemUser = true; + home = "/var/lib/qbittorrent"; + group = cfg.group; + }; + }; + users.groups = lib.mkIf (cfg.group == "qbittorrent") { + qbittorrent = {}; + }; + + systemd.services."qbittorrent-nox@" ={ + serviceConfig = { + ExecStart = "qbittorrent-nox -d --configuration=${cfg.configFile}"; + User = cfg.user; + Group = cfg.group; + Restart = "on-failure"; + + # Security options + PrivateTmp = true; + ProtectSystem = "full"; + ProtectKernelTunables = true; + ProtectKernelModules = true; + ProtectControlGroups = true; + }; + }; + + }; +} \ No newline at end of file diff --git a/services/qbittorrent.nix b/services/qbittorrent.nix new file mode 100644 index 0000000..1c15c8e --- /dev/null +++ b/services/qbittorrent.nix @@ -0,0 +1,83 @@ +{ config, lib, pkgs, options, ... }: +let + port = 8090; + Interface = "tun0"; + InterfaceAddress = ""; + torrentPort = 44183; + TempPath = "/Main/Data/media/Downloads/temp"; + TorrentExportPath = "/Main/Data/media/Downloads/torrents"; + FinishedTorrentExportDirectory = "/Main/Data/media/Downloads/torrents-complete"; +in +{ + imports = [ + ../modules/qbittorrent-nox.nix + ]; + + environment.systemPackages = [ + pkgs.qbittorrent-nox + ]; + + services.qbittorrent-nox = { + enable = true; + Interface = Interface; + openFirewall = true; + user = "qbittorrent"; + group = "qbittorrent"; + Filelogger = { + enable = true; + age = 1; + ageType = 1; + backup = true; + deleteOld = true; + maxSizeBytes = 66560; + path = "/Main/Data/media/.qbittorrent/logs"; + }; + MemoryWorkingSetLimit = 8192; + AddExtensionToIncompleteFiles = true; + AlternativeGlobalDLSpeedLimit = 1000; + AlternativeGlobalUPSpeedLimit = 1000; + AnonymousModeEnabled = false; + BTProtocol = "Both"; + BandwidthSchedulerEnabled = false; + DefaultSavePath = TorrentExportPath; + Encryption = 1; + ExcludedFileNames = ""; + FinishedTorrentExportDirectory = FinishedTorrentExportDirectory; + GlobalDLSpeedLimit = 0; + GlobalMaxRatio = 1.5; + GlobalUPSpeedLimit = 0; + I2PEnabled = true; + IgnoreLimitsOnLAN = true; + IncludeOverheadInLimits = true; + InterfaceAddress = InterfaceAddress; + InterfaceName = Interface; + LSDEnabled = true; + MaxActiveCheckingTorrents = 15; + MaxRatioAction = 1; + Port = torrentPort; + Preallocation = true; + QueueingSystemEnabled = false; + SubcategoriesEnabled = true; + Tags = "movie, anime"; + TempPath = TempPath; + TempPathEnabled = true; + TorrentExportDirectory = TorrentExportPath; + UseAlternativeGlobalSpeedLimit = false; + AutoDeleteAddedTorrentFile = "Never"; + Accepted = true; + MigrationVersion = 6; + PortForwardingEnabled = true; + GeneralLocale = "en"; + MailNotificationReqAuth = true; + SchedulerDays = "Weekday"; + SchedulerEndTime = "@Variant(\\0\\0\\0\\xf\\x5%q\\xa0)"; + WebUIAuthSubnetWhitelist = "192.168.1.0/24, 100.0.0.0/8"; + WebUIAuthSubnetWhitelistEnabled = true; + WebUIPort = port; + WebUIUseUPnP = false; + AutoDownloaderDownloadRepacks = true; + AutoDownloaderEnableProcessing = true; + AutoDownloaderSmartEpisodeFilter = "s(\\d+)e(\\d+), (\\d+)x(\\d+), \"(\\d{4}[.\\-]\\d{1,2}[.\\-]\\d{1,2})\", \"(\\d{1,2}[.\\-]\\d{1,2}[.\\-]\\d{4})\""; + SessionEnableProcessing = true; + }; +} \ No newline at end of file diff --git a/services/torrent.nix b/services/torrent.nix deleted file mode 100644 index 47b0316..0000000 --- a/services/torrent.nix +++ /dev/null @@ -1,29 +0,0 @@ -{ config, lib, pkgs, options, ... }: -let - port = 8090; - configLocation = "~/.config/qBittorrent/qBittorrent.conf"; -in -{ - - environment.systemPackages = [ - pkgs.qbittorrent-nox - ]; - systemd.services."qbittorrent-nox@" = { - serviceConfig.ExecStart = let - in "qbittorrent-nox -d --webui-port=${port}"; - }; - - -#services.transmission = { -# enable = false; #Enable transmission daemon -# openRPCPort = true; #Open firewall for RPC -# settings = { #Override default settings -# rpc-bind-address = "0.0.0.0"; #Bind to own IP -# rpc-whitelist = "127.0.0.1,192.168.0.0/23,10.0.0.0/23,100.0.0.0/8,100.117.216.131 "; #Whitelist your remote machine (10.0.0.1 in this example) -# }; - -}; - - - -}