diff --git a/lxc-nix b/lxc-nix
deleted file mode 160000
index 171675d..0000000
--- a/lxc-nix
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 171675dae9dd0e673416badf01ef4cc1ee33c96c
diff --git a/lxc-nix/buildLxcImage.sh b/lxc-nix/buildLxcImage.sh
new file mode 100755
index 0000000..c4a3e46
--- /dev/null
+++ b/lxc-nix/buildLxcImage.sh
@@ -0,0 +1,12 @@
+#! /usr/bin/env nix-shell
+#! nix-shell -p nixos-generators
+#! nix-shell -i bash
+set -xe
+
+CONFIGURATIONNIX=$1
+METAIMG=$(nixos-generate -f lxc-metadata)
+# IMG_PROXMOX=`nixos-generate -c ${CONFIGURATIONNIX} -f proxmox-lxc`
+IMG=$(nixos-generate -c "${CONFIGURATIONNIX}" -f lxc)
+
+lxc image delete nixos || echo true
+lxc image import --alias nixos "${METAIMG}" "${IMG}"
diff --git a/lxc-nix/configuration.nix b/lxc-nix/configuration.nix
new file mode 100644
index 0000000..c37a4c3
--- /dev/null
+++ b/lxc-nix/configuration.nix
@@ -0,0 +1,131 @@
+{ config, pkgs, ... }:
+
+let
+
+ parameters = import ./parameters.nix { };
+
+ # GID = 888;
+ # user = "rtorrent";
+ # passwordHash = "$y$j9T$dA94KVg1/jYLqclQQbTDk.$cnfxBWUN8P4shr8Kkipv5bU/RCtQNoAwYFDZ0X/BYs5";
+
+ timeZone = "Europe/Rome";
+ defaultLocale = "en_US.UTF-8";
+in
+{
+ imports = [
+
+ # Need to load some defaults for running in an lxc container.
+ # This is explained in:
+ # https://github.com/nix-community/nixos-generators/issues/79
+ # "${modulesPath}/virtualisation/lxc-container.nix"
+
+ # ./modules/qbittorrent.nix
+ #./modules/rutorrent.nix
+
+ # ./services/qbittorrent.nix
+ #./services/rutorrent.nix
+ ./services/networking.nix
+ ];
+
+ # This doesn't do _everything_ we need, because `boot.isContainer` is
+ # specifically talking about light-weight NixOS containers, not LXC. But it
+ # does at least gives us something to start with.
+ boot.isContainer = true;
+
+ networking = {
+ hostName = parameters.containerName;
+ };
+
+ nixpkgs.config.allowUnfree = true;
+
+ # Extra packages
+ # environment.systemPackages = with pkgs; [ ];
+
+ services = {
+ openssh.enable = true;
+ tailscale = {
+ enable = false;
+ useRoutingFeatures = "both";
+ extraUpFlags = [ "--exit-node=${parameters.tailscaleExitNodeIP}" ];
+ authKeyFile = builtins.toFile "authKey" ''${parameters.tailscaleAuthKey}'';
+ };
+ };
+
+ time.timeZone = parameters.timeZone;
+
+ i18n = {
+ defaultLocale = defaultLocale;
+ extraLocaleSettings = {
+ LC_ADDRESS = defaultLocale;
+ LC_IDENTIFICATION = defaultLocale;
+ LC_MEASUREMENT = defaultLocale;
+ LC_MONETARY = defaultLocale;
+ LC_NAME = defaultLocale;
+ LC_PAPER = defaultLocale;
+ LC_TELEPHONE = defaultLocale;
+ # LC_NUMERIC = defaultLocale;
+ # LC_TIME = defaultLocale;
+ };
+ };
+
+ users = {
+
+ # If set to false, the contents of the user and group files will simply
+ # be replaced on system activation.
+ # This also holds for the user passwords.
+ # All changed passwords will be reset according
+ # to the `users.users` configuration on activation.
+ mutableUsers = false;
+
+ users.root = {
+ hashedPassword = "$6$gir1YD6tNdC9xAj0$zLr1yt/ea9PvwygjHfQVnPmeCd1.2zrAKWiN80duidwOkZF6hwm06ta6J3O9uw6F3uUHC0N7iiKYhCgXXR.Q7/";
+ openssh.authorizedKeys.keys = [
+ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDhiGLc/whCY3lCmDiRlYnMJOLiO/gvcRj/sKVEFVAhQ pazpi@deadbeef"
+ ];
+ };
+
+ users.pazpi = {
+ isNormalUser = true;
+ shell = pkgs.bash;
+ openssh.authorizedKeys.keys = [
+ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDhiGLc/whCY3lCmDiRlYnMJOLiO/gvcRj/sKVEFVAhQ pazpi@deadbeef"
+ ];
+ };
+
+ # groups = {
+ # qbittorrent = { gid = GID; };
+ # };
+
+ # users."${user}" = {
+ # isNormalUser = true;
+ # group = "qbittorrent";
+ # extraGroups = [ "user" "multimedia" ];
+ # # initialHashedPassword = passwordHash;
+ # };
+ };
+
+ # # Enable passwordless sudo.
+ # security.sudo.extraRules = [
+ # {
+ # users = [ user ];
+ # commands = [
+ # {
+ # command = "ALL";
+ # options = [ "NOPASSWD" ];
+ # }
+ # ];
+ # }
+ # ];
+
+ # Supress systemd units that don't work because of LXC.
+ # https://blog.xirion.net/posts/nixos-proxmox-lxc/#configurationnix-tweak
+ systemd.suppressedSystemUnits = [
+ "dev-mqueue.mount"
+ "sys-kernel-debug.mount"
+ "sys-fs-fuse-connections.mount"
+ ];
+
+ nix.settings.experimental-features = [ "nix-command" "flakes" ];
+
+ system.stateVersion = "24.05";
+}
diff --git a/lxc-nix/modules/qbittorrent.nix b/lxc-nix/modules/qbittorrent.nix
new file mode 100644
index 0000000..b319c9b
--- /dev/null
+++ b/lxc-nix/modules/qbittorrent.nix
@@ -0,0 +1,126 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+ cfg = config.services.qbittorrent;
+ UID = 888;
+ GID = 888;
+in
+{
+ options.services.qbittorrent = {
+ enable = mkEnableOption (lib.mdDoc "qBittorrent headless");
+
+ dataDir = mkOption {
+ type = types.path;
+ default = "/var/lib/qbittorrent";
+ description = lib.mdDoc ''
+ The directory where qBittorrent stores its data files.
+ '';
+ };
+
+ user = mkOption {
+ type = types.str;
+ default = "qbittorrent";
+ description = lib.mdDoc ''
+ User account under which qBittorrent runs.
+ '';
+ };
+
+ group = mkOption {
+ type = types.str;
+ default = "qbittorrent";
+ description = lib.mdDoc ''
+ Group under which qBittorrent runs.
+ '';
+ };
+
+ port = mkOption {
+ type = types.port;
+ default = 8080;
+ description = lib.mdDoc ''
+ qBittorrent web UI port.
+ '';
+ };
+
+ openFirewall = mkOption {
+ type = types.bool;
+ default = false;
+ description = lib.mdDoc ''
+ Open services.qBittorrent.port to the outside network.
+ '';
+ };
+
+ package = mkOption {
+ type = types.package;
+ default = pkgs.qbittorrent-nox;
+ defaultText = literalExpression "pkgs.qbittorrent-nox";
+ description = lib.mdDoc ''
+ The qbittorrent package to use.
+ '';
+ };
+ };
+
+ config = mkIf cfg.enable {
+ networking.firewall = mkIf cfg.openFirewall {
+ allowedTCPPorts = [ cfg.port ];
+ };
+
+ systemd.services.qbittorrent = {
+ # based on the plex.nix service module and
+ # https://github.com/qbittorrent/qBittorrent/blob/master/dist/unix/systemd/qbittorrent-nox%40.service.in
+ description = "qBittorrent-nox service";
+ documentation = [ "man:qbittorrent-nox(1)" ];
+ after = [ "network.target" ];
+ wantedBy = [ "multi-user.target" ];
+
+ serviceConfig = {
+ Type = "simple";
+ User = cfg.user;
+ Group = cfg.group;
+
+ # Run the pre-start script with full permissions (the "!" prefix) so it
+ # can create the data directory if necessary.
+ ExecStartPre =
+ let
+ preStartScript = pkgs.writeScript "qbittorrent-run-prestart" ''
+ #!${pkgs.bash}/bin/bash
+
+ # Create data directory if it doesn't exist
+ if ! test -d "$QBT_PROFILE"; then
+ echo "Creating initial qBittorrent data directory in: $QBT_PROFILE"
+ install -d -m 0755 -o "${cfg.user}" -g "${cfg.group}" "$QBT_PROFILE"
+ fi
+ '';
+ in
+ "!${preStartScript}";
+
+ #ExecStart = "${pkgs.qbittorrent-nox}/bin/qbittorrent-nox";
+ ExecStart = "${cfg.package}/bin/qbittorrent-nox";
+ # To prevent "Quit & shutdown daemon" from working; we want systemd to
+ # manage it!
+ #Restart = "on-success";
+ #UMask = "0002";
+ #LimitNOFILE = cfg.openFilesLimit;
+ };
+
+ environment = {
+ QBT_PROFILE = cfg.dataDir;
+ QBT_WEBUI_PORT = toString cfg.port;
+ QBT_EULA = "accept";
+ # QBT_EULA = toString cfg.acceptEula;
+ };
+ };
+
+ # users.users = mkIf (cfg.user == "qbittorrent") {
+ # qbittorrent = {
+ # group = cfg.group;
+ # uid = UID;
+ # };
+ # };
+
+ # users.groups = mkIf (cfg.group == "qbittorrent") {
+ # qbittorrent = { gid = GID; };
+ # };
+ };
+}
diff --git a/lxc-nix/modules/rutorrent.nix b/lxc-nix/modules/rutorrent.nix
new file mode 100644
index 0000000..54eaab5
--- /dev/null
+++ b/lxc-nix/modules/rutorrent.nix
@@ -0,0 +1,325 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+ cfg = config.services.rutorrent;
+
+ rutorrentPkgs = import ../packages/rutorrent.nix { inherit pkgs; inherit lib; };
+
+ rtorrentPluginDependencies = with pkgs; {
+ _task = [ procps ];
+ unpack = [ unzip unrar ];
+ rss = [ curl ];
+ mediainfo = [ mediainfo ];
+ spectrogram = [ sox ];
+ screenshots = [ ffmpeg ];
+ };
+
+ phpPluginDependencies = with pkgs; {
+ _cloudflare = [ python3 ];
+ };
+
+ getPluginDependencies = dependencies: concatMap (p: attrByPath [ p ] [ ] dependencies);
+
+in
+{
+ options = {
+ services.rutorrent = {
+ enable = mkEnableOption "ruTorrent";
+
+ hostName = mkOption {
+ type = types.str;
+ description = "FQDN for the ruTorrent instance.";
+ };
+
+ dataDir = mkOption {
+ type = types.str;
+ default = "/var/lib/rutorrent";
+ description = "Storage path of ruTorrent.";
+ };
+
+ user = mkOption {
+ type = types.str;
+ default = "rutorrent";
+ description = ''
+ User which runs the ruTorrent service.
+ '';
+ };
+
+ group = mkOption {
+ type = types.str;
+ default = "rutorrent";
+ description = ''
+ Group which runs the ruTorrent service.
+ '';
+ };
+
+ rpcSocket = mkOption {
+ type = types.str;
+ default = config.services.rtorrent.rpcSocket;
+ defaultText = "config.services.rtorrent.rpcSocket";
+ description = ''
+ Path to rtorrent rpc socket.
+ '';
+ };
+
+ plugins = mkOption {
+ type = with types; listOf (either str package);
+ default = [ "httprpc" ];
+ example = literalExample ''[ "httprpc" "data" "diskspace" "edit" "erasedata" "theme" "trafic" ]'';
+ description = ''
+ List of plugins to enable. See the list of available plugins. Note: the unpack plugin needs the nonfree unrar package.
+ You need to either enable one of the rpc or httprpc plugin or enable the option.
+ '';
+ };
+
+ poolSettings = mkOption {
+ type = with types; attrsOf (oneOf [ str int bool ]);
+ default = {
+ "pm" = "dynamic";
+ "pm.max_children" = 32;
+ "pm.start_servers" = 2;
+ "pm.min_spare_servers" = 2;
+ "pm.max_spare_servers" = 4;
+ "pm.max_requests" = 500;
+ };
+ description = ''
+ Options for ruTorrent's PHP pool. See the documentation on php-fpm.conf for details on configuration directives.
+ '';
+ };
+
+ nginx = {
+ enable = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Whether to enable nginx virtual host management.
+ Further nginx configuration can be done by adapting services.nginx.virtualHosts.<name>.
+ See for further information.
+ '';
+ };
+
+ exposeInsecureRPC2mount = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ If you do not enable one of the rpc or httprpc plugins you need to expose an RPC mount through scgi using this option.
+ Warning: This allow to run arbitrary commands, as the rtorrent user, so make sure to use authentification. The simplest way would be to use the services.nginx.virtualHosts.<name>.basicAuth option.
+ '';
+ };
+ };
+ };
+ };
+
+ config = mkIf cfg.enable (mkMerge [
+ {
+ assertions =
+ let
+ usedRpcPlugins = intersectLists cfg.plugins [ "httprpc" "rpc" ];
+ in
+ [
+ {
+ assertion = (length usedRpcPlugins < 2);
+ message = "Please specify only one of httprpc or rpc plugins";
+ }
+ {
+ assertion = !(length usedRpcPlugins > 0 && cfg.nginx.exposeInsecureRPC2mount);
+ message = "Please do not use exposeInsecureRPC2mount if you use one of httprpc or rpc plugins";
+ }
+ ];
+
+ warnings =
+ let
+ nginxVhostCfg = config.services.nginx.virtualHosts."${cfg.hostName}";
+ in
+ [ ]
+ ++ (optional (cfg.nginx.exposeInsecureRPC2mount && (nginxVhostCfg.basicAuth == { } || nginxVhostCfg.basicAuthFile == null)) ''
+ You are using exposeInsecureRPC2mount without using basic auth on the virtual host. The exposed rpc mount allow for remote command execution.
+
+ Please make sure it is not accessible from the outside.
+ '');
+
+ systemd = {
+ services = {
+ rtorrent.path = getPluginDependencies rtorrentPluginDependencies cfg.plugins;
+ rutorrent-setup =
+ let
+ rutorrentConfig = pkgs.writeText "rutorrent-config.php" ''
+ false,
+ 'proto' => 'http', // 'http' or 'https'
+ 'host' => 'PROXY_HOST_HERE',
+ 'port' => 3128
+ );
+
+ @define('RPC_TIME_OUT', 5, true); // in seconds
+
+ @define('LOG_RPC_CALLS', false, true);
+ @define('LOG_RPC_FAULTS', true, true);
+
+ // for php
+ @define('PHP_USE_GZIP', false, true);
+ @define('PHP_GZIP_LEVEL', 2, true);
+
+ $schedule_rand = 10; // rand for schedulers start, +0..X seconds
+
+ $do_diagnostic = true;
+ $log_file = '${cfg.dataDir}/logs/errors.log'; // path to log file (comment or leave blank to disable logging)
+
+ $saveUploadedTorrents = true; // Save uploaded torrents to profile/torrents directory or not
+ $overwriteUploadedTorrents = false; // Overwrite existing uploaded torrents in profile/torrents directory or make unique name
+
+ $topDirectory = '/'; // Upper available directory. Absolute path with trail slash.
+ $forbidUserSettings = false;
+
+ $scgi_port = 0;
+ $scgi_host = "unix://${cfg.rpcSocket}";
+
+ $XMLRPCMountPoint = "/RPC2"; // DO NOT DELETE THIS LINE!!! DO NOT COMMENT THIS LINE!!!
+
+ $pathToExternals = array(
+ "php" => "${pkgs.php}/bin/php", // Something like /usr/bin/php. If empty, will be found in PATH.
+ "curl" => "${pkgs.curl}/bin/curl", // Something like /usr/bin/curl. If empty, will be found in PATH.
+ "gzip" => "${pkgs.gzip}/bin/gzip", // Something like /usr/bin/gzip. If empty, will be found in PATH.
+ "id" => "${pkgs.coreutils}/bin/id", // Something like /usr/bin/id. If empty, will be found in PATH.
+ "stat" => "${pkgs.coreutils}/bin/stat", // Something like /usr/bin/stat. If empty, will be found in PATH.
+ "pgrep" => "${pkgs.procps}/bin/pgrep", // TODO why can't we use phpEnv.PATH
+ );
+
+ $localhosts = array( // list of local interfaces
+ "127.0.0.1",
+ "localhost",
+ );
+
+ $profilePath = '${cfg.dataDir}/share'; // Path to user profiles
+ $profileMask = 0770; // Mask for files and directory creation in user profiles.
+ // Both Webserver and rtorrent users must have read-write access to it.
+ // For example, if Webserver and rtorrent users are in the same group then the value may be 0770.
+
+ $tempDirectory = null; // Temp directory. Absolute path with trail slash. If null, then autodetect will be used.
+
+ $canUseXSendFile = false; // If true then use X-Sendfile feature if it exist
+
+ $locale = "UTF8";
+
+ $throttleMaxSpeed = 327625*1024;
+ '';
+ in
+ {
+ wantedBy = [ "multi-user.target" ];
+ before = [ "phpfpm-rutorrent.service" ];
+ script = ''
+ ln -sf ${rutorrentPkgs}/{css,images,js,lang,index.html} ${cfg.dataDir}/
+ mkdir -p ${cfg.dataDir}/{conf,logs,plugins} ${cfg.dataDir}/share/{settings,torrents,users}
+ ln -sf ${rutorrentPkgs}/conf/{access.ini,plugins.ini} ${cfg.dataDir}/conf/
+ ln -sf ${rutorrentConfig} ${cfg.dataDir}/conf/config.php
+
+ cp -r ${rutorrentPkgs}/php ${cfg.dataDir}/
+
+ ${optionalString (cfg.plugins != [])
+ ''cp -r ${concatMapStringsSep " " (p: "${rutorrentPkgs}/plugins/${p}") cfg.plugins} ${cfg.dataDir}/plugins/''}
+
+ chown -R ${cfg.user}:${cfg.group} ${cfg.dataDir}/{conf,share,logs,plugins}
+ chmod -R 755 ${cfg.dataDir}/{conf,share,logs,plugins}
+ '';
+ serviceConfig.Type = "oneshot";
+ };
+ };
+
+ tmpfiles.rules = [ "d '${cfg.dataDir}' 0775 ${cfg.user} ${cfg.group} -" ];
+ };
+
+ users.groups."${cfg.group}" = { };
+
+ users.users = {
+ "${cfg.user}" = {
+ home = cfg.dataDir;
+ group = cfg.group;
+ extraGroups = [ config.services.rtorrent.group ];
+ description = "ruTorrent Daemon user";
+ isSystemUser = true;
+ };
+
+ "${config.services.rtorrent.user}" = {
+ extraGroups = [ cfg.group ];
+ };
+ };
+ }
+
+ (mkIf cfg.nginx.enable (mkMerge [
+ {
+
+ networking.firewall = {
+ allowedTCPPorts = [ 80 443 ];
+ };
+
+ services = {
+
+ nginx = {
+ enable = true;
+ user = cfg.user;
+ group = cfg.group;
+ virtualHosts = {
+ ${cfg.hostName} = {
+ root = cfg.dataDir;
+ locations = {
+ "~ [^/]\.php(/|$)" = {
+ extraConfig = ''
+ fastcgi_split_path_info ^(.+?\.php)(/.*)$;
+ if (!-f $document_root$fastcgi_script_name) {
+ return 404;
+ }
+
+ # Mitigate https://httpoxy.org/ vulnerabilities
+ fastcgi_param HTTP_PROXY "";
+
+ fastcgi_pass unix:${config.services.phpfpm.pools.rutorrent.socket};
+ fastcgi_index index.php;
+
+ include ${pkgs.nginx}/conf/fastcgi.conf;
+ '';
+ };
+ };
+ };
+ };
+ };
+
+ phpfpm.pools.rutorrent =
+ let
+ envPath = lib.makeBinPath (getPluginDependencies phpPluginDependencies cfg.plugins);
+ pool = {
+ user = cfg.user;
+ group = config.services.rtorrent.group;
+ settings = mapAttrs (name: mkDefault)
+ {
+ "listen.owner" = config.services.nginx.user;
+ "listen.group" = config.services.nginx.group;
+ } // cfg.poolSettings;
+ };
+ in
+ if (envPath == "") then pool else pool // { phpEnv.PATH = envPath; };
+
+ };
+ }
+
+ (mkIf cfg.nginx.exposeInsecureRPC2mount {
+ services.nginx.virtualHosts."${cfg.hostName}".locations."/RPC2" = {
+ extraConfig = ''
+ include ${pkgs.nginx}/conf/scgi_params;
+ scgi_pass unix:${cfg.rpcSocket};
+ '';
+ };
+ })
+ ]))
+ ]);
+}
diff --git a/lxc-nix/packages/rutorrent.nix b/lxc-nix/packages/rutorrent.nix
new file mode 100644
index 0000000..8907240
--- /dev/null
+++ b/lxc-nix/packages/rutorrent.nix
@@ -0,0 +1,27 @@
+{ pkgs ? import { }, lib, }:
+
+with pkgs;
+
+stdenv.mkDerivation rec {
+ pname = "rutorrent";
+ version = "4.2.9";
+
+ src = fetchFromGitHub {
+ owner = "Novik";
+ repo = "ruTorrent";
+ rev = "v${version}";
+ sha256 = "qgtP8IOJ5R8IWXf34MSa5WiH68oRG2j/IjGC2TPfQc0=";
+ };
+
+ installPhase = ''
+ mkdir -p $out/
+ cp -r . $out/
+ '';
+
+ meta = with lib; {
+ description = "Yet another web front-end for rTorrent";
+ homepage = "https://github.com/Novik/ruTorrent";
+ license = licenses.gpl3Plus;
+ platforms = platforms.unix;
+ };
+}
diff --git a/lxc-nix/parameters.nix b/lxc-nix/parameters.nix
new file mode 100644
index 0000000..5011ac7
--- /dev/null
+++ b/lxc-nix/parameters.nix
@@ -0,0 +1,10 @@
+{ ... }:
+{
+ containerName = "nixos-test"; # Name of the container, used for nginx virtualhost and for tailscale machine name
+ timeZone = "Europe/Rome"; # TimeZone
+
+ downloadDir = "/mnt/data"; # Main download folder
+
+ tailscaleAuthKey = "tskey-auth-kmgDY87CNTRL-urQA7eRn235t8Sjs6hW3259wJHE63Kvd";
+ tailscaleExitNodeIP = "100.81.1.32"; # vps
+}
diff --git a/lxc-nix/services/networking.nix b/lxc-nix/services/networking.nix
new file mode 100644
index 0000000..3fd223e
--- /dev/null
+++ b/lxc-nix/services/networking.nix
@@ -0,0 +1,26 @@
+{ ... }:
+{
+
+ networking = {
+
+ # If you prefer DHCP
+ # interfaces.eth0.useDHCP = true;
+
+ # We don't use DHCP, so we configure it statically.
+ interfaces.eth0.ipv4.addresses = [{
+ address = "10.42.135.101";
+ prefixLength = 24;
+ }];
+
+ # We can access the internet through this interface.
+ defaultGateway = {
+ address = "10.42.135.1";
+ interface = "eth0";
+ };
+
+ # Since we don't use DHCP, we need to set our own nameservers.
+ nameservers = [ "1.1.1.1" "1.0.0.1" ];
+
+ };
+
+}
diff --git a/lxc-nix/services/qbittorrent.nix b/lxc-nix/services/qbittorrent.nix
new file mode 100644
index 0000000..36114e6
--- /dev/null
+++ b/lxc-nix/services/qbittorrent.nix
@@ -0,0 +1,29 @@
+# qBittorrent service activation
+#
+# The shell script 'fixdlperms' is also created and should be added to the
+# "Run external program on finished" section with the full path:
+# /run/current-system/sw/bin/fixdlperms
+
+{ pkgs, ... }:
+
+let
+ downloadDir = "/data/multimedia/downloads";
+ fixDownloadPerms = pkgs.writeShellScriptBin "fixdlperms" ''
+ find ${downloadDir} -type d -exec chmod 2775 {} +
+ find ${downloadDir} -type f -exec chmod 0664 {} +
+ '';
+in
+{
+ services.qbittorrent = {
+ enable = true;
+ openFirewall = true;
+ dataDir = "/srv/qbittorrent";
+ port = 58080;
+ user = "qbittorrent";
+ };
+
+ # Allow qbittorrent to save files in the multimedia share
+ # users.users.qbittorrent.extraGroups = [ "multimedia" ];
+
+ environment.systemPackages = [ fixDownloadPerms ];
+}
diff --git a/lxc-nix/services/rutorrent.nix b/lxc-nix/services/rutorrent.nix
new file mode 100644
index 0000000..166a3f2
--- /dev/null
+++ b/lxc-nix/services/rutorrent.nix
@@ -0,0 +1,69 @@
+{ config, ... }:
+let
+ parameters = import ../parameters.nix { };
+in
+{
+ services = {
+
+ rtorrent = {
+ enable = true;
+ openFirewall = true;
+ downloadDir = parameters.downloadDir;
+ };
+
+ rutorrent = {
+ enable = true;
+ hostName = parameters.containerName;
+ plugins = [
+ "_cloudflare"
+ "_getdir"
+ "_noty2"
+ "_task"
+ "autotools"
+ "check_port"
+ "chunks"
+ "cookies"
+ "cpuload"
+ # "сreate"
+ "data"
+ "datadir"
+ "diskspace"
+ "edit"
+ "erasedata"
+ "extratio"
+ "extsearch"
+ "feeds"
+ "filedrop"
+ "geoip"
+ "history"
+ "httprpc"
+ "ipad"
+ "loginmgr"
+ "lookat"
+ "mediainfo"
+ "ratio"
+ "retrackers"
+ "rss"
+ "rssurlrewrite"
+ "rutracker_check"
+ "scheduler"
+ "screenshots"
+ "seedingtime"
+ "show_peers_like_wtorrent"
+ "source"
+ "spectrogram"
+ "theme"
+ "throttle"
+ "tracklabels"
+ "trafic"
+ "unpack"
+ "uploadeta"
+ ];
+ nginx = {
+ enable = true;
+ # exposeInsecureRPC2mount = true;
+ };
+ };
+
+ };
+}