diff --git a/flake.lock b/flake.lock index 41c81de..6c1e3d5 100644 --- a/flake.lock +++ b/flake.lock @@ -17,6 +17,26 @@ "type": "github" } }, + "compose2nix": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1712629085, + "narHash": "sha256-rmGuDNiDyXFpahhXBvVociJXtWh8fr3eyu+LX1LULsc=", + "owner": "aksiksi", + "repo": "compose2nix", + "rev": "3a033a0bb0fd9fd44b6583ad435d359937073813", + "type": "github" + }, + "original": { + "owner": "aksiksi", + "repo": "compose2nix", + "type": "github" + } + }, "crane": { "inputs": { "nixpkgs": [ @@ -45,11 +65,11 @@ ] }, "locked": { - "lastModified": 1712612224, - "narHash": "sha256-Tv4C8OSPVmm4LbpJGLFSODyvJy6DqrisEGPCQdNVOeY=", + "lastModified": 1712798444, + "narHash": "sha256-aAksVB7zMfBQTz0q2Lw3o78HM3Bg2FRziX2D6qnh+sk=", "owner": "nix-community", "repo": "disko", - "rev": "79eab0e82cb126bf4ac170f44af82479f0895ab5", + "rev": "a297cb1cb0337ee10a7a0f9517954501d8f6f74d", "type": "github" }, "original": { @@ -120,11 +140,11 @@ "sqlite3pp": "sqlite3pp" }, "locked": { - "lastModified": 1712601482, - "narHash": "sha256-MpiJmDRewGJT/jUl3IRKiiSfFVtA+bAzMZAKXMqL+a8=", + "lastModified": 1712860128, + "narHash": "sha256-xqg2hbPv5WS+JnGv+9LVFLo5dRUyBt8BvmYEDuSTXr0=", "owner": "flox", "repo": "flox", - "rev": "7092e6d6108e1ed6e4989aa1ced779828ec79e37", + "rev": "c470fb87a0d9765603194259c227158a8957f95e", "type": "github" }, "original": { @@ -136,17 +156,17 @@ "flox-latest": { "flake": false, "locked": { - "lastModified": 1711561242, - "narHash": "sha256-oCnthe0/sSZi8lDA2kYliG/J++CBoEiEV8Go8TNwbOQ=", - "ref": "refs/tags/v1.0.2", - "rev": "947bd4c4a3b660d308a01a05d32ed62e495ef69f", - "revCount": 1150, + "lastModified": 1712673935, + "narHash": "sha256-PdGM5BOpebs6sdM3qCPh/W5R/0o6RSgSrAG5qEvL7ms=", + "ref": "refs/tags/v1.0.3", + "rev": "c50d78782713d19d6c790af271c8819b89b1a253", + "revCount": 1173, "type": "git", "url": "ssh://git@github.com/flox/flox" }, "original": { - "ref": "refs/tags/v1.0.2", - "rev": "947bd4c4a3b660d308a01a05d32ed62e495ef69f", + "ref": "refs/tags/v1.0.3", + "rev": "c50d78782713d19d6c790af271c8819b89b1a253", "type": "git", "url": "ssh://git@github.com/flox/flox" } @@ -350,11 +370,11 @@ }, "nixpkgs-unstable": { "locked": { - "lastModified": 1712634594, - "narHash": "sha256-fzBqUvcJjjyIapioiaW5b/mj7V/xxljDt864JrDC5qI=", + "lastModified": 1712849433, + "narHash": "sha256-flQtf/ZPJgkLY/So3Fd+dGilw2DKIsiwgMEn7BbBHL0=", "owner": "nixos", "repo": "nixpkgs", - "rev": "0dca19054c663a0cf3b471be3c3079acfd623924", + "rev": "f173d0881eff3b21ebb29a2ef8bedbc106c86ea5", "type": "github" }, "original": { @@ -395,11 +415,11 @@ }, "nixpkgs_4": { "locked": { - "lastModified": 1712639375, - "narHash": "sha256-V/7wFmh6O1OGOrlk//CTW9q4lYpb/RB3p2tRQNws95U=", + "lastModified": 1712867921, + "narHash": "sha256-edTFV4KldkCMdViC/rmpJa7oLIU8SE/S35lh/ukC7bg=", "owner": "nixos", "repo": "nixpkgs", - "rev": "73844014f48f8f968f98366b33bbdcf693d6d407", + "rev": "51651a540816273b67bc4dedea2d37d116c5f7fe", "type": "github" }, "original": { @@ -436,6 +456,7 @@ }, "root": { "inputs": { + "compose2nix": "compose2nix", "disko": "disko", "flox-flake": "flox-flake", "genebean-omp-themes": "genebean-omp-themes", diff --git a/flake.nix b/flake.nix index ac86e3e..e88f35d 100644 --- a/flake.nix +++ b/flake.nix @@ -42,6 +42,12 @@ # inputs.nixpkgs.follows ="nixpkgs"; }; + compose2nix = { + url = "github:aksiksi/compose2nix"; + inputs.nixpkgs.follows ="nixpkgs"; + }; + + # My oh-my-posh theme genebean-omp-themes = { url = "github:genebean/my-oh-my-posh-themes"; @@ -49,7 +55,7 @@ }; }; # end inputs - outputs = inputs@{ self, nixpkgs, nixpkgs-unstable, nix-darwin, home-manager, nix-homebrew, nix-flatpak, disko, sops-nix, flox-flake, genebean-omp-themes, ... }: let + outputs = inputs@{ self, nixpkgs, nixpkgs-unstable, nix-darwin, home-manager, nix-homebrew, nix-flatpak, disko, sops-nix, compose2nix, flox-flake, genebean-omp-themes, ... }: let # creates a macOS system config darwinHostConfig = system: hostname: username: nix-darwin.lib.darwinSystem { @@ -89,7 +95,7 @@ # creates a nixos system config nixosHostConfig = system: hostname: username: nixpkgs.lib.nixosSystem { - specialArgs = { inherit inputs username hostname flox-flake; + specialArgs = { inherit inputs username hostname compose2nix flox-flake; pkgs = import nixpkgs { inherit system; config = { diff --git a/modules/hosts/nixos/nixnuc/audiobookshelf.nix b/modules/hosts/nixos/nixnuc/audiobookshelf.nix deleted file mode 100644 index 7a77670..0000000 --- a/modules/hosts/nixos/nixnuc/audiobookshelf.nix +++ /dev/null @@ -1,23 +0,0 @@ -{ ... }: let - volume_base = "/orico/audiobookshelf"; -in { - # Audiobookshelf - virtualisation.oci-containers.containers = { - "audiobookshelf" = { - autoStart = true; - image = "ghcr.io/advplyr/audiobookshelf:latest"; - environment = { - AUDIOBOOKSHELF_UID = "99"; - AUDIOBOOKSHELF_GID = "100"; - }; - ports = [ "13378:80" ]; - volumes = [ - "${volume_base}/audiobooks:/audiobooks" - "${volume_base}/podcasts:/podcasts" - "${volume_base}/printbooks:/printbooks" - "${volume_base}/config:/config" - "${volume_base}/metadata:/metadata" - ]; - }; - }; -} diff --git a/modules/hosts/nixos/nixnuc/containers/audiobookshelf.nix b/modules/hosts/nixos/nixnuc/containers/audiobookshelf.nix new file mode 100644 index 0000000..44d63d3 --- /dev/null +++ b/modules/hosts/nixos/nixnuc/containers/audiobookshelf.nix @@ -0,0 +1,33 @@ +{ ... }: let + volume_base = "/orico/audiobookshelf"; + http_port = "13378"; +in { + # Audiobookshelf + + ############################################################################# + # I am using v2.8.1 because that is both the current Docker image and # + # the current version in nixpkgs unstable. My plan is to switch from Podman # + # to a systemd-nspawn container. # + ############################################################################# + + virtualisation.oci-containers.containers = { + "audiobookshelf" = { + autoStart = true; + image = "ghcr.io/advplyr/audiobookshelf:2.8.1"; + environment = { + AUDIOBOOKSHELF_UID = "99"; + AUDIOBOOKSHELF_GID = "100"; + }; + ports = [ "${http_port}:80" ]; + volumes = [ + "${volume_base}/audiobooks:/audiobooks" + "${volume_base}/podcasts:/podcasts" + "${volume_base}/printbooks:/printbooks" + "${volume_base}/config:/config" + "${volume_base}/metadata:/metadata" + ]; + }; + }; + + services.restic.backups.daily.paths = [ volume_base ]; +} diff --git a/modules/hosts/nixos/nixnuc/containers/nginx-proxy.nix b/modules/hosts/nixos/nixnuc/containers/nginx-proxy.nix index 13e93d1..227352a 100644 --- a/modules/hosts/nixos/nixnuc/containers/nginx-proxy.nix +++ b/modules/hosts/nixos/nixnuc/containers/nginx-proxy.nix @@ -94,7 +94,7 @@ in { acmeRoot = null; forceSSL = true; locations."/".proxyWebsockets = true; - locations."/".proxyPass = "http://${mini_watcher}:13378"; + locations."/".proxyPass = "http://${backend_ip}:13378"; }; "atuin.${home_domain}" = { listen = [{ port = https_port; addr = "0.0.0.0"; ssl = true; }]; @@ -136,14 +136,14 @@ in { enableACME = true; acmeRoot = null; forceSSL = true; - locations."/".proxyPass = "http://${mini_watcher}:8090"; + locations."/".proxyPass = "http://${backend_ip}:8090"; }; "tandoor.${home_domain}" = { listen = [{ port = https_port; addr = "0.0.0.0"; ssl = true; }]; enableACME = true; acmeRoot = null; forceSSL = true; - locations."/".proxyPass = "http://${mini_watcher}:8080"; + locations."/".proxyPass = "http://${backend_ip}:8080"; }; }; }; diff --git a/modules/hosts/nixos/nixnuc/containers/psitransfer.nix b/modules/hosts/nixos/nixnuc/containers/psitransfer.nix new file mode 100644 index 0000000..b8f6e55 --- /dev/null +++ b/modules/hosts/nixos/nixnuc/containers/psitransfer.nix @@ -0,0 +1,32 @@ +{ config, ... }: let + volume_base = "/orico/psitransfer"; + http_port = "3000"; + psitransfer_dot_env = "${config.sops.secrets.psitransfer_dot_env.path}"; +in { + + ############################################################################# + # My intent as of now is to only make this available to the outside world # + # on an as-needed basis, maybe via Tailscale Funnel. # + # For example: $ tailscale funnel localhost:3000 # + ############################################################################# + + sops.secrets.psitransfer_dot_env = { + sopsFile = ../secrets.yaml; + restartUnits = [ + "podman-psitransfer.service" + ]; + }; + + virtualisation.oci-containers.containers = { + "psitransfer" = { + autoStart = true; + image = "psitrax/psitransfer"; + environmentFiles = [ psitransfer_dot_env ]; + ports = [ "${http_port}:3000" ]; + volumes = [ + "${volume_base}/data:/data" + ]; + }; + }; +} + diff --git a/modules/hosts/nixos/nixnuc/default.nix b/modules/hosts/nixos/nixnuc/default.nix index 82e73ba..abd2d4d 100644 --- a/modules/hosts/nixos/nixnuc/default.nix +++ b/modules/hosts/nixos/nixnuc/default.nix @@ -1,8 +1,10 @@ -{ config, pkgs, username, ... }: { +{ compose2nix, config, pkgs, username, ... }: { imports = [ ./hardware-configuration.nix - ./audiobookshelf.nix + ./containers/audiobookshelf.nix + ./containers/psitransfer.nix ./containers/nginx-proxy.nix + ../../../system/common/linux/restic.nix ]; system.stateVersion = "23.11"; @@ -21,12 +23,16 @@ }; environment.systemPackages = with pkgs; [ + compose2nix.packages.${pkgs.system}.default + docker-compose intel-gpu-tools jellyfin jellyfin-ffmpeg jellyfin-web net-snmp nginx + podman-compose + podman-tui # status of containers in the terminal yt-dlp ]; @@ -43,7 +49,14 @@ networking = { # Open ports in the firewall. - firewall.allowedTCPPorts = [ 22 80 ]; + firewall.allowedTCPPorts = [ + 22 # ssh + 80 # http to local Nginx + 3000 # PsiTransfer in oci-container + 8080 # Tandoor in docker compose + 8090 # Wallabag in docker compose + 13378 # Audiobookshelf in oci-container + ]; # firewall.allowedUDPPorts = [ ... ]; # Or disable the firewall altogether. # firewall.enable = false; @@ -60,7 +73,11 @@ }; interfaces = { eno1.useDHCP = true; - br1-23.useDHCP = false; + br1-23 = { + useDHCP = false; + # This enables the container attached to the bridge to be reachable + ipv4.routes = [{ address = "192.168.23.21"; prefixLength = 32; }]; + }; }; }; @@ -127,6 +144,13 @@ }; }; }; + resolved.enable = true; + restic.backups.daily.paths = [ + "/orico/jellyfin/data" + "/orico/jellyfin/staging/downloaded-files" + "${config.users.users.${username}.home}/compose-files/tandoor" + "${config.users.users.${username}.home}/compose-files/wallabag" + ]; tailscale = { enable = true; authKeyFile = config.sops.secrets.tailscale_key.path; @@ -162,11 +186,24 @@ users.users.${username} = { isNormalUser = true; description = "Gene Liverman"; - extraGroups = [ "docker" "networkmanager" "wheel" ]; - packages = with pkgs; [ - docker-compose - ]; + extraGroups = [ "docker" "podman" "networkmanager" "wheel" ]; }; + # Enable common container config files in /etc/containers + virtualisation.containers.enable = true; + + virtualisation.oci-containers.backend = "podman"; + + # Compose based apps were crashing with podman compose, so back to Docker... virtualisation.docker.enable = true; + + virtualisation.podman = { + enable = true; + autoPrune.enable = true; + #dockerCompat = true; + extraPackages = [ pkgs.zfs ]; # Required if the host is running ZFS + + # Required for container networking to be able to use names. + defaultNetwork.settings.dns_enabled = true; + }; } diff --git a/modules/hosts/nixos/nixnuc/secrets.yaml b/modules/hosts/nixos/nixnuc/secrets.yaml index de8c622..6b5196f 100644 --- a/modules/hosts/nixos/nixnuc/secrets.yaml +++ b/modules/hosts/nixos/nixnuc/secrets.yaml @@ -1,6 +1,7 @@ tailscale_key: ENC[AES256_GCM,data:aB3KUD4QYm+ZDrjjLcU3gQ8kneVGkVYBsrkVcioOhxunal2FekLDrpKxJwNXuiwx2M5vipnGAEPO,iv:e+tPPfVYkv4U0KRGwspWb1O3ZQom/WFFGm9H9cd/KKE=,tag:ZG5z1C18bj1L7DcGzunQ0w==,type:str] local_git_config: ENC[AES256_GCM,data:Nqwog5C4wnRzNoS4oqaYQ4J1DIj7fUL1y/nXESquR0N7KQ+ebhvuJnM=,iv:Q6o45LZStS3k8iO7s2P6u7OrKFu5alplshZuGgeRKmk=,tag:NcLJrI9AK4eDroODX15lcA==,type:str] local_private_env: ENC[AES256_GCM,data:qOPXTS2uo/1jyVEKCtBvuK/dzZaPf1K5tHuSVF2hBg4fdPYIsDPkM108cGVxJviebB3xVZejn/JVOdUDXQj6,iv:TtyMTOJXaPUrbSaAdtMaGPBlwLl/Y/IBYVCzhhiZozY=,tag:hUyVL8xk3w1iMwNAZw5QUw==,type:str] +psitransfer_dot_env: ENC[AES256_GCM,data:bhvU0AOCjecZ62BtLw4H1DdkLeatI+uUl6L7UkdDRkBF3sayO45Z1eR4q60tflXucyTGhT8WgKFz53I+C2dn265wzojIRc3Xr4TBLyWpfJ7/dct40SckgUiRvOnrefiriWQ=,iv:DGMhDkzgeupzzTJnCdVWDPUSo2wxI3MAypKQwVfHExE=,tag:KbteGqrkqgj2XB1lvlk/yQ==,type:str] sops: kms: [] gcp_kms: [] @@ -16,8 +17,8 @@ sops: bHZlNTZDV2NYU1hQQy9mem80SFF6TFkKfmjkJBfTdh0vTtGaVx1t3tHJvSsAwdYD PF025X9U+yG2oIopwXEVBkxcD70eyuJn3OqH0xoVLBkbhNM9i8LHrA== -----END AGE ENCRYPTED FILE----- - lastmodified: "2023-12-21T01:11:58Z" - mac: ENC[AES256_GCM,data:Yr41oSVmHr6UJ5H9tSTq5Cv5yZJH3Mfi7QQowJ6uu/L9WO4Ehjij3z7WGhsYk3EQvZjH0C2pcFKZY4ldaMLJNGN3pn0xmIvs3H4KIpVcmJLbPjUzRguCDV4ETSrBcB1z6IF1YPnCzUGmGWLkEePIZmeVvXMkBvKWITXzm9ApCHM=,iv:crQ9DBzq3btjrTZt+Pcch+evJszzVmokLM4pyRhGTo8=,tag:6GfDtzoCdFMw65VWL4CU/A==,type:str] + lastmodified: "2024-04-12T12:45:07Z" + mac: ENC[AES256_GCM,data:SdLYmMEPe3UilHiSifRvLYFd9gJR7KlmcaGtkKB5X+Xj94KMALsfrU0NsRmrlMr5XGYSwhBIaJrgz9RPFUu5VmG1Lli2K8D8QNyc/qSr7AHTWU9uBFfmFJEau0VyD6oFmi/nJPObwJlTfoUn5H7BU0jCFjNnsf1BYHXS8Qafh4Y=,iv:vEwboA3iz/6tHpWh5ZQhkok9ZAOGXf1WHI+6VrR4fnA=,tag:lfTIRhg99Vs57hFQE/n84g==,type:str] pgp: [] unencrypted_suffix: _unencrypted version: 3.8.1 diff --git a/modules/system/common/all-nixos.nix b/modules/system/common/all-nixos.nix index 3aff185..5d3761a 100644 --- a/modules/system/common/all-nixos.nix +++ b/modules/system/common/all-nixos.nix @@ -9,7 +9,9 @@ age dconf2nix file + iftop inetutils + iotop neofetch python3 sops diff --git a/modules/system/common/linux/restic.nix b/modules/system/common/linux/restic.nix new file mode 100644 index 0000000..6f3b1ee --- /dev/null +++ b/modules/system/common/linux/restic.nix @@ -0,0 +1,28 @@ +{ config, pkgs, ... }: { + environment.systemPackages = with pkgs; [ + restic + ]; + + sops.secrets = { + restic_env.sopsFile = ../secrets.yaml; + restic_repo.sopsFile = ../secrets.yaml; + restic_password.sopsFile = ../secrets.yaml; + }; + + services.restic.backups = { + daily = { + initialize = true; + + environmentFile = config.sops.secrets.restic_env.path; + repositoryFile = config.sops.secrets.restic_repo.path; + passwordFile = config.sops.secrets.restic_password.path; + + pruneOpts = [ + "--keep-daily 7" + "--keep-weekly 5" + "--keep-monthly 6" + ]; + }; + }; +} + diff --git a/modules/system/common/secrets.yaml b/modules/system/common/secrets.yaml index 8064289..c5749fb 100644 --- a/modules/system/common/secrets.yaml +++ b/modules/system/common/secrets.yaml @@ -1,5 +1,8 @@ gandi_dns_pat: ENC[AES256_GCM,data:81tlAE6e655+RgKZVJgwYg6V59VtMmuVk5spkGZq1U6AgxYXO3wvsA==,iv:Dp5csrqHIAYloi5XkrBgDMqeIX/W+JFJ1avKbTnEU/Y=,tag:QjhdX4gv9OmWtQp7r06+RA==,type:str] gandi_api: ENC[AES256_GCM,data:YsdDMk75miIKO4LkCZjfwJw6gxfrmsTL,iv:BOPRxB661sPJnUH1AUKEALIJfBeyAHZpkWJEDbY+7i8=,tag:TvtW7qhPbOqi9kKDcIe28w==,type:str] +restic_env: ENC[AES256_GCM,data:FCYR8tkClRwfcjUotcr28D6uRz7sNihn50nw38CaYnqOD/U9+5kU0iAPSvqAbeuw+xUoKKKAPAfMHI12dPTYt17Wz1N7i4a+MRkiIR9pjyv5KZTK59G+,iv:jStc8GMbZUQUgooZiRdImSZskdckYN1cRm2gsKbUyYY=,tag:HpQQIj1j7fjCmxkSeY/k4g==,type:str] +restic_repo: ENC[AES256_GCM,data:kCoNYVKwB87W4h5doa3IXj4n,iv:jKEw/Hki/tp3RSTsRB4dlg593I5B4pCLBav84ADCh70=,tag:+GFF5vHOVw0r/G8BbhcCjw==,type:str] +restic_password: ENC[AES256_GCM,data:PfQsxJul1Qpt3WQoUEI941l+yng3lVjhDd8=,iv:U5KjhcVqyksN2ay19RBjNhYIB31tUbfNRIqCEx/+Wbc=,tag:jsoU+B1mjAprPK+M5I0pAQ==,type:str] sops: kms: [] gcp_kms: [] @@ -69,8 +72,8 @@ sops: ZlBVMUJmWml3dkQ3OTN1ZmF1N0hXNHcKnLOSViooQmhU5yE754VHIBYNRVikgptc 3bXDiOlkjBbxGru3bnn+vUUJ3n+QdZoAnCgdL7D2/Me3HVrAW5M5LA== -----END AGE ENCRYPTED FILE----- - lastmodified: "2024-04-05T03:17:40Z" - mac: ENC[AES256_GCM,data:4u2rpoc20qDv3W6s3lgtYU+35cfaK1tOmMySuji07s7IxqXqmkAn/giynH7y+PQRLACV6XvKnysLwuTPanekmXqQx/cOPOIPPrXOwz4oDLncFILI+7H/ShFuRN3KKUq9+OZElO4lLO0PDL+6flo3Mq6oSbzzeqxqVXUvt5gG8So=,iv:WEoiZzIWxAsxr3+nUY7b/jewYn6YRraU+zIPBhin8JI=,tag:BN5zLe8jdrvvCFU0BbfiaQ==,type:str] + lastmodified: "2024-04-07T00:55:24Z" + mac: ENC[AES256_GCM,data:5GaItFbHP8Qj8Dev5a0kkI7VFovvW5STaI7MPaZibHWCB2Xvcw50ZjKPRVVx6yqsnjz6zf3H2h/siowq/eAvvKJ5gltbof4NAxcCqjcOrqpUaeFT1ykG2SMznX8OezUyH6K7KmFgSFgYv3F/5JhoQOIClJs4NmQIBxUf7afY9KQ=,iv:oJhBRcyyL5zBc324tyyTYF2i1a0Q+CkOxwg4HbyUXkA=,tag:kK9/bQIO/VioSpmxC7P+XA==,type:str] pgp: [] unencrypted_suffix: _unencrypted version: 3.8.1