diff --git a/.vscode/settings.json b/.vscode/settings.json index a8bbf8c..ac3d269 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -11,16 +11,17 @@ "files.trimTrailingWhitespace": true, "sops.defaults.ageKeyFile": "age.key", "nix.enableLanguageServer": true, - "nix.serverPath": "/run/current-system/sw/bin/nil", + "nix.serverPath": "/run/current-system/sw/bin/nixd", "nix.formatterPath": "/run/current-system/sw/bin/nixfmt", "nix.serverSettings": { - "nil": { + "nixd": { "formatting": { "command": ["nixfmt"] }, - "diagnostics": { - "ignored": [], - "excludedFiles": [] + "options": { + "nixos": { + "expr": "(builtins.getFlake \"/home/jahanson/projects/mochi\").nixosConfigurations.shadowfax.options" + } } }, "nix": { diff --git a/nixos/hosts/shadowfax/default.nix b/nixos/hosts/shadowfax/default.nix index 966ac10..68625e7 100644 --- a/nixos/hosts/shadowfax/default.nix +++ b/nixos/hosts/shadowfax/default.nix @@ -4,28 +4,26 @@ inputs, pkgs, ... -}: -let - sanoidConfig = import ./config/sanoid.nix { }; +}: let + sanoidConfig = import ./config/sanoid.nix {}; disks = import ./config/disks.nix; - smartdDevices = map (device: { inherit device; }) disks; -in -{ + smartdDevices = map (device: {inherit device;}) disks; +in { imports = [ inputs.disko.nixosModules.disko (import ../../profiles/disko-nixos.nix { - disks = [ "/dev/sda|/dev/disk/by-id/nvme-Samsung_SSD_970_EVO_Plus_500GB_S58SNM0W406409E" ]; + disks = ["/dev/sda|/dev/disk/by-id/nvme-Samsung_SSD_970_EVO_Plus_500GB_S58SNM0W406409E"]; }) inputs.nix-minecraft.nixosModules.minecraft-servers ]; boot = { initrd = { - kernelModules = [ "nfs" ]; - supportedFilesystems = [ "nfs" ]; + kernelModules = ["nfs"]; + supportedFilesystems = ["nfs"]; }; - binfmt.emulatedSystems = [ "aarch64-linux" ]; # Enabled for arm compilation + binfmt.emulatedSystems = ["aarch64-linux"]; # Enabled for arm compilation kernelModules = [ "vfio" @@ -33,11 +31,11 @@ in "vfio_pci" "vfio_virqfd" ]; - extraModulePackages = [ ]; - kernelParams = [ "zfs.zfs_arc_max=107374182400" ]; # 100GB + extraModulePackages = []; + kernelParams = ["zfs.zfs_arc_max=107374182400"]; # 100GB }; - swapDevices = [ ]; + swapDevices = []; hardware = { cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; @@ -47,7 +45,7 @@ in nvidia-container-toolkit.enable = true; }; - users.users.root.openssh.authorizedKeys.keys = [ ]; + users.users.root.openssh.authorizedKeys.keys = []; # Network settings networking = { @@ -103,7 +101,6 @@ in # Minio 9000 # console web interface 9001 # api interface - ]; }; @@ -120,7 +117,7 @@ in # Minio minio = { enable = true; - dataDir = [ "/eru/minio" ]; + dataDir = ["/eru/minio"]; rootCredentialsFile = config.sops.secrets."minio".path; }; @@ -147,7 +144,7 @@ in # Soft Serve - SSH git server soft-serve = { enable = true; - settings = import ./config/soft-serve.nix { }; + settings = import ./config/soft-serve.nix {}; }; # Tailscale @@ -159,7 +156,7 @@ in # VSCode Compatibility Settings vscode-server.enable = true; - xserver.videoDrivers = [ "nvidia" ]; + xserver.videoDrivers = ["nvidia"]; }; # sops @@ -169,19 +166,19 @@ in owner = "minio"; group = "minio"; mode = "400"; - restartUnits = [ "minio.service" ]; + restartUnits = ["minio.service"]; }; "syncthing/publicCert" = { sopsFile = ./secrets.sops.yaml; owner = "jahanson"; mode = "400"; - restartUnits = [ "syncthing.service" ]; + restartUnits = ["syncthing.service"]; }; "syncthing/privateKey" = { sopsFile = ./secrets.sops.yaml; owner = "jahanson"; mode = "400"; - restartUnits = [ "syncthing.service" ]; + restartUnits = ["syncthing.service"]; }; # "caddy/env" = { # sopsFile = ./secrets.sops.yaml; @@ -229,6 +226,19 @@ in publicCertPath = config.sops.secrets."syncthing/publicCert".path; privateKeyPath = config.sops.secrets."syncthing/privateKey".path; }; + # qBittorrent + qbittorrent = { + enable = true; + package = pkgs.unstable.qbittorrent.override {guiSupport = false;}; + user = "qbittorrent"; + group = "qbittorrent"; + dataDir = "/nahar/qbittorrent"; + downloadsDir = "/eru/media/qb/downloads/complete"; + webuiPort = 8456; + openFirewall = true; + hardening = true; + qbittorrentPort = 50413; + }; # ZFS nightly snapshot of container volumes zfs-nightly-snap = { enable = true; @@ -242,9 +252,9 @@ in system = { incus = { enable = true; - preseed = import ./config/incus-preseed.nix { }; + preseed = import ./config/incus-preseed.nix {}; }; - motd.networkInterfaces = [ "bond0" ]; + motd.networkInterfaces = ["bond0"]; nfs.enable = true; zfs.enable = true; zfs.mountPoolsAtBoot = [ diff --git a/nixos/modules/nixos/services/default.nix b/nixos/modules/nixos/services/default.nix index 80ab71c..e8216b9 100644 --- a/nixos/modules/nixos/services/default.nix +++ b/nixos/modules/nixos/services/default.nix @@ -10,6 +10,7 @@ ./nix-index-daily ./onepassword-connect ./podman + ./qbittorrent ./reboot-required-check.nix ./sanoid ./syncthing diff --git a/nixos/modules/nixos/services/qbittorrent/default.nix b/nixos/modules/nixos/services/qbittorrent/default.nix new file mode 100644 index 0000000..eb4cd4d --- /dev/null +++ b/nixos/modules/nixos/services/qbittorrent/default.nix @@ -0,0 +1,155 @@ +{ + config, + lib, + pkgs, + ... +}: +with lib; +let + cfg = config.mySystem.services.qbittorrent; +in +{ + options.mySystem.services.qbittorrent = { + enable = mkEnableOption "qBittorrent"; + + package = mkOption { + type = types.package; + default = pkgs.qbittorrent; + description = "qBittorrent package to use"; + }; + + user = mkOption { + type = types.str; + default = "qbittorrent"; + description = "User account under which qBittorrent runs"; + }; + + group = mkOption { + type = types.str; + default = "qbittorrent"; + description = "Group under which qBittorrent runs"; + }; + + dataDir = mkOption { + type = types.path; + default = "/var/lib/qbittorrent"; + description = "Storage directory for qBittorrent data"; + }; + + downloadsDir = mkOption { + type = types.path; + default = "/var/lib/qbittorrent/downloads"; + description = "Location to store the downloads"; + }; + + webuiPort = mkOption { + type = types.port; + default = 8080; + description = "Port for qBittorrent web interface"; + }; + + openFirewall = mkOption { + type = types.bool; + default = false; + description = "Open firewall ports for qBittorrent"; + }; + + hardening = mkOption { + type = types.bool; + default = true; + description = "Enable security hardening features"; + }; + + qbittorrentPort = mkOption { + type = types.port; + default = 6881; + description = "Port used for peer connections"; + }; + }; + + config = mkIf cfg.enable { + users.groups.${cfg.group} = { }; + users.users = mkIf (cfg.user == "qbittorrent") { + qbittorrent = { + inherit (cfg) group; + isSystemUser = true; + home = cfg.dataDir; + }; + }; + + environment.systemPackages = [ + cfg.package + ]; + + systemd.services.qbittorrent = { + environment = { + QBT_CONFIRM_LEGAL_NOTICE = "1"; + QBT_WEBUI_PORT = toString cfg.webuiPort; + QBT_TORRENTING_PORT = toString cfg.qbittorrentPort; + QBT_DOWNLOADS_PATH = "${cfg.downloadsDir}"; + XDG_CONFIG_HOME = cfg.dataDir; + XDG_DATA_HOME = cfg.dataDir; + CONFIG_DIR = "${cfg.dataDir}/qBittorrent"; + CONFIG_FILE = "${cfg.dataDir}/qBittorrent/config/qBittorrent.conf"; + LOG_DIR = "${cfg.dataDir}/logs"; + LOG_FILE = "${cfg.dataDir}/logs/qbittorrent.log"; + }; + + serviceConfig = lib.mkMerge [ + { + ExecStart = "${cfg.package}/bin/qbittorrent-nox --profile=${cfg.dataDir}"; + ReadWritePaths = [ + cfg.dataDir + cfg.downloadsDir + ]; + Restart = "on-failure"; + RestartSec = 5; + User = cfg.user; + Group = cfg.group; + } + (lib.mkIf cfg.hardening { + CapabilityBoundingSet = [ "" ]; + DeviceAllow = [ "" ]; + DevicePolicy = "closed"; + LockPersonality = true; + MemoryDenyWriteExecute = true; + NoNewPrivileges = true; + PrivateDevices = true; + PrivateTmp = true; + ProtectControlGroups = true; + ProtectHome = "read-only"; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectSystem = "strict"; + RestrictAddressFamilies = [ + "AF_INET" + "AF_INET6" + ]; + RestrictNamespaces = [ + "uts" + "ipc" + "pid" + "user" + "cgroup" + "net" + ]; + RestrictSUIDSGID = true; + SystemCallArchitectures = "native"; + SystemCallFilter = [ + "@system-service" + "~@privileged" + "~@resources" + ]; + }) + ]; + }; + + networking.firewall = mkIf cfg.openFirewall { + allowedTCPPorts = [ + cfg.webuiPort + cfg.qbittorrentPort + ]; + allowedUDPPorts = [ cfg.qbittorrentPort ]; + }; + }; +}