Prove
This commit is contained in:
parent
4300ddacb0
commit
b80563f0ed
10 changed files with 755 additions and 1 deletions
1
lxc-nix
1
lxc-nix
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit 171675dae9dd0e673416badf01ef4cc1ee33c96c
|
|
||||||
12
lxc-nix/buildLxcImage.sh
Executable file
12
lxc-nix/buildLxcImage.sh
Executable file
|
|
@ -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}"
|
||||||
131
lxc-nix/configuration.nix
Normal file
131
lxc-nix/configuration.nix
Normal file
|
|
@ -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";
|
||||||
|
}
|
||||||
126
lxc-nix/modules/qbittorrent.nix
Normal file
126
lxc-nix/modules/qbittorrent.nix
Normal file
|
|
@ -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; };
|
||||||
|
# };
|
||||||
|
};
|
||||||
|
}
|
||||||
325
lxc-nix/modules/rutorrent.nix
Normal file
325
lxc-nix/modules/rutorrent.nix
Normal file
|
|
@ -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 <link xlink:href="https://github.com/Novik/ruTorrent/wiki/Plugins#currently-there-are-the-following-plugins">available plugins</link>. Note: the <literal>unpack</literal> plugin needs the nonfree <literal>unrar</literal> package.
|
||||||
|
You need to either enable one of the <literal>rpc</literal> or <literal>httprpc</literal> plugin or enable the <xref linkend="opt-services.rutorrent.nginx.exposeInsecureRPC2mount"/> 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 <literal>php-fpm.conf</literal> 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 <literal>services.nginx.virtualHosts.<name></literal>.
|
||||||
|
See <xref linkend="opt-services.nginx.virtualHosts"/> for further information.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
exposeInsecureRPC2mount = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = ''
|
||||||
|
If you do not enable one of the <literal>rpc</literal> or <literal>httprpc</literal> 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 <literal>services.nginx.virtualHosts.<name>.basicAuth</literal> 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" ''
|
||||||
|
<?php
|
||||||
|
// configuration parameters
|
||||||
|
|
||||||
|
// for snoopy client
|
||||||
|
@define('HTTP_USER_AGENT', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.87 Safari/537.36', true);
|
||||||
|
@define('HTTP_TIME_OUT', 30, true); // in seconds
|
||||||
|
@define('HTTP_USE_GZIP', true, true);
|
||||||
|
$httpIP = null; // IP string. Or null for any.
|
||||||
|
$httpProxy = array
|
||||||
|
(
|
||||||
|
'use' => 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};
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
})
|
||||||
|
]))
|
||||||
|
]);
|
||||||
|
}
|
||||||
27
lxc-nix/packages/rutorrent.nix
Normal file
27
lxc-nix/packages/rutorrent.nix
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
{ pkgs ? import <nixpkgs> { }, 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;
|
||||||
|
};
|
||||||
|
}
|
||||||
10
lxc-nix/parameters.nix
Normal file
10
lxc-nix/parameters.nix
Normal file
|
|
@ -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
|
||||||
|
}
|
||||||
26
lxc-nix/services/networking.nix
Normal file
26
lxc-nix/services/networking.nix
Normal file
|
|
@ -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" ];
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
29
lxc-nix/services/qbittorrent.nix
Normal file
29
lxc-nix/services/qbittorrent.nix
Normal file
|
|
@ -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 ];
|
||||||
|
}
|
||||||
69
lxc-nix/services/rutorrent.nix
Normal file
69
lxc-nix/services/rutorrent.nix
Normal file
|
|
@ -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;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue