diff options
| author | Max Audron <audron@cocaine.farm> | 2024-02-07 14:46:29 +0000 |
|---|---|---|
| committer | Max Audron <audron@cocaine.farm> | 2024-02-07 17:27:40 +0000 |
| commit | 44ee565dfcf908df660751351d00caeb2ba39bc8 (patch) | |
| tree | 43a11284abc04d0657901f56e579dd86166814da | |
| parent | update authentik (diff) | |
migrate tlmp setup to nixos
| -rw-r--r-- | modules/tlmp/default.nix | 80 | ||||
| -rw-r--r-- | modules/tlmp/rtorrent.nix | 42 | ||||
| -rw-r--r-- | modules/tlmp/rtorrent.rc | 100 | ||||
| -rw-r--r-- | modules/tlmp/rutorrent.nix | 43 | ||||
| -rw-r--r-- | modules/tlmp/sonarr.nix | 57 |
5 files changed, 265 insertions, 57 deletions
diff --git a/modules/tlmp/default.nix b/modules/tlmp/default.nix index e653b29..e9f286f 100644 --- a/modules/tlmp/default.nix +++ b/modules/tlmp/default.nix @@ -2,7 +2,7 @@ with self.lib.nginx; { - imports = [ ./rutorrent.nix ]; + imports = [ ./rutorrent.nix ./rtorrent.nix ]; security.acme.certs = { "media.cocaine.farm" = { @@ -10,7 +10,37 @@ with self.lib.nginx; }; }; - services.jellyfin.enable = true; + users = { + users.media = { + isSystemUser = true; + group = "media"; + }; + groups.media = {}; + }; + + services.jellyfin = { + enable = true; + user = "media"; + group = "media"; + }; + + services.radarr = { + enable = true; + user = "media"; + group = "media"; + }; + + services.sonarr = { + enable = true; + package = pkgs.callPackage ./sonarr.nix {}; + user = "media"; + group = "media"; + }; + + services.prowlarr = { + enable = true; + }; + services.jackett = let jackett = pkgs.jackett.overrideAttrs (prev: { doCheck = false; @@ -24,43 +54,47 @@ with self.lib.nginx; services.rutorrent = { enable = true; hostName = "torrent.media.cocaine.farm"; - rpcSocket = "10.101.131.197"; plugins = lib.mkForce [ "data" "diskspace" "edit" "erasedata" "theme" "trafic" ]; nginx.enable = true; }; + virtualisation.oci-containers.containers = { + flaresolverr = { + image = "ghcr.io/flaresolverr/flaresolverr:v3.3.13"; + autoStart = true; + ports = [ + "10.10.0.2:8191:8191" + ]; + }; + }; + services.nginx = { enable = true; virtualHosts = { "media.cocaine.farm" = (proxyDomain "media.cocaine.farm" "http://127.0.0.1:8096/"); - "sonarr.media.cocaine.farm" = proxyDomainAuth "media.cocaine.farm" "http://10.101.73.6:80"; - "radarr.media.cocaine.farm" = proxyDomainAuth "media.cocaine.farm" "http://10.101.22.234:80"; + "sonarr.media.cocaine.farm" = proxyDomainAuth "media.cocaine.farm" "http://127.0.0.1:8989"; + "radarr.media.cocaine.farm" = proxyDomainAuth "media.cocaine.farm" "http://127.0.0.1:7878"; + "prowlarr.media.cocaine.farm" = proxyDomainAuth "media.cocaine.farm" "http://127.0.0.1:9696"; "jackett.media.cocaine.farm" = proxyDomainAuth "media.cocaine.farm" "http://127.0.0.1:9117"; - "torrent.media.cocaine.farm" = { - addSSL = true; - useACMEHost = "media.cocaine.farm"; + "torrent.media.cocaine.farm" = domainAuth "media.cocaine.farm"; + + "torrent.local" = { + listen = [{ + addr = "10.10.0.2"; + port = 80; + }]; locations."/RPC2" = { extraConfig = '' include ${pkgs.nginx}/conf/scgi_params; - scgi_pass 10.101.131.197:5000; + scgi_pass unix:/run/rtorrent/rpc.sock; ''; }; - - - # locations."/" = { - # proxyPass = "http://127.0.0.1"; - # proxyWebsockets = true; - # extraConfig = '' - # proxy_pass_header Authorization; - - # proxy_set_header X-Forwarded-Proto $scheme; - # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - # proxy_set_header Host $host; - # proxy_set_header Upgrade $http_upgrade; - # ''; - # }; }; }; }; + + networking.hosts = { + "10.10.0.2" = [ "torrent.local" ]; + }; } diff --git a/modules/tlmp/rtorrent.nix b/modules/tlmp/rtorrent.nix new file mode 100644 index 0000000..bf72a2a --- /dev/null +++ b/modules/tlmp/rtorrent.nix @@ -0,0 +1,42 @@ +{ config, lib, pkgs, ... }: + +{ + systemd.services = { + wireguard-mullvad = { + bindsTo = [ "netns@mullvad.service" ]; + after = [ "netns@mullvad.service" ]; + }; + + rtorrent = { + bindsTo = [ "wireguard-mullvad.service" ]; + after = [ "wireguard-mullvad.service" ]; + unitConfig.JoinsNamespaceOf = "netns@mullvad.service"; + serviceConfig.PrivateNetwork = true; + }; + }; + + networking.wireguard.interfaces = { + mullvad = { # Caring Wasp + ips = [ "10.67.4.3/32" "fc00:bbbb:bbbb:bb01::4:402/128" ]; + privateKeyFile = "/root/wireguard/privkey"; + interfaceNamespace = "mullvad"; + + peers = [ + { # de-fra-wg-006.relays.mullvad.net + publicKey = "nAF0wrLG2+avwQfqxnXhBGPUBCvc3QCqWKH4nK5PfEU="; + endpoint = "185.209.196.76:51820"; + allowedIPs = [ "0.0.0.0/0" "::/0" ]; + } + ]; + }; + }; + + services.rtorrent = { + enable = true; + # dataDir = "/mnt/media/download"; + user = "media"; + group = "media"; + + configText = lib.mkForce (lib.readFile ./rtorrent.rc); + }; +} diff --git a/modules/tlmp/rtorrent.rc b/modules/tlmp/rtorrent.rc new file mode 100644 index 0000000..3353f50 --- /dev/null +++ b/modules/tlmp/rtorrent.rc @@ -0,0 +1,100 @@ +############################################################################# +# A minimal rTorrent configuration that provides the basic features +# you want to have in addition to the built-in defaults. +# +# See https://github.com/rakshasa/rtorrent/wiki/CONFIG-Template +# for an up-to-date version. +############################################################################# + +# Instance layout (base paths) +method.insert = cfg.basedir, private|const|string, (cat,"/mnt/media/") +method.insert = cfg.watch, private|const|string, (cat,(cfg.basedir),"watch/") +method.insert = cfg.logs, private|const|string, (cat,"/var/log/rtorrent/") +method.insert = cfg.logfile, private|const|string, (cat,(cfg.logs),"rtorrent-",(system.time),".log") + +# Create instance directories +execute.throw = bash, -c, (cat,\ + "builtin cd \"", (cfg.basedir), "\" ",\ + "&& mkdir -p .session download watch/{load,start}") + +# Listening port for incoming peer traffic (fixed; you can also randomize it) +network.port_range.set = 50000-50000 +network.port_random.set = no + +# Tracker-less torrent and UDP tracker support +# (conservative settings for 'private' trackers, change for 'public') +dht.mode.set = disable +protocol.pex.set = no +trackers.use_udp.set = no + +# Peer settings +throttle.max_uploads.set = 100 +throttle.max_uploads.global.set = 250 + +throttle.min_peers.normal.set = 20 +throttle.max_peers.normal.set = 60 +throttle.min_peers.seed.set = 30 +throttle.max_peers.seed.set = 80 +trackers.numwant.set = 80 + +protocol.encryption.set = allow_incoming,try_outgoing,enable_retry + +# Limits for file handle resources, this is optimized for +# an `ulimit` of 1024 (a common default). You MUST leave +# a ceiling of handles reserved for rTorrent's internal needs! +network.http.max_open.set = 50 +network.max_open_files.set = 600 +network.max_open_sockets.set = 300 + +# Memory resource usage (increase if you have a large number of items loaded, +# and/or the available resources to spend) +pieces.memory.max.set = 1800M +network.xmlrpc.size_limit.set = 4M + +# Basic operational settings (no need to change these) +session.path.set = (cat, (cfg.basedir), ".session") +directory.default.set = (cat, (cfg.basedir), "download/") +log.execute = (cat, (cfg.logs), "execute.log") +##log.xmlrpc = (cat, (cfg.logs), "xmlrpc.log") +execute.nothrow = bash, -c, (cat, "echo >",\ + (session.path), "rtorrent.pid", " ", (system.pid)) + +# Other operational settings (check & adapt) +encoding.add = utf8 +system.umask.set = 0027 +system.cwd.set = (directory.default) +network.http.dns_cache_timeout.set = 25 +##network.http.capath.set = "/etc/ssl/certs" +##network.http.ssl_verify_peer.set = 0 +##network.http.ssl_verify_host.set = 0 +##pieces.hash.on_completion.set = no +##keys.layout.set = qwerty + +##view.sort_current = seeding, greater=d.ratio= +schedule2 = monitor_diskspace, 15, 60, ((close_low_diskspace, 1000M)) + +# Some additional values and commands +method.insert = system.startup_time, value|const, (system.time) +method.insert = d.data_path, simple,\ + "if=(d.is_multi_file),\ + (cat, (d.directory), /),\ + (cat, (d.directory), /, (d.name))" +method.insert = d.session_file, simple, "cat=(session.path), (d.hash), .torrent" + +# Watch directories (add more as you like, but use unique schedule names) +schedule2 = watch_start, 10, 10, ((load.start_verbose, (cat, (cfg.watch), "start/*.torrent"))) +schedule2 = watch_load, 11, 10, ((load.verbose, (cat, (cfg.watch), "load/*.torrent"))) + +# Logging: +# Levels = critical error warn notice info debug +# Groups = connection_* dht_* peer_* rpc_* storage_* thread_* tracker_* torrent_* +print = (cat, "Logging to ", (cfg.logfile)) +log.open_file = "log", (cfg.logfile) +log.add_output = "info", "log" +##log.add_output = "tracker_debug", "log" + +# XMLRPC +network.scgi.open_local = /run/rtorrent/rpc.sock +execute.nothrow = chmod,777,/run/rtorrent/rpc.sock + +### END of rtorrent.rc ### diff --git a/modules/tlmp/rutorrent.nix b/modules/tlmp/rutorrent.nix index 34bff4c..bfb8ef1 100644 --- a/modules/tlmp/rutorrent.nix +++ b/modules/tlmp/rutorrent.nix @@ -3,10 +3,10 @@ with lib; let - rutorrent = pkgs.callPackage ./rutorrent.pkg.nix {}; - cfg = config.services.rutorrent; + rutorrent = pkgs.callPackage ./rutorrent.pkg.nix {}; + rtorrentPluginDependencies = with pkgs; { _task = [ procps ]; unpack = [ unzip unrar ]; @@ -128,7 +128,6 @@ in { 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. ''); @@ -139,7 +138,6 @@ in { 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 @@ -152,32 +150,22 @@ in { '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 = 5000; - $scgi_host = "${cfg.rpcSocket}"; - + $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. @@ -186,21 +174,16 @@ in { "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"; ''; in { @@ -211,12 +194,9 @@ in { mkdir -p ${cfg.dataDir}/{conf,logs,plugins} ${cfg.dataDir}/share/{settings,torrents,users} ln -sf ${rutorrent}/conf/{access.ini,plugins.ini} ${cfg.dataDir}/conf/ ln -sf ${rutorrentConfig} ${cfg.dataDir}/conf/config.php - cp -r ${rutorrent}/php ${cfg.dataDir}/ - ${optionalString (cfg.plugins != []) ''cp -r ${concatMapStringsSep " " (p: "${rutorrent}/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} ''; @@ -233,14 +213,14 @@ in { "${cfg.user}" = { home = cfg.dataDir; group = cfg.group; - # extraGroups = [ config.services.rtorrent.group ]; + extraGroups = [ config.services.rtorrent.group ]; description = "ruTorrent Daemon user"; isSystemUser = true; }; - # "${config.services.rtorrent.user}" = { - # extraGroups = [ cfg.group ]; - # }; + "${config.services.rtorrent.user}" = { + extraGroups = [ cfg.group ]; + }; }; } @@ -250,7 +230,7 @@ in { envPath = lib.makeBinPath (getPluginDependencies phpPluginDependencies cfg.plugins); pool = { user = cfg.user; - group = config.services.rutorrent.group; + group = config.services.rtorrent.group; settings = mapAttrs (name: mkDefault) { "listen.owner" = config.services.nginx.user; "listen.group" = config.services.nginx.group; @@ -270,13 +250,10 @@ in { 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; ''; }; @@ -294,8 +271,6 @@ in { scgi_pass unix:${cfg.rpcSocket}; ''; }; - - # services.rtorrent.rpcGroup = "nginx"; }) ])) ]); diff --git a/modules/tlmp/sonarr.nix b/modules/tlmp/sonarr.nix new file mode 100644 index 0000000..cf56476 --- /dev/null +++ b/modules/tlmp/sonarr.nix @@ -0,0 +1,57 @@ +{ lib, stdenv, fetchurl, dotnet-runtime, icu, ffmpeg, openssl, sqlite, curl, makeWrapper, nixosTests }: + +let + os = if stdenv.isDarwin then "osx" else "linux"; + arch = { + x86_64-linux = "x64"; + aarch64-linux = "arm64"; + x86_64-darwin = "x64"; + aarch64-darwin = "arm64"; + }."${stdenv.hostPlatform.system}" or (throw "Unsupported system: ${stdenv.hostPlatform.system}"); + + hash = { + x64-linux_hash = "sha256-9YNhyhxnnn2CesXLJH5Cs7yB9w23YUAZPrk9vEHvevk="; + arm64-linux_hash = "sha256-RBCyfozmBpWrmsfMcdb1BqcBXj64CMDrgpMZTzj85ZQ="; + x64-osx_hash = "sha256-+AKENBZohBUEKQEM3L69EzC84MhCX3fGvsNFn5p2v84="; + arm64-osx_hash = "sha256-Arx8usecAN+d0NGL7Hv+rB4GG7p/KLAaqpJFgNg7C2Y="; + }."${arch}-${os}_hash"; +in +stdenv.mkDerivation rec { + pname = "sonarr"; + version = "4.0.1.929"; + + src = fetchurl { + url = "https://github.com/Sonarr/Sonarr/releases/download/v${version}/Sonarr.main.${version}.${os}-${arch}.tar.gz"; + inherit hash; + }; + + nativeBuildInputs = [ makeWrapper ]; + + installPhase = '' + runHook preInstall + + mkdir -p $out/{bin,share/sonarr-${version}} + cp -r * $out/share/sonarr-${version}/. + + makeWrapper "${dotnet-runtime}/bin/dotnet" $out/bin/NzbDrone \ + --add-flags "$out/share/sonarr-${version}/Sonarr.dll" \ + --prefix PATH : ${lib.makeBinPath [ ffmpeg ]} \ + --prefix LD_LIBRARY_PATH : ${lib.makeLibraryPath [ curl sqlite openssl icu ]} + + runHook postInstall + ''; + + passthru = { + updateScript = ./update.sh; + tests.smoke-test = nixosTests.sonarr; + }; + + meta = { + description = "Smart PVR for newsgroup and bittorrent users"; + homepage = "https://sonarr.tv/"; + license = lib.licenses.gpl3Only; + maintainers = with lib.maintainers; [ fadenb purcell ]; + mainProgram = "NzbDrone"; + platforms = lib.platforms.all; + }; +} |
