From ef42c9577aec764369d625e5ac4ca67988942e91 Mon Sep 17 00:00:00 2001 From: harry Date: Sun, 14 Jul 2024 15:48:01 +0200 Subject: [PATCH] splitted apps + rewrote everything from scratch --- .sops.yaml | 9 -- README.md | 7 + configuration.nix | 76 ++++++---- features/arr-suite.nix | 36 +++++ features/authentik.nix | 32 +++++ features/containers.nix | 36 +++++ features/homelab-dashboard.nix | 121 ++++++++++++++++ features/samba-shares.nix | 35 +++++ features/slskd.nix | 30 ++++ features/transmission.nix | 33 +++++ hardware-configuration.nix | 31 ++++ nix | 1 - nix/sources.json | 26 ++++ nix/sources.nix | 198 +++++++++++++++++++++++++ secrets/arrsuite.json | 26 ++++ secrets/authentik.env | 9 ++ secrets/searx.env | 9 ++ secrets/slskd.env | 10 ++ secrets/transmission.json | 24 ++++ server-configuration.nix | 256 +++------------------------------ 20 files changed, 731 insertions(+), 274 deletions(-) delete mode 100644 .sops.yaml create mode 100644 README.md create mode 100644 features/arr-suite.nix create mode 100644 features/authentik.nix create mode 100644 features/containers.nix create mode 100644 features/homelab-dashboard.nix create mode 100644 features/samba-shares.nix create mode 100644 features/slskd.nix create mode 100644 features/transmission.nix create mode 100644 hardware-configuration.nix delete mode 120000 nix create mode 100644 nix/sources.json create mode 100644 nix/sources.nix create mode 100644 secrets/arrsuite.json create mode 100644 secrets/authentik.env create mode 100644 secrets/searx.env create mode 100644 secrets/slskd.env create mode 100644 secrets/transmission.json diff --git a/.sops.yaml b/.sops.yaml deleted file mode 100644 index d782dcb..0000000 --- a/.sops.yaml +++ /dev/null @@ -1,9 +0,0 @@ -keys: - - &admin_cypherpunk age1c8kr95dc7cqq34qyjgpnsgfgyntqnt5rlrq2c025ehp32f8h3sjqkf8k3s - - &server_cypherpunk age1k9297jq43kjmqcau62rt7pz0fc8uqkyshpm6kvw2tky4997r6flqmx8cce -creation_rules: - - path_regex: secrets/[^/]+\.(yaml|json|env)$ - key_groups: - - age: - - *admin_cypherpunk - - *server_cypherpunk diff --git a/README.md b/README.md new file mode 100644 index 0000000..70ee0a0 --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# my nix homelab config!! + +Hosted on a Proxmox VM. This config includes : + +## Installation + +You will need to do a basic install diff --git a/configuration.nix b/configuration.nix index 46292c0..2b6260f 100644 --- a/configuration.nix +++ b/configuration.nix @@ -13,70 +13,88 @@ imports = [ # Include the results of the hardware scan. ./hardware-configuration.nix - "${(import ./nix/sources.nix).sops-nix}/modules/sops" ./server-configuration.nix + "${(import ./nix/sources.nix).sops-nix}/modules/sops" ]; # Use the GRUB 2 boot loader. - boot = { - loader.grub = { - enable = true; - device = "/dev/sda"; - }; - kernelParams = [ "console=ttyS0" ]; - }; + boot.loader.grub.enable = true; + boot.loader.grub.device = "/dev/sda"; # or "nodev" for efi only + boot.kernelParams = [ "console=ttyS0" ]; - networking.hostName = "hypervirtualworld"; # Define your hostname. + services.qemuGuest.enable = true; + networking.hostName = "sisyphe"; # Define your hostname. + # Pick only one of the below networking options. + # networking.wireless.enable = true; # Enables wireless support via wpa_supplicant. + # networking.networkmanager.enable = true; # Easiest to use and most distros use this by default. # Set your time zone. time.timeZone = lib.mkDefault "Europe/Paris"; - # Select internationalisation properties. i18n.defaultLocale = "fr_FR.UTF-8"; console = { font = "Lat2-Terminus16"; keyMap = "fr"; + # useXkbConfig = true; # use xkb.options in tty. }; - services.qemuGuest.enable = true; - services.cloud-init.network.enable = true; - - # Define a user account. Don't forget to set a password with ‘passwd’. - users.users.cypherpunk = { + users.users.homelab = { isNormalUser = true; extraGroups = [ "wheel" - "docker" "dialout" ]; # Enable ‘sudo’ for the user. - packages = with pkgs; [ btop ]; + + packages = with pkgs; [ + neovim + btop + tree + git + ]; openssh.authorizedKeys.keys = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA8sdToNavEQv7PTMJ97HIGM6UlChwGS3x9O8hFilzui harryh@ik.me" - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII/pj2uTGRHkYwP/EqIfgHP+MQavBuDMnWMXtOedkwIQ harryh@ik.me" ]; + + initialHashedPassword = "$y$j9T$H0D6NpMw1EU.oDhbMWrwL.$wDGGBKKGQdzeDRTzq0gWhoLdyUpQ2w6PMmGl.nuQ11/"; }; + users.users.root.initialHashedPassword = "$y$j9T$99/NEnBGoewbrl5eHvTw7/$87rjPrvqs0Ys72338SxZJDibi8p7Fe8Can37rJyhcQ."; + # List packages installed in system profile. To search, run: + # $ nix search wget environment.systemPackages = with pkgs; [ - neovim + vim # Do not forget to add an editor to edit configuration.nix! The Nano editor is also installed by default. curl - git + niv ]; - # enable docker - virtualisation.docker = { - enable = true; - }; + # Some programs need SUID wrappers, can be configured further or are + # started in user sessions. + # programs.mtr.enable = true; + # programs.gnupg.agent = { + # enable = true; + # enableSSHSupport = true; + # }; + + # List services that you want to enable: - # configure openssh services.openssh = { enable = true; - # require public key authentication for better security - settings.PasswordAuthentication = false; - settings.KbdInteractiveAuthentication = false; - settings.PermitRootLogin = "no"; + settings = { + PasswordAuthentication = false; + KbdInteractiveAuthentication = false; + PermitRootLogin = "no"; + }; }; + # Open ports in the firewall. + networking.firewall.allowedTCPPorts = [ + 22 + 80 + 443 + 8080 + ]; + # Copy the NixOS configuration file and link it from the resulting system # (/run/current-system/configuration.nix). This is useful in case you # accidentally delete configuration.nix. diff --git a/features/arr-suite.nix b/features/arr-suite.nix new file mode 100644 index 0000000..ceccf0e --- /dev/null +++ b/features/arr-suite.nix @@ -0,0 +1,36 @@ +{ pkgs }: +{ + services.sonarr = { + enable = true; + openFirewall = true; + }; + + services.radarr = { + enable = true; + group = "multimedia"; + openFirewall = true; + }; + + services.readarr = { + enable = true; + openFirewall = true; + }; + + services.prowlarr = { + enable = true; + openFirewall = true; + }; + + services.jellyseerr = { + openFirewall = true; + enable = true; + }; + + systemd.services.sonarrAnime = { + enable = true; + path = [ pkgs.sonarr ]; + serviceConfig = { + ExecStart = "Sonarr -nobrowser -data=/var/lib/sonarrAnime"; + }; + }; +} diff --git a/features/authentik.nix b/features/authentik.nix new file mode 100644 index 0000000..087e09c --- /dev/null +++ b/features/authentik.nix @@ -0,0 +1,32 @@ +{ config, ... }: +let + authentik-version = "2024.6.1"; + authentik-nix-src = builtins.fetchTarball { + url = "https://github.com/nix-community/authentik-nix/archive/version/${authentik-version}.tar.gz"; + sha256 = "15b9a2csd2m3vwhj3xc24nrqnj1hal60jrd69splln0ynbnd9ki4"; + }; + authentik-nix = import authentik-nix-src; +in +{ + + imports = [ authentik-nix.nixosModules.default ]; + + sops.secrets."authentik" = { + sopsFile = ./secrets/authentik.env; + format = "dotenv"; + }; + + services.authentik = { + enable = true; + environmentFile = config.sops.secrets."authentik".path; + settings = { + email = { + + }; + + disable_startup_analytics = true; + + avatars = "initials"; + }; + }; +} diff --git a/features/containers.nix b/features/containers.nix new file mode 100644 index 0000000..d82782b --- /dev/null +++ b/features/containers.nix @@ -0,0 +1,36 @@ +{ ... }: + +{ + # docker containers, for apps that aren't avaiable on Nix. (yet) + virtualisation.oci-containers = { + backend = "docker"; + containers = { + flaresolverr = { + ports = [ "8191:8191" ]; + image = "ghcr.io/flaresolverr/flaresolverr:latest"; + environment = { + "LOG_LEVEL" = "info"; + }; + }; + crafty-controller = { + image = "registry.gitlab.com/crafty-controller/crafty-4:latest"; + ports = [ + "8443:8443" + "8123:8123" + "19132:19132/udp" + "25500-25600:25500-25600" + ]; + volumes = [ + "./docker/backups:/crafty/backups" + "./docker/logs:/crafty/logs" + "./docker/servers:/crafty/servers" + "./docker/config:/crafty/app/config" + "./docker/import:/crafty/import" + ]; + environment = { + "TZ" = "Europe/Paris"; + }; + }; + }; + }; +} diff --git a/features/homelab-dashboard.nix b/features/homelab-dashboard.nix new file mode 100644 index 0000000..24c1681 --- /dev/null +++ b/features/homelab-dashboard.nix @@ -0,0 +1,121 @@ +{config, lib, pkgs, ...}: + +{ + services.homepage-dashboard = { + enable = true; + settings = { + "headerStyle" = "boxed"; + "language" = "fr"; + }; + services = [ + { + "Divertissement" = [ + { + "Jellyfin" = { + icon = "jellyfin"; + description = "Permet de regarder ou écouter du contenu."; + href = "http://${ip}:8096/"; + }; + } + { + "Calibre-web" = { + icon = "calibre"; + description = "Serveur de livres"; + href = "http://${ip}:8083"; + }; + } + ]; + } + { + "Téléchargement" = [ + { + "Jellyseerr" = { + icon = "jellyseerr"; + description = "Moteur de recherche de films/séries"; + href = "http://${ip}:5055"; + }; + } + { + "slskd" = { + icon = "slskd"; + description = "Pour télécharger/partager de la musique"; + href = "http://${ip}:5030"; + }; + } + { + "Readarr" = { + icon = "readarr"; + description = "Moteur de recherche de livres"; + href = "http://${ip}:8787/"; + }; + } + { + "Prowlarr" = { + icon = "prowlarr"; + description = "Indexe les différents sites de téléchargement"; + href = "http://${ip}:9696/"; + }; + } + { + + "Sonarr" = { + icon = "sonarr"; + description = "Moteur de recherche pour les séries"; + href = "http://${ip}:8989"; + }; + } + { + "Radarr" = { + icon = "radarr"; + description = "Moteur de recherche pour les films"; + href = "http://${ip}:7878"; + }; + } + { + + "Transmission" = { + icon = "transmission"; + description = "s'occupe du téléchargement des fichiers"; + href = "http://${ip}:9091"; + }; + } + ]; + } + { + "Utilitaires" = [ + { + "Photoprism" = { + icon = "photoprism"; + description = "Sauvegarde de photos"; + href = "http://${ip}:2342"; + }; + + } + { + "Searx" = { + icon = "searx"; + description = "Moteur de recherche privé pour remplacer Google."; + href = "http://${ip}:8080"; + }; + } + ]; + } + { + "Administration" = [ + { + "Proxmox Backup Server" = { + description = "Permet de sauvegarder le serveur." + }; + + } + { + + "Proxmox VE" = {}; + } + ]; + } + ]; + + }; + +} diff --git a/features/samba-shares.nix b/features/samba-shares.nix new file mode 100644 index 0000000..bfbb388 --- /dev/null +++ b/features/samba-shares.nix @@ -0,0 +1,35 @@ +{ username, driveMountPoint }: + +{ + # enable samba + services.samba = { + enable = true; + securityType = "user"; + openFirewall = true; + extraConfig = '' + workgroup = WORKGROUP + server string = hyperserver + netbios name = hyperserver + security = user + ''; + shares = { + music = { + path = "${driveMountPoint}/Music"; + browseable = "yes"; + "read only" = "no"; + "create mask" = "0644"; + "directory mask" = "0755"; + "force user" = username; + }; + ebooks = { + path = "${driveMountPoint}/Ebooks"; + browseable = "yes"; + "read only" = "no"; + "create mask" = "0644"; + "directory mask" = "0755"; + "force user" = username; + }; + }; + }; + +} diff --git a/features/slskd.nix b/features/slskd.nix new file mode 100644 index 0000000..1d299a9 --- /dev/null +++ b/features/slskd.nix @@ -0,0 +1,30 @@ +{ config, lib }: +with lib; + +let + cfg = config.slskd; +in +{ + options = { + slskd.directory = mkOption { type = types.str; }; + }; + config = { + + sops.secrets."slskd" = { + sopsFile = ./secrets/slskd.env; + format = "dotenv"; + }; + services.slskd = { + enable = true; + openFirewall = true; + environmentFile = config.sops.secrets."slskd".path; + domain = null; + settings = { + shares.directories = [ "${cfg.slskd.directory}/Music" ]; + soulseek.description = "i luv katz n mewsik"; + directories.files.downloads = "${cfg.slskd.directory}/Music/clean"; + directories.files.incomplete = "${cfg.slskd.directory}/Music/incomplete"; + }; + }; + }; +} diff --git a/features/transmission.nix b/features/transmission.nix new file mode 100644 index 0000000..1df72a9 --- /dev/null +++ b/features/transmission.nix @@ -0,0 +1,33 @@ +{ config, lib, ... }: +with lib; + +let + cfg = config.transmission; +in +{ + options.transmission = { + directory = mkOption { type = lib.types.str; }; + }; + + config = { + sops.secrets."transmission" = { + sopsFile = ./secrets/transmission.json; + path = "/var/lib/secrets/transmission/settings.json"; + }; + + # torrenting apps + services.transmission = { + enable = true; + openFirewall = true; + openRPCPort = true; + credentialsFile = config.sops.secrets."transmission".path; + settings = { + rpc-bind-address = "0.0.0.0"; + rpc-whitelist-enabled = false; + rpc-authentication-required = true; + download-dir = "${cfg.directory}/Torrents"; + ratio-limit-enabled = true; + }; + }; + }; +} diff --git a/hardware-configuration.nix b/hardware-configuration.nix new file mode 100644 index 0000000..8d351fc --- /dev/null +++ b/hardware-configuration.nix @@ -0,0 +1,31 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ config, lib, pkgs, modulesPath, ... }: + +{ + imports = + [ (modulesPath + "/profiles/qemu-guest.nix") + ]; + + boot.initrd.availableKernelModules = [ "ata_piix" "uhci_hcd" "virtio_pci" "virtio_scsi" "sd_mod" "sr_mod" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = + { device = "/dev/disk/by-uuid/1095480f-fcbc-4b0f-be6d-61380032cfed"; + fsType = "ext4"; + }; + + swapDevices = [ ]; + + # Enables DHCP on each ethernet and wireless interface. In case of scripted networking + # (the default) this is the recommended approach. When using systemd-networkd it's + # still possible to use this option, but it's recommended to use it in conjunction + # with explicit per-interface declarations with `networking.interfaces..useDHCP`. + networking.useDHCP = lib.mkDefault true; + # networking.interfaces.ens18.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; +} diff --git a/nix b/nix deleted file mode 120000 index a2f715e..0000000 --- a/nix +++ /dev/null @@ -1 +0,0 @@ -/home/cypherpunk/nix/ \ No newline at end of file diff --git a/nix/sources.json b/nix/sources.json new file mode 100644 index 0000000..f7db996 --- /dev/null +++ b/nix/sources.json @@ -0,0 +1,26 @@ +{ + "nixpkgs": { + "branch": "nixos-unstable", + "description": "Nix Packages collection", + "homepage": null, + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "6c43a3495a11e261e5f41e5d7eda2d71dae1b2fe", + "sha256": "16f329z831bq7l3wn1dfvbkh95l2gcggdwn6rk3cisdmv2aa3189", + "type": "tarball", + "url": "https://github.com/NixOS/nixpkgs/archive/6c43a3495a11e261e5f41e5d7eda2d71dae1b2fe.tar.gz", + "url_template": "https://github.com///archive/.tar.gz" + }, + "sops-nix": { + "branch": "master", + "description": "Atomic secret provisioning for NixOS based on sops", + "homepage": "", + "owner": "Mic92", + "repo": "sops-nix", + "rev": "67035a355b1d52d2d238501f8cc1a18706979760", + "sha256": "1pihm7c30q38k7xzqbfvd5g9ffbim59qhvynmg3v8k7k6lnf3awf", + "type": "tarball", + "url": "https://github.com/Mic92/sops-nix/archive/67035a355b1d52d2d238501f8cc1a18706979760.tar.gz", + "url_template": "https://github.com///archive/.tar.gz" + } +} diff --git a/nix/sources.nix b/nix/sources.nix new file mode 100644 index 0000000..fe3dadf --- /dev/null +++ b/nix/sources.nix @@ -0,0 +1,198 @@ +# This file has been generated by Niv. + +let + + # + # The fetchers. fetch_ fetches specs of type . + # + + fetch_file = pkgs: name: spec: + let + name' = sanitizeName name + "-src"; + in + if spec.builtin or true then + builtins_fetchurl { inherit (spec) url sha256; name = name'; } + else + pkgs.fetchurl { inherit (spec) url sha256; name = name'; }; + + fetch_tarball = pkgs: name: spec: + let + name' = sanitizeName name + "-src"; + in + if spec.builtin or true then + builtins_fetchTarball { name = name'; inherit (spec) url sha256; } + else + pkgs.fetchzip { name = name'; inherit (spec) url sha256; }; + + fetch_git = name: spec: + let + ref = + spec.ref or ( + if spec ? branch then "refs/heads/${spec.branch}" else + if spec ? tag then "refs/tags/${spec.tag}" else + abort "In git source '${name}': Please specify `ref`, `tag` or `branch`!" + ); + submodules = spec.submodules or false; + submoduleArg = + let + nixSupportsSubmodules = builtins.compareVersions builtins.nixVersion "2.4" >= 0; + emptyArgWithWarning = + if submodules + then + builtins.trace + ( + "The niv input \"${name}\" uses submodules " + + "but your nix's (${builtins.nixVersion}) builtins.fetchGit " + + "does not support them" + ) + { } + else { }; + in + if nixSupportsSubmodules + then { inherit submodules; } + else emptyArgWithWarning; + in + builtins.fetchGit + ({ url = spec.repo; inherit (spec) rev; inherit ref; } // submoduleArg); + + fetch_local = spec: spec.path; + + fetch_builtin-tarball = name: throw + ''[${name}] The niv type "builtin-tarball" is deprecated. You should instead use `builtin = true`. + $ niv modify ${name} -a type=tarball -a builtin=true''; + + fetch_builtin-url = name: throw + ''[${name}] The niv type "builtin-url" will soon be deprecated. You should instead use `builtin = true`. + $ niv modify ${name} -a type=file -a builtin=true''; + + # + # Various helpers + # + + # https://github.com/NixOS/nixpkgs/pull/83241/files#diff-c6f540a4f3bfa4b0e8b6bafd4cd54e8bR695 + sanitizeName = name: + ( + concatMapStrings (s: if builtins.isList s then "-" else s) + ( + builtins.split "[^[:alnum:]+._?=-]+" + ((x: builtins.elemAt (builtins.match "\\.*(.*)" x) 0) name) + ) + ); + + # The set of packages used when specs are fetched using non-builtins. + mkPkgs = sources: system: + let + sourcesNixpkgs = + import (builtins_fetchTarball { inherit (sources.nixpkgs) url sha256; }) { inherit system; }; + hasNixpkgsPath = builtins.any (x: x.prefix == "nixpkgs") builtins.nixPath; + hasThisAsNixpkgsPath = == ./.; + in + if builtins.hasAttr "nixpkgs" sources + then sourcesNixpkgs + else if hasNixpkgsPath && ! hasThisAsNixpkgsPath then + import { } + else + abort + '' + Please specify either (through -I or NIX_PATH=nixpkgs=...) or + add a package called "nixpkgs" to your sources.json. + ''; + + # The actual fetching function. + fetch = pkgs: name: spec: + + if ! builtins.hasAttr "type" spec then + abort "ERROR: niv spec ${name} does not have a 'type' attribute" + else if spec.type == "file" then fetch_file pkgs name spec + else if spec.type == "tarball" then fetch_tarball pkgs name spec + else if spec.type == "git" then fetch_git name spec + else if spec.type == "local" then fetch_local spec + else if spec.type == "builtin-tarball" then fetch_builtin-tarball name + else if spec.type == "builtin-url" then fetch_builtin-url name + else + abort "ERROR: niv spec ${name} has unknown type ${builtins.toJSON spec.type}"; + + # If the environment variable NIV_OVERRIDE_${name} is set, then use + # the path directly as opposed to the fetched source. + replace = name: drv: + let + saneName = stringAsChars (c: if (builtins.match "[a-zA-Z0-9]" c) == null then "_" else c) name; + ersatz = builtins.getEnv "NIV_OVERRIDE_${saneName}"; + in + if ersatz == "" then drv else + # this turns the string into an actual Nix path (for both absolute and + # relative paths) + if builtins.substring 0 1 ersatz == "/" then /. + ersatz else /. + builtins.getEnv "PWD" + "/${ersatz}"; + + # Ports of functions for older nix versions + + # a Nix version of mapAttrs if the built-in doesn't exist + mapAttrs = builtins.mapAttrs or ( + f: set: with builtins; + listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set)) + ); + + # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/lists.nix#L295 + range = first: last: if first > last then [ ] else builtins.genList (n: first + n) (last - first + 1); + + # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L257 + stringToCharacters = s: map (p: builtins.substring p 1 s) (range 0 (builtins.stringLength s - 1)); + + # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269 + stringAsChars = f: s: concatStrings (map f (stringToCharacters s)); + concatMapStrings = f: list: concatStrings (map f list); + concatStrings = builtins.concatStringsSep ""; + + # https://github.com/NixOS/nixpkgs/blob/8a9f58a375c401b96da862d969f66429def1d118/lib/attrsets.nix#L331 + optionalAttrs = cond: as: if cond then as else { }; + + # fetchTarball version that is compatible between all the versions of Nix + builtins_fetchTarball = { url, name ? null, sha256 }@attrs: + let + inherit (builtins) lessThan nixVersion fetchTarball; + in + if lessThan nixVersion "1.12" then + fetchTarball ({ inherit url; } // (optionalAttrs (name != null) { inherit name; })) + else + fetchTarball attrs; + + # fetchurl version that is compatible between all the versions of Nix + builtins_fetchurl = { url, name ? null, sha256 }@attrs: + let + inherit (builtins) lessThan nixVersion fetchurl; + in + if lessThan nixVersion "1.12" then + fetchurl ({ inherit url; } // (optionalAttrs (name != null) { inherit name; })) + else + fetchurl attrs; + + # Create the final "sources" from the config + mkSources = config: + mapAttrs + ( + name: spec: + if builtins.hasAttr "outPath" spec + then + abort + "The values in sources.json should not have an 'outPath' attribute" + else + spec // { outPath = replace name (fetch config.pkgs name spec); } + ) + config.sources; + + # The "config" used by the fetchers + mkConfig = + { sourcesFile ? if builtins.pathExists ./sources.json then ./sources.json else null + , sources ? if sourcesFile == null then { } else builtins.fromJSON (builtins.readFile sourcesFile) + , system ? builtins.currentSystem + , pkgs ? mkPkgs sources system + }: rec { + # The sources, i.e. the attribute set of spec name to spec + inherit sources; + + # The "pkgs" (evaluated nixpkgs) to use for e.g. non-builtin fetchers + inherit pkgs; + }; + +in +mkSources (mkConfig { }) // { __functor = _: settings: mkSources (mkConfig settings); } diff --git a/secrets/arrsuite.json b/secrets/arrsuite.json new file mode 100644 index 0000000..96fc7d8 --- /dev/null +++ b/secrets/arrsuite.json @@ -0,0 +1,26 @@ +{ + "radarr_key": "", + "sonarr_key": "ENC[AES256_GCM,data:DF7j2/br+TVLfbfyhG/B64ks5sLPWtQ+aRWCEV26RMI=,iv:cfmYc/4vnZCifYxCATIEiVUIrw/qfdYErjtJZXIm8Nw=,tag:2mhZAm/gT3rm4yNivZ/O5g==,type:str]", + "jellyfin_key": "", + "sops": { + "kms": null, + "gcp_kms": null, + "azure_kv": null, + "hc_vault": null, + "age": [ + { + "recipient": "age1c8kr95dc7cqq34qyjgpnsgfgyntqnt5rlrq2c025ehp32f8h3sjqkf8k3s", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBoa0Q4NGtpeWI2OFRIZXFZ\nd2hsTVdYWm1vMDVkeUFHR1NVcGlwSXNEWkY0Cm1Vb3pONXU5QzVuNXQ1dkNxMkVh\nR21pNGxZUGdmK21LMmR4dXJVNDJveEkKLS0tIDlkb0RXMFZLK2Y5VE1qdXg2THlD\nY2FDS2J6RE1vOUdHMjY1ZGxyMXZyckUK1P+EtjvmmPx0QHUywuznY73tJFO2+LT5\n1JUZaQr+3V2bbJyeU2ZX5NTet1uemxFJTTMMfs4MD4t2xjXPM1AW6A==\n-----END AGE ENCRYPTED FILE-----\n" + }, + { + "recipient": "age17pq9xyrcv6tlms9sznnhql6pejue33r0aukn72hzpcn4jykrg33q4u0a3m", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBiRzF2VHkwUmhUWDBoTHlp\nZXVQendPL0VqeENiYVhjai9UVEZHSWdtQkQ0CjVuUzFaNlJjTHVlLzlESXdRWk1M\ncG8rcVVzZndSL0xZWmZPQ3hDNjlNVWcKLS0tIFBGcmlGbjVrQzNWOU9qOXRMaTNj\nVHBndVMzY3RXdGZ1K0NxSHNxSytRV28K3bOiWVmMpRdYk2CbAntlGRwOFIxptcBE\n8ehUmdfw3v7zC0776RPHjavbpUZ3u2Yhg5Y1NFaUrvuSkM31ULwKsQ==\n-----END AGE ENCRYPTED FILE-----\n" + } + ], + "lastmodified": "2024-07-14T13:43:51Z", + "mac": "ENC[AES256_GCM,data:/pX6z+9XMdSo5d9a0FkmHv2KJXoMXYDIv7fHWbz2Jh7ukckfQ+qxQ2kjUjEc5bAFknolSpc+ggbhIPUNwSVcQgtUegwegEQPwyq6+8u90/AGPDTscKj1NHQPMNYI4PpuWyAbPtCnd9JCIpjDc8d5q4BfsMhD+ioV/UIodbpWVRU=,iv:XhbmgYk3tr2h9vsKpCbPDv2n/SfnOyNUOSAB45uQbw8=,tag:bggLlobJLFT4+ApQ+8Q2fg==,type:str]", + "pgp": null, + "unencrypted_suffix": "_unencrypted", + "version": "3.9.0" + } +} \ No newline at end of file diff --git a/secrets/authentik.env b/secrets/authentik.env new file mode 100644 index 0000000..eb31dfb --- /dev/null +++ b/secrets/authentik.env @@ -0,0 +1,9 @@ +AUTHENTIK_SECRET_KEY=ENC[AES256_GCM,data:CK+gqP7F87R9vvwLAoIXSlt1LolqjEXS/mjtPBZkPNR4stBuA61LL6wbg4I=,iv:dw19pO31vg/U2GbGBdMmNyVeJ4an2QWJ++CR+13vAxg=,tag:omxplYgc0J8U6udIudXV9Q==,type:str] +sops_age__list_0__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBFQ2tJZ3ViazJncS8waW9T\nZmxwcUJJY2s0Q25iZzBzNjRyYnBuMDVyRGprCkt2a2xXUEwvQU1zb0o2UDhFTkhl\nMFAvbmpEQnp6b2gvT1BaeTdIeTlGSGsKLS0tIEFtTjFVZ24vZ3RkZ1FETWttdGJY\ncmRRSkJpOWs0aHNYVVFvSzFZR2hGWDQKcY8ekizqL6C8dVxiNgFGe+iy1iqRfSpF\nOKOe70g87CBfbAcjQlXgY1KLC32Lv+IQMqcAfK/mDhLXpDviUPipgg==\n-----END AGE ENCRYPTED FILE-----\n +sops_age__list_0__map_recipient=age1c8kr95dc7cqq34qyjgpnsgfgyntqnt5rlrq2c025ehp32f8h3sjqkf8k3s +sops_age__list_1__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA1TWtxcDgvcWVFNzNOaTRW\nQ2U2OWl0MG1Zbng2WXlWQmQzczJveTlTV1FRCjBPek1KZFN0NGp6NWJiVTFKaEZU\nSkQ0dHpUek13VGdtQjNLeU9UdzNEbGcKLS0tIHo5NFBHVXBVY2N2ZE8yOFhrVjd5\nV3k0M1JNaEVQSXJEMHIvbVEvbFRPMzgKM8iHBgXyezCFCUbj/eLDMRkahX5NCb+0\naKGc4bFSF0WxMEJub0lBn7f/yl+qmQaNokDYDfz3EeaD9OAsLeJc9Q==\n-----END AGE ENCRYPTED FILE-----\n +sops_age__list_1__map_recipient=age17pq9xyrcv6tlms9sznnhql6pejue33r0aukn72hzpcn4jykrg33q4u0a3m +sops_lastmodified=2024-07-12T21:37:51Z +sops_mac=ENC[AES256_GCM,data:HdM8iarjUPja04QJtP8BTcmWTDj3PLjp6+eG1u8KozBiGjLMwn42FBwn6wLxO0hofboRwGAFD+qN6cHlbBR8UNbIK/2oRTomzr8IILjowRif9WHTrbkYJBQa4YoNKIHSGNKOQ8byITWa0dnT7+cXEU5QXdzqDT5AABNROwBI1J4=,iv:cbkJFHx4JVOZ6jPA6ebH6QcdKGrLipkrdlVilwXlCXE=,tag:DwE0P853iUfXN7JhKVAIDA==,type:str] +sops_unencrypted_suffix=_unencrypted +sops_version=3.8.1 diff --git a/secrets/searx.env b/secrets/searx.env new file mode 100644 index 0000000..57bd5cd --- /dev/null +++ b/secrets/searx.env @@ -0,0 +1,9 @@ +secret_key=ENC[AES256_GCM,data:lRAnDFXN7nBf5gKcG+ih4Yo/SCD1h3hPwUU=,iv:0L+zupkyXNFWSeXePNHz270bHtlDB7l+BvavOuV4SDQ=,tag:pjjaS/uGHgd0AsovGppUqw==,type:str] +sops_age__list_0__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBsd3FRcWV6VXdKdEtEMHhq\nOUxrRHc0OGx4RFYrWXFPMDl0RmpvdGpJYkdNCkFodDE2NFhpYWhPOXpneGY3dGti\nL0ttejdnMWkrK1BqR0xLRHpNQ1Z0dFUKLS0tIDhRQzYzN1R5cXVzQ1dBdXVTOEN2\ndGgrWkFDWW5UTEZwTGh0U1Y5dEp5WTAKupifD9Z5QPY7HRk/z8zHMwdMnBgO7cVc\nqKLSx3aFVaAVJtBIgymit1PIyLnW6oTRKEUuD5dsYo4V197itZdGgQ==\n-----END AGE ENCRYPTED FILE-----\n +sops_age__list_0__map_recipient=age1c8kr95dc7cqq34qyjgpnsgfgyntqnt5rlrq2c025ehp32f8h3sjqkf8k3s +sops_age__list_1__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBNYW9HN0tERVdtVnhCTHd6\ncmhOM3JFKzl0bU11Wk1xZktNTFYvRVM2bVdJCnJtQkNyb1FyU2c4NzJvY1JQVkZ4\neVMvV2dnaC9MRHVMVUNsS2VEcXp0S28KLS0tIGs4Z2hzWE1rN3dDeW50RFNtQjVy\nc0ZXam1xZll2eC8rTm9ySG55RG5Kc1EKVq4tLmRjdZ65WO6yY97q5w5C0R5HFoyk\nc6FX7NhP7ab0x9JUEuBtEgzwEeohMCyxY5HmNufQN+KXVG2CH4lzRg==\n-----END AGE ENCRYPTED FILE-----\n +sops_age__list_1__map_recipient=age17pq9xyrcv6tlms9sznnhql6pejue33r0aukn72hzpcn4jykrg33q4u0a3m +sops_lastmodified=2024-07-12T19:11:00Z +sops_mac=ENC[AES256_GCM,data:N2lKNF/oJ4YcEIf22E+39LCSGelhsBh3j9PGnHHQ/xXqia3DfmlEeVo/l6Jt2RvLQ9VmJ2786FvjvZ1QGIR1uDsTXr5BLLPmIVpYTID5loP80sJP8gDddT1wN2CGZwGZES6pMlkyDKHcCWyKR84Rt2c2aas8mevk6Ple/GJj+Uk=,iv:H8RWALfvNgex7wz6E9/fvtJAA5+FcFBKfuaEgJixdQA=,tag:+CaH8DxKVSajLy8Hm9aisg==,type:str] +sops_unencrypted_suffix=_unencrypted +sops_version=3.8.1 diff --git a/secrets/slskd.env b/secrets/slskd.env new file mode 100644 index 0000000..f23f450 --- /dev/null +++ b/secrets/slskd.env @@ -0,0 +1,10 @@ +SLSKD_SLSK_USERNAME=ENC[AES256_GCM,data:D07PEfL688Y=,iv:F3XnF3NLQG8XhcD0A+/2n4BFGv+9iFv71+CctCLVI+c=,tag:LaC9Pvi5EAoFRdRtrOcfBw==,type:str] +SLSKD_SLSK_PASSWORD=ENC[AES256_GCM,data:XGPVBqfArUHU0inJ,iv:nlIBoh6hJG5mU6MJIULtNAQnPujQnuKZaHT3o8ArHks=,tag:V3pjLxRcyW8LWq/GfShPcQ==,type:str] +sops_age__list_0__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBtYnFtZytxVmtmVWNsYUJz\nU2NURnNQMWFqd08zUHRibklhYlQvNWVLQ2lnClFZbGhJeXMrSGkzNzdPVzJTR3NE\nSG9DOGpVOVovNXI0dSt1dW1SeWlCWmsKLS0tIFpCNjZJeUtBWmJTdVpQZWhyZmhF\nbUdlSi8xN0RjcCt4UEMrUTNKTTdBUm8Kdkky7wDAYbVtgyVygXPdU70QvGqLLYT2\nIT5Vapt3g0znZb/pUg1ThdRUxWvqoR26d8T/qvNbBk4XQv9myT2K5g==\n-----END AGE ENCRYPTED FILE-----\n +sops_age__list_0__map_recipient=age1c8kr95dc7cqq34qyjgpnsgfgyntqnt5rlrq2c025ehp32f8h3sjqkf8k3s +sops_age__list_1__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBPS1dhNWZIVFA5Vlg0STZT\ncXRqbU5kUGpwSlo4b1JYdlZPbEQ1K0IyaWc4CjJWcDZSQi90Ri9uVTY1aGhaZ3NZ\nYVZyZ3pEUXJXeWxMd1B3RUgxaFpoc1kKLS0tIGl6c0tYYzNUZ0ZNV3R2RmgySVJE\naUhTeCtzN0dQNlRaRStYT0dIR3hhTXMKPXJsauKG4PUzNT5j424DWvi4vit16Wi1\nUHIf/hPZLfKvnMa5X3QK3CxX956dOh/nRqfcFXbbhH+Y0TVUInZ9nQ==\n-----END AGE ENCRYPTED FILE-----\n +sops_age__list_1__map_recipient=age17pq9xyrcv6tlms9sznnhql6pejue33r0aukn72hzpcn4jykrg33q4u0a3m +sops_lastmodified=2024-07-12T19:10:06Z +sops_mac=ENC[AES256_GCM,data:u5V3WcgW+dWSeDFz4FcPRDDXkL6ZGuyVp5fX97dcyxd2Op7T4oVAsHhYYe6S5fIU16kqHQ4Gi3nSRLTbjz1vDg10Jq/GKeNQlyQzj2JG4DuLqNibZ1cfYGgyYA2gZS1uZuiWelclvJF4dh92djo4SA/CWlXdPTGUUfs3eIKRtBg=,iv:wiCdIzqwzNXDeWLiD8+ep7vbkqpeeoNuFT0YCc7rZdw=,tag:+sAgEDzvbiMAQV6ql/90GQ==,type:str] +sops_unencrypted_suffix=_unencrypted +sops_version=3.8.1 diff --git a/secrets/transmission.json b/secrets/transmission.json new file mode 100644 index 0000000..7142599 --- /dev/null +++ b/secrets/transmission.json @@ -0,0 +1,24 @@ +{ + "transmission": "ENC[AES256_GCM,data:cWaPMHrg2Ff6c5VdSrBbYw6xS7ZARg8Xpnos8QvR40YovNc7rOK3kR94C3thVOvFb7+md4vPxVoEwbAQ+Z+OWaRT63lzLl+grpClS7mv,iv:KgheQ5ippN+k4UrrvIb+8hMBv/qoPA638IdjRTJXsrQ=,tag:OhFFDWU7wXvsMmynPvwKHQ==,type:str]", + "sops": { + "kms": null, + "gcp_kms": null, + "azure_kv": null, + "hc_vault": null, + "age": [ + { + "recipient": "age1c8kr95dc7cqq34qyjgpnsgfgyntqnt5rlrq2c025ehp32f8h3sjqkf8k3s", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBPQ0tZTXBiU3l3WGNxQmgy\nUzBaUFNjNkZOcDRYREVFNkxhRUF3U3NSTFQwCnlNTHlhMUpHMUV2ZXhIV0x4aFl3\nQW5hdDhhYXY3cnBUakN0dGxENkZXQ00KLS0tIDN2V1pCUFZDZUovZ0ZJTG5EL3ZH\nL1hFVWsvS25rUnc1YnF4RVBtUHF1cUkKgU3HYnrdsz5GtsZh6fh86qPDAFxCQHg/\nhgF6kTcECLeZUzfwYA6YtVHoUUeGdOiFeXB84fQPA3ZKyds9dcVHoA==\n-----END AGE ENCRYPTED FILE-----\n" + }, + { + "recipient": "age17pq9xyrcv6tlms9sznnhql6pejue33r0aukn72hzpcn4jykrg33q4u0a3m", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAvL2N3cTNuYzQrajdzMGxG\neWRqc0dKOUVmaENibkhOVnJURHRFSGRRcUhjCngvM0hMOFpMdTVoMVFjZVYxeGZ2\ncmhwbFFXZ2xsZVJlYU5VOXQ2Q0QvMDAKLS0tIFZaajczNGMzUTh3V0xlSGZtdEQ0\nZjIvdjVTcjllV256ZGpISDBBRHZKZkUKiBs0TMo/p84gjclRovTfAVImnOviy3aG\nDt+mZKeKlnXYH5vfC/CguSQT5TbkoEVqZKJ2u0PDquHnKh/ycnIlvg==\n-----END AGE ENCRYPTED FILE-----\n" + } + ], + "lastmodified": "2024-07-12T21:23:20Z", + "mac": "ENC[AES256_GCM,data:6DbmAKn38r+gCxWHdgQrVbvvEOqimZYSU/G8slzIOz5ML6XLoEnj/4bwoKS5/PXTjUFo8Wyyx2pFqD0dxiyvrcFVROAzNqSpgAlpr3FrmBtrb+C6AX2mkt2YkC1UgbUG0wVs6cJw1SzzFzNW9jMNuxDuPW34MWxGAm8t74UjKBs=,iv:VLuRoOEaBOffl6IQITDljzs3vBA+tgDtVoAKOlF+p8g=,tag:Fn3kCssUa73Tc96GjC3a9w==,type:str]", + "pgp": null, + "unencrypted_suffix": "_unencrypted", + "version": "3.8.1" + } +} \ No newline at end of file diff --git a/server-configuration.nix b/server-configuration.nix index 3cf78fa..11c7597 100644 --- a/server-configuration.nix +++ b/server-configuration.nix @@ -5,17 +5,22 @@ ... }: let - ip = "192.168.1.207"; + ip = "192.168.1.177"; gateway = "192.168.1.1"; - driveMountPoint = "/mnt/hdd1"; - authentik-version = "2024.2.3"; - authentik-nix-src = builtins.fetchTarball { - url = "https://github.com/nix-community/authentik-nix/archive/version/${authentik-version}.tar.gz"; - sha256 = "15b9a2csd2m3vwhj3xc24nrqnj1hal60jrd69splln0ynbnd9ki4"; - }; - authentik-nix = import authentik-nix-src; + driveMountPoint = "/srv/Multimedia"; + username = "homelab"; in { + imports = [ + ./features/authentik.nix + ./features/slskd.nix + ./features/arr-suite.nix + ./features/samba-shares.nix + ./features/containers.nix + ./features/homelab-dashboard.nix + ./features/transmission.nix + ]; + # setting up networking!! networking = { interfaces = { @@ -54,44 +59,11 @@ in "sonarr" "transmission" "jellyfin" - "cypherpunk" + username ]; }; - # enable samba - services.samba = { - enable = true; - securityType = "user"; - openFirewall = true; - extraConfig = '' - workgroup = WORKGROUP - server string = hyperserver - netbios name = hyperserver - security = user - ''; - shares = { - music = { - path = "${driveMountPoint}/Musique"; - browseable = "yes"; - "read only" = "no"; - "create mask" = "0644"; - "directory mask" = "0755"; - "force user" = "cypherpunk"; - }; - ebooks = { - path = "${driveMountPoint}/Ebooks"; - browseable = "yes"; - "read only" = "no"; - "create mask" = "0644"; - "directory mask" = "0755"; - "force user" = "cypherpunk"; - }; - }; - }; - - imports = [ authentik-nix.nixosModules.default ]; - - sops.age.sshKeyPaths = [ "/home/cypherpunk/.ssh/id_ed25519" ]; + sops.age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ]; sops.age.keyFile = "/var/lib/sops-nix/key.txt"; sops.age.generateKey = true; @@ -103,17 +75,6 @@ in format = "dotenv"; }; - sops.secrets."slskd" = { - sopsFile = ./secrets/slskd.env; - format = "dotenv"; - }; - - sops.secrets."authentik" = { - sopsFile = ./secrets/authentik.env; - format = "dotenv"; - disable_startup_analytics = true; - }; - environment.systemPackages = with pkgs; [ jellyfin jellyfin-web @@ -126,68 +87,14 @@ in jellyseerr homepage-dashboard slskd - niv # for using sops-nix ]; services.jellyfin = { enable = true; openFirewall = true; - user = "cypherpunk"; }; # -arr suite - services.sonarr = { - enable = true; - openFirewall = true; - }; - - services.radarr = { - enable = true; - openFirewall = true; - }; - - services.readarr = { - enable = true; - openFirewall = true; - }; - - services.prowlarr = { - enable = true; - openFirewall = true; - }; - - services.jellyseerr = { - openFirewall = true; - enable = true; - }; - - # torrenting apps - services.transmission = { - enable = true; - openFirewall = true; - openRPCPort = true; - credentialsFile = ""; - settings = { - rpc-bind-address = "0.0.0.0"; - rpc-whitelist-enabled = false; - rpc-authentication-required = true; - download-dir = "${driveMountPoint}/Torrents"; - ratio-limit-enabled = true; - }; - }; - - services.slskd = { - enable = true; - openFirewall = true; - environmentFile = config.sops.secrets."slskd".path; - domain = null; - settings = { - shares.directories = [ "${driveMountPoint}/Music" ]; - soulseek.description = "i luv katz n mewsik"; - directories.files.downloads = "${driveMountPoint}/Music/clean"; - directories.files.incomplete = "${driveMountPoint}/Music/incomplete"; - }; - }; services.searx = { enable = true; @@ -206,140 +113,19 @@ in services.caddy = { enable = true; - virtualHosts."localhost".extraConfig = '' + virtualHosts.":80".extraConfig = '' reverse_proxy :8082 ''; + }; /* - services.authentik = { - enable = true; - environmentFile = config.sops.secrets."authentik".path; - }; - services.photoprism = { - enable = true; - settings = { - PHOTOPRISM_DEFAULT_LOCALE = "fr"; - }; + enable = true; + settings = { + PHOTOPRISM_DEFAULT_LOCALE = "fr"; }; + }; */ - # docker containers, for apps that aren't avaiable on Nix. (yet) - virtualisation.oci-containers = { - backend = "docker"; - containers = { - flaresolverr = { - ports = [ "8181:8181" ]; - image = "ghcr.io/flaresolverr/flaresolverr:latest"; - environment = { - "LOG_LEVEL" = "info"; - }; - }; - crafty-controller = { - image = "registry.gitlab.com/crafty-controller/crafty-4:latest"; - ports = [ - "8443:8443" - "8123:8123" - "19132:19132/udp" - "25500-25600:25500-25600" - ]; - volumes = [ ]; - environment = { - "TZ" = "Europe/Paris"; - }; - }; - }; - }; - - services.homepage-dashboard = { - enable = true; - services = [ - { - "Divertissement" = [ - { - "Jellyfin" = { - icon = "jellyfin"; - description = "Permet de regarder ou écouter du contenu."; - href = "http://${ip}:8096/"; - }; - } - { - "calibre-web" = { - icon = "Calibre"; - description = "Serveur de livres"; - href = "http://${ip}:8083"; - }; - } - ]; - } - { - "Téléchargement" = [ - { - "Jellyseerr" = { - icon = "Jellyseerr"; - description = "Moteur de recherche de films/séries"; - href = "http://${ip}:5055"; - }; - } - { - "slskd" = { - icon = "slskd"; - description = "Pour télécharger/partager de la musique"; - href = "http://${ip}:5030"; - }; - } - { - "Readarr" = { - icon = "readarr"; - description = "Moteur de recherche de livres"; - href = "http://${ip}:8787/"; - }; - } - { - "Prowlarr" = { - icon = "prowlarr"; - description = "Indexe les différents sites de téléchargement"; - href = "http://${ip}:9696/"; - }; - } - { - - "Sonarr" = { - icon = "sonarr"; - description = "Moteur de recherche pour les séries"; - href = "http://${ip}:8989"; - }; - } - { - "Radarr" = { - icon = "radarr"; - description = "Moteur de recherche pour les films"; - href = "http://${ip}:7878"; - }; - } - { - - "Transmission" = { - icon = "transmission"; - description = "s'occupe du téléchargement des fichiers"; - href = "http://${ip}:9091"; - }; - } - ]; - } - { - "Utilitaires" = [ - { - "Photoprism" = { - icon = "photoprism"; - description = "Sauvegarde de photos"; - href = "http://${ip}:2342"; - }; - } - ]; - } - ]; - - }; }