diff --git a/.gitignore b/.gitignore deleted file mode 100644 index fd099b8..0000000 --- a/.gitignore +++ /dev/null @@ -1,74 +0,0 @@ -### Linux gitignore ### -*~ - -# temporary files which can be created if a process still has a handle open of a deleted file -.fuse_hidden* - -# Metadata left by Dolphin file manager, which comes with KDE Plasma -.directory - -# Linux trash folder which might appear on any partition or disk -.Trash-* - -# .nfs files are created when an open file is removed but is still being accessed -.nfs* - -# Log files created by default by the nohup command -nohup.out - -### MacOS gitignore ### -# General -.DS_Store -__MACOSX/ -.AppleDouble -.LSOverride -Icon[] - -# Thumbnails -._* - -# Files that might appear in the root of a volume -.DocumentRevisions-V100 -.fseventsd -.Spotlight-V100 -.TemporaryItems -.Trashes -.VolumeIcon.icns -.com.apple.timemachine.donotpresent - -# Directories potentially created on remote AFP share -.AppleDB -.AppleDesktop -Network Trash Folder -Temporary Items -.apdisk - -### Nix gitignore ### -# Ignore build outputs from performing a nix-build or `nix build` command -result -result-* - -# Ignore automatically generated direnv output -.direnv - -### Vim gitignore ### -# Swap -[._]*.s[a-v][a-z] -# comment out the next line if you don't need vector files -!*.svg -[._]*.sw[a-p] -[._]s[a-rt-v][a-z] -[._]ss[a-gi-z] -[._]sw[a-p] - -# Session -Session.vim -Sessionx.vim - -# Temporary -.netrwhist -*~ -# Auto-generated tag files -tags -# Persistent undo -[._]*.un~ diff --git a/README.md b/README.md deleted file mode 100644 index d650f9b..0000000 --- a/README.md +++ /dev/null @@ -1,157 +0,0 @@ -# nix-dotfiles - -System and home configurations for my machines. - -| Machine | Role | OS | Arch | System config tool | Home config tool | -| -------- | --------------- | ------ | ------- | --------------------------- | ---------------- | -| anderson | server | linux | x86_64 | dpkg/Docker (not this repo) | home-manager | -| bosephus | server | linux | x86_64 | NixOS | home-manager | -| mcentire | server | linux | x86_64 | NixOS | home-manager | -| corianne | MacBook | darwin | aarch64 | nix-darwin | home-manager | -| odyssey | workstation | linux | x86_64 | Ansible | home-manager | - -## Quickstart - -### Home dotfiles - -> ![WARNING] -> Fedora systems will set this up automagically via Ansible. Follow the -[Fedora quickstart] instructions. - -Ensure Nix is installed, with the `nix` command and flakes enabled. I try to use -the [Determinate Nix installer] (with upstream Nix) to install Nix with these -options turned on by default. - -```bash -curl -fsSL https://install.determinate.systems/nix | sh -s -- install -``` - -Once Nix is installed, clone the repository to `~/.config/home-manager` and -initiate home-manager. - -```bash -git clone https://code.millironx.com/millironx/nix-dotfiles.git ~/.config/home-manager -nix run home-manager -- switch --flake ~/.config/home-manager#$USER@$(hostname -s) -``` - -In the case that the host has not been assigned a configuration within this repo -yet, pick a hostname with the same system OS, arch, and role as the target -system to get temporary dotfiles up and running. - -```bash -nix run home-manager -- switch --flake ~/.config/home-manager#millironx@anderson -``` - -Once an SSH (with or without GPG) key has been setup and added to the authorized -keys of the git server, switch the upstream to track an authorized (i.e. -read/write) version of the repo. - -```bash -cd ~/.config/home-manager -git remote set-url origin git@code.millironx.com:millironx/nix-dotfiles.git -cd - -``` - -### NixOS - -Switching to a flake-based config requires running as root. All of the following -commands are assumed to be running as root. - -Ensure that the `nix` command and flakes are enabled. - -```bash -sed -i '/^}/i nix.settings.experimental-features = [ "nix-command" "flakes" ];' /etc/nixos/configuration.nix -nixos-rebuild switch -``` - -> ![NOTE] -> To allow secret decryption in the system, the *machine*-specific SSH key must -> be added to the publicKeys attribute of all applicable secrets, and the -> `hardware-configuration.nix` file must be added to git. Copying arbitrary -> strings like SSH keys or disk UUIDs between systems can be painful, so it might -> be worth setting up the [home dotfiles] immediately after enabling flakes, -> then running these steps on the same machine to avoid typos. Alternatively, I -> might someday be smart enough to create an installer CD that automagically -> sets this up for me. - -Get the machine-specific public SSH key. - -```bash -cat /etc/ssh/ssh_host_ed25519_key.pub -``` - -On a separate machine, add the machine's SSH key to `./secrets.nix` and assign -it to any secrets it would need. - -```nix -let - bosephus-host = - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIxTfeg+GZsfmG8TuEV1xW1gXknAIKzZ3UjZ3guRY+EW root@nixos"; - bosephus-millironx = - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKaDPqRJHoqgY2pseh/mnhjaGWXprHk2s5I52LhHpHcF millironx@bosephus"; - odyssey-millironx = - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN9Aj7BtQp1Roa0tgopDrUo7g2am5WJ43lO1d1fDUz45 millironx@odyssey"; - - system-administrators = [ - bosephus-millironx - odyssey-millironx - ]; -in { - "secrets/network-information.age".publicKeys = system-administrators - ++ [ bosephus-host ]; -} -``` - -Rekey the secrets, and push the updated secrets to the upstream repo. - -```bash -nix run github:ryantm/agenix -- --rekey -git add secrets.nix secrets/* -git commit -m "added $NEW_HOST to secrets" -git push -``` - -Copy the target machine's `hardware-configuration.nix` file to this repo's -`./systems/linux/hardware-configuration/$NEW_HOST.nix`, and be sure to update -the configuration to import its own `hardware-configuration`. - -```bash -cp /etc/nixos/hardware-configuration.nix ./systems/linux/hardware-configuration/$NEW_HOST.nix -``` - -```nix -{ config, pkgs, ... }: { - imports = [ - ./hardware-configuration/bosephus.nix - ]; -} -``` - -Commit and push the hardware configuration to the upstream repo. - -```bash -git add systems/linux/* -git commit -m "added $NEW_HOST hardware configuration" -git push -``` - -Now switch to the flake by pulling and switching in one step. - - -```bash -nixos-rebuild switch --flake git+https://code.millironx.com/millironx/nix-dotfiles#$(hostname -s) -``` - -### Fedora - -Fedora systems are managed using Ansible. - -TODO - -## Home settings - -TODO - -[determinate nix installer]: https://github.com/DeterminateSystems/nix-installer -[fedora quickstart]: #fedora -[home dotfiles]: #home-dotfiles diff --git a/bin/secret-translator.jl b/bin/secret-translator.jl deleted file mode 100644 index c5dee39..0000000 --- a/bin/secret-translator.jl +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env julia -using TOML: TOML - -@show ENV["PATH"] - -function remove_podman_secrets() - run(`podman secret rm --all`) - return nothing -end #function - -function create_podman_secret(name, secret) - run( - addenv( - `podman secret create --env=true --replace $name SECRET`, - Dict("SECRET" => secret), - ), - ) - return nothing -end #function - -function parse_toml_secrets(file) - foreach(f -> create_podman_secret(f[1], f[2]), TOML.parsefile(file)) - return nothing -end #function - -function main() - remove_podman_secrets() - foreach(parse_toml_secrets, ARGS) - return 0 -end #function - -main() diff --git a/conf/peertube.caddyfile b/conf/peertube.caddyfile deleted file mode 100644 index 204cd75..0000000 --- a/conf/peertube.caddyfile +++ /dev/null @@ -1,157 +0,0 @@ -# Translated from -@api_resumable </dev/null)" ] && [ ! -n "$(ls $FREETUBE_CONFIG_DIR/*.db 2>/dev/null)" ]; then + echo "Performing initial sync from Nextcloud to FreeTube" + for DB_FILE in "''${DB_FILES[@]}"; do + if [ -f "$NEXTCLOUD_DIR/$DB_FILE" ]; then + rsync -av --checksum "$NEXTCLOUD_DIR/$DB_FILE" "$FREETUBE_CONFIG_DIR/$DB_FILE" + fi + done + # If Nextcloud is empty but FreeTube has db files, copy to Nextcloud + elif [ ! -n "$(ls $NEXTCLOUD_DIR/*.db 2>/dev/null)" ] && [ -n "$(ls $FREETUBE_CONFIG_DIR/*.db 2>/dev/null)" ]; then + echo "Performing initial sync from FreeTube to Nextcloud" + for DB_FILE in "''${DB_FILES[@]}"; do + if [ -f "$FREETUBE_CONFIG_DIR/$DB_FILE" ]; then + rsync -av --checksum "$FREETUBE_CONFIG_DIR/$DB_FILE" "$NEXTCLOUD_DIR/$DB_FILE" + fi + done + else + # Process each database file individually + for DB_FILE in "''${DB_FILES[@]}"; do + FT_PATH="$FREETUBE_CONFIG_DIR/$DB_FILE" + NC_PATH="$NEXTCLOUD_DIR/$DB_FILE" + + # Skip if neither file exists + if [ ! -f "$FT_PATH" ] && [ ! -f "$NC_PATH" ]; then + continue + fi + + # If only one exists, copy it + if [ -f "$FT_PATH" ] && [ ! -f "$NC_PATH" ]; then + echo "Copying $DB_FILE from FreeTube to Nextcloud" + rsync -av "$FT_PATH" "$NC_PATH" + continue + fi + + if [ ! -f "$FT_PATH" ] && [ -f "$NC_PATH" ]; then + echo "Copying $DB_FILE from Nextcloud to FreeTube" + rsync -av "$NC_PATH" "$FT_PATH" + continue + fi + + # Both files exist, check which is newer + if [ "$FT_PATH" -nt "$NC_PATH" ]; then + echo "Syncing newer $DB_FILE from FreeTube to Nextcloud" + rsync -av --update "$FT_PATH" "$NC_PATH" + elif [ "$NC_PATH" -nt "$FT_PATH" ]; then + echo "Syncing newer $DB_FILE from Nextcloud to FreeTube" + rsync -av --update "$NC_PATH" "$FT_PATH" + else + # Same modification time, compare checksums + echo "Verifying $DB_FILE with checksum comparison" + rsync -av --checksum "$NC_PATH" "$FT_PATH" + rsync -av --checksum "$FT_PATH" "$NC_PATH" + fi + done + fi + '' + ]; + RunAtLoad = true; + StartInterval = 300; # Run every 5 minutes (300 seconds) + StandardOutPath = + "${config.home.homeDirectory}/Library/Logs/freetube-sync.log"; + StandardErrorPath = + "${config.home.homeDirectory}/Library/Logs/freetube-sync-error.log"; + EnvironmentVariables = { + PATH = "${lib.makeBinPath [ pkgs.rsync pkgs.findutils ]}:$PATH"; + }; + }; + }; + }; + }; programs = { bash = { profileExtra = '' diff --git a/homes/desktop.nix b/homes/desktop.nix index 37cdec8..2a0790c 100644 --- a/homes/desktop.nix +++ b/homes/desktop.nix @@ -2,9 +2,9 @@ imports = [ ./../programs/firefox.nix + ./../programs/ghostty.nix ./../programs/zed.nix ./../services/gpg-agent.nix - ./../services/syncthing.nix ]; home = { @@ -23,7 +23,7 @@ nil nixd nixfmt-classic - nixos-rebuild + ollama quarto roboto-slab shellcheck @@ -31,8 +31,6 @@ woodpecker-cli (texlive.combine { inherit (texlive) scheme-basic latex-bin latexmk; }) custom-pkgs.ark - custom-pkgs.jlfmt - custom-pkgs.runic ]; shellAliases = { code = "codium"; diff --git a/homes/harmony.nix b/homes/harmony.nix new file mode 100644 index 0000000..2e48431 --- /dev/null +++ b/homes/harmony.nix @@ -0,0 +1,95 @@ +{ config, lib, pkgs, pkgs-unstable, ... }: { + # harmony is an Asahi Fedora box + # I don't use NixOS, so there are some programs that don't interact well with + # the base system (or won't even install) when installed from Nix. + # There is no uniform way to trigger dnf package installs from Nix, so I'm + # just going to list my packages here. I hope to create a custom script that + # mimics the ideas of a Brewfile someday + # TODO: Create a Brewfile equivalent for dnf + + # dnf repos: + # https://github.com/terrapkg/packages?tab=readme-ov-file + # https://pkgs.tailscale.com/stable/fedora/tailscale.repo + # https://packagecloud.io/filips/FirefoxPWA + + # copr repos: + # iucar/rstudio + + # dnf packages: + # apptainer + # chromium + # firefoxpwa - The nix version installs an "immutable" runtime, which simply launches extra browser windows on non-NixOS + # inkscape + # kate + # kdiff3 + # krita + # lutris + # musescore + # nextcloud-client + # nextcloud-client-dolphin + # obs-studio + # podman-compose + # podman-docker + # qownnotes + # qt + # rssguard + # rstudio-desktop + # steam + # supertuxkart + # tailscale + # thunderbird + # vlc + # vorta - The vorta package is aarch64 compatible, but you cannot see any icons, and it cannot access local ssh keys, so we have to use the dnf package instead + # yakuake + # zed + # zsh + # R + # https://downloads.sourceforge.net/project/mscorefonts2/rpms/msttcore-fonts-installer-2.6-1.noarch.rpm + home = { + username = "millironx"; + homeDirectory = "/home/millironx"; + # Signal desktop is not available in any other package repository for aarch64 linux + # Similarly, Bitwarden is non-functional in all other forms using a 16k page size + packages = with pkgs; [ + trayscale + veracrypt + pkgs-unstable.signal-desktop + pkgs.bitwarden-desktop + ]; + }; + programs = { + git = { + signing = { + key = "0x37A3041D1C8C4524!"; + signByDefault = true; + }; + }; + }; + services = { + gpg-agent = { sshKeys = [ "207D13371E19752A67AA2686C16354D9963821DB" ]; }; + }; + xdg = { + configFile = { + "nextflow.config".text = '' + params { + config_profile_description = 'harmony Asahi Linux local profile' + config_profile_contact = 'Thomas A. Christensen II <25492070+MillironX@users.noreply.github.com>' + config_profile_url = null + + max_memory = 12.GB + max_cpus = 12 + max_time = 7.d + } + + apptainer { + enabled = true + autoMounts = true + } + + process { + executor = 'local' + } + ''; + }; + }; +} diff --git a/homes/linux-desktop.nix b/homes/linux-desktop.nix index 8d25100..6d78716 100644 --- a/homes/linux-desktop.nix +++ b/homes/linux-desktop.nix @@ -18,16 +18,115 @@ in { ''; }; }; + systemd.user = { + services = { + freetube-sync = { + Unit = { + Description = "Sync FreeTube settings with Nextcloud"; + After = [ "network.target" ]; + }; + Service = { + Type = "oneshot"; + ExecStart = "${pkgs.writeShellScript "freetube-sync.sh" '' + FREETUBE_CONFIG_DIR="$HOME/.var/app/io.freetubeapp.FreeTube/config/FreeTube" + NEXTCLOUD_DIR="$HOME/Nextcloud/Settings/FreeTube" + + # Create directories if they don't exist + mkdir -p "$FREETUBE_CONFIG_DIR" + mkdir -p "$NEXTCLOUD_DIR" + + # List of database files to sync + DB_FILES=("settings.db" "history.db" "playlists.db" "subscriptions.db" "profiles.db") + + # Initial sync if Nextcloud has db files but FreeTube doesn't + if [ -n "$(ls -A $NEXTCLOUD_DIR/*.db 2>/dev/null)" ] && [ ! -n "$(ls -A $FREETUBE_CONFIG_DIR/*.db 2>/dev/null)" ]; then + echo "Performing initial sync from Nextcloud to FreeTube" + for DB_FILE in "''${DB_FILES[@]}"; do + if [ -f "$NEXTCLOUD_DIR/$DB_FILE" ]; then + rsync -av --checksum "$NEXTCLOUD_DIR/$DB_FILE" "$FREETUBE_CONFIG_DIR/$DB_FILE" + fi + done + # If Nextcloud is empty but FreeTube has db files, copy to Nextcloud + elif [ ! -n "$(ls -A $NEXTCLOUD_DIR/*.db 2>/dev/null)" ] && [ -n "$(ls -A $FREETUBE_CONFIG_DIR/*.db 2>/dev/null)" ]; then + echo "Performing initial sync from FreeTube to Nextcloud" + for DB_FILE in "''${DB_FILES[@]}"; do + if [ -f "$FREETUBE_CONFIG_DIR/$DB_FILE" ]; then + rsync -av --checksum "$FREETUBE_CONFIG_DIR/$DB_FILE" "$NEXTCLOUD_DIR/$DB_FILE" + fi + done + else + # Process each database file individually + for DB_FILE in "''${DB_FILES[@]}"; do + FT_PATH="$FREETUBE_CONFIG_DIR/$DB_FILE" + NC_PATH="$NEXTCLOUD_DIR/$DB_FILE" + + # Skip if neither file exists + if [ ! -f "$FT_PATH" ] && [ ! -f "$NC_PATH" ]; then + continue + fi + + # If only one exists, copy it + if [ -f "$FT_PATH" ] && [ ! -f "$NC_PATH" ]; then + echo "Copying $DB_FILE from FreeTube to Nextcloud" + rsync -av "$FT_PATH" "$NC_PATH" + continue + fi + + if [ ! -f "$FT_PATH" ] && [ -f "$NC_PATH" ]; then + echo "Copying $DB_FILE from Nextcloud to FreeTube" + rsync -av "$NC_PATH" "$FT_PATH" + continue + fi + + # Both files exist, check which is newer + if [ "$FT_PATH" -nt "$NC_PATH" ]; then + echo "Syncing newer $DB_FILE from FreeTube to Nextcloud" + rsync -av --update "$FT_PATH" "$NC_PATH" + elif [ "$NC_PATH" -nt "$FT_PATH" ]; then + echo "Syncing newer $DB_FILE from Nextcloud to FreeTube" + rsync -av --update "$NC_PATH" "$FT_PATH" + else + # Same modification time, compare checksums + echo "Verifying $DB_FILE with checksum comparison" + rsync -av --checksum "$NC_PATH" "$FT_PATH" + rsync -av --checksum "$FT_PATH" "$NC_PATH" + fi + done + fi + ''}"; + }; + }; + }; + + timers = { + freetube-sync = { + Unit = { Description = "Timer for FreeTube settings sync"; }; + Timer = { + OnBootSec = "1m"; + OnUnitActiveSec = "5m"; + }; + Install = { WantedBy = [ "timers.target" ]; }; + }; + }; + }; xdg = { configFile = { "plasma-workspace/env/ZED_WINDOW_DECORATIONS.sh".text = "export ZED_WINDOW_DECORATIONS=server"; + "dolphinrc".source = + mkOutOfStoreSymlink "${home-manager-repo}/dotfiles/dolphinrc"; + "konsolerc".source = + mkOutOfStoreSymlink "${home-manager-repo}/dotfiles/konsolerc"; "onedrive/config".text = '' force_session_upload = "true" delay_inotify_processing = "true" ''; + "yakuakerc".source = + mkOutOfStoreSymlink "${home-manager-repo}/dotfiles/yakuakerc"; }; dataFile = { + "konsole/My Default.profile".source = + mkOutOfStoreSymlink "${home-manager-repo}/dotfiles/MyDefault.profile"; "kio/servicemenus/kate.desktop".source = ./../dotfiles/kate.desktop; "kio/servicemenus/vlc.desktop".source = ./../dotfiles/vlc.desktop; "kio/servicemenus/word-to-pdf.desktop".source = diff --git a/homes/mcentire.nix b/homes/mcentire.nix deleted file mode 100644 index 82adbbc..0000000 --- a/homes/mcentire.nix +++ /dev/null @@ -1,8 +0,0 @@ -{ ... }: { - home = { - username = "millironx"; - homeDirectory = "/home/millironx"; - }; - programs = { }; - services = { }; -} diff --git a/homes/odyssey.nix b/homes/odyssey.nix index fd1c201..53b5368 100644 --- a/homes/odyssey.nix +++ b/homes/odyssey.nix @@ -14,23 +14,6 @@ services = { gpg-agent = { sshKeys = [ "F72C07DBA3DC0903C3ABB55E8B460803FEC22640" ]; }; }; - virtualisation.quadlet = { - containers = { - anythingllm = { - autoStart = true; - containerConfig = { - image = "docker.io/mintplexlabs/anythingllm:latest"; - addHosts = [ "ollama.millironx.local:host-gateway" ]; - publishPorts = [ "3001:3001" ]; - volumes = - [ "${config.xdg.dataHome}/anythingllm:/app/server/storage:Z" ]; - environments = { STORAGE_DIR = "/app/server/storage"; }; - - }; - }; - }; - autoUpdate.enable = true; - }; xdg = { configFile = { "nextflow.config".text = '' diff --git a/inventory.yaml b/inventory.yaml index 63f1f3c..ba53698 100644 --- a/inventory.yaml +++ b/inventory.yaml @@ -3,13 +3,20 @@ ungrouped: hosts: localhost: ansible_connection: local + harmony: + ansible_connection: local odyssey: ansible_connection: local +asahi: + hosts: + harmony: + amd64: hosts: odyssey: fedora: hosts: + harmony: odyssey: diff --git a/modules/podman-secrets.nix b/modules/podman-secrets.nix deleted file mode 100644 index fb99285..0000000 --- a/modules/podman-secrets.nix +++ /dev/null @@ -1,167 +0,0 @@ -# Warning to my future self: This module was "vibe coded" by Claude Sonnet 4.5. -# I originally had a hand-written module in here that did the secrets -# translation as the root user. I knew that I would want to support multiple -# secrets files and multiple users, and thought I should be able to create an -# arbitrary number of them, similar to how you can have an arbitrary number -# of `programs.firefox.profiles`. Unfortunately, even after looking at lots of -# example modules, I could not figure out the syntax (Nix has a serious lack -# of minimum working examples), so I broke down and asked Claude to rewrite it -# for me. Based on everything that I read, this seems to be exactly what I asked -# for. -# -# Here is the prompt I used to get here: -# [@Per service isolation on NixOS with Traefik](zed:///agent/thread/94cb8a22-ff0c-4772-a1a1-018b0107f334?name=Per+service+isolation+on+NixOS+with+Traefik) -# -# [@podman-secrets.nix](file:///home/millironx/.config/home-manager/modules/podman-secrets.nix) -# -# I originally wrote this module assuming that I would use Podman as root for -# all containers. I would like to fix the module to have as many secrets files -# processed as needed with services setup for each secret that is run as the -# appropriate user. Ideally, the syntax for working with secrets to be -# translated would be -# -# ```nix -# { config, ... }: { -# age.secrets = { -# "caddy.toml" = { -# file = ./../secrets/caddy.toml.age; -# owner = "caddy"; -# group = "caddy"; -# }; -# -# "authentik.toml" = { -# file = ./../secrets/authentik.toml.age; -# owner = "authentik"; -# group = "authentik"; -# }; -# -# "freshrss.toml" = { -# file = ./../secrets/freshrss.toml.age; -# owner = "freshrss"; -# group = "freshrss"; -# }; -# }; -# -# millironx.podman-secrets = with config; { -# caddy = { -# user = "caddy"; -# secrets-files = [ -# ./../not-really-secret.toml -# age.secrets."caddy.toml".path -# ]; -# }; -# authentik = { -# user = "authentik"; -# secrets-files = [ -# age.secrets."authentik.toml".path -# ]; -# }; -# freshrss = { -# user = "freshrss"; -# secrets-files = [ -# age.secrets."freshrss.toml".path -# ]; -# }; -# }; -# } -# ``` -# -# Can you help me rewrite the module to accomplish this? -# -{ config, lib, pkgs, ... }: -with lib; -let - cfg = config.millironx.podman-secrets; - - secret-translator = pkgs.writeScriptBin "secret-translator" - (builtins.readFile ./../bin/secret-translator.jl); - - # Submodule type for each service's secrets configuration - serviceSecretsType = types.submodule ({ config, name, ... }: { - options = { - user = mkOption { - type = types.str; - description = "User account to run the secrets translation service as"; - example = "caddy"; - }; - - secrets-files = mkOption { - type = types.listOf (types.either types.path types.string); - description = - "List of TOML files containing secrets to translate to Podman secrets"; - example = literalExpression '' - [ - "/run/agenix/caddy.toml" - ./../not-really-secret.toml - ] - ''; - default = [ ]; - }; - - ref = mkOption { - type = types.str; - description = - "Reference to the systemd service name for declaring dependencies"; - readOnly = true; - default = "podman-secrets-${name}.service"; - example = "podman-secrets-caddy.service"; - }; - }; - }); - - # Generate a systemd user service for each configured service - mkSecretsService = name: serviceCfg: - nameValuePair "podman-secrets-${name}" { - description = "Podman secrets converter service for ${name}"; - wantedBy = [ "default.target" ]; - - unitConfig.ConditionUser = "${serviceCfg.user}"; - - serviceConfig = { - Type = "oneshot"; - ProtectProc = "invisible"; - ExecStart = "${secret-translator}/bin/secret-translator ${ - lib.concatStringsSep " " serviceCfg.secrets-files - }"; - Environment = "PATH=/run/wrappers/bin:${ - lib.makeBinPath (with pkgs; [ shadow podman julia-lts-bin ]) - }"; - }; - }; - - # Filter out services with no secrets-files - enabledServices = - lib.filterAttrs (name: serviceCfg: serviceCfg.secrets-files != [ ]) cfg; - -in { - options.millironx.podman-secrets = mkOption { - type = types.attrsOf serviceSecretsType; - description = '' - Per-service Podman secrets configuration. - Each attribute creates a separate systemd user service that translates TOML secrets - files into Podman secrets. - ''; - example = literalExpression '' - { - caddy = { - user = "caddy"; - secrets-files = [ - ./../not-really-secret.toml - config.age.secrets."caddy.toml".path - ]; - }; - authentik = { - user = "authentik"; - secrets-files = [ - config.age.secrets."authentik.toml".path - ]; - }; - } - ''; - default = { }; - }; - - config = mkIf (enabledServices != { }) { - systemd.user.services = lib.mapAttrs' mkSecretsService enabledServices; - }; -} diff --git a/pkgs/default.nix b/pkgs/default.nix index 8178242..2e0c11e 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -1,7 +1,6 @@ { pkgs, ... }: -with pkgs; { - ark = callPackage ./ark.nix { }; - jlfmt = callPackage ./jlfmt.nix { }; - runic = callPackage ./runic.nix { }; - sc4pac = callPackage ./sc4pac.nix { }; + +{ + ark = pkgs.callPackage ./ark.nix { }; + sc4pac = pkgs.callPackage ./sc4pac.nix { }; } diff --git a/pkgs/jlfmt.nix b/pkgs/jlfmt.nix deleted file mode 100644 index 21916a4..0000000 --- a/pkgs/jlfmt.nix +++ /dev/null @@ -1,12 +0,0 @@ -{ pkgs, ... }: -with pkgs; -let - juliaWithPkgs = julia-bin.withPackages.override { setDefaultDepot = false; } - [ "JuliaFormatter" ]; - depotWithPkgs = runCommand "getDepot" { } '' - ${juliaWithPkgs}/bin/julia -e 'println(first(DEPOT_PATH))' | tee $out - ''; -in writeShellScriptBin "jlfmt" '' - export JULIA_DEPOT_PATH=$(< ${depotWithPkgs}) - exec ${juliaWithPkgs}/bin/julia --startup-file=no -e 'using JuliaFormatter; print(format_text(String(read(stdin))));' -- "$@" -'' diff --git a/pkgs/runic.nix b/pkgs/runic.nix deleted file mode 100644 index b91b550..0000000 --- a/pkgs/runic.nix +++ /dev/null @@ -1,12 +0,0 @@ -{ pkgs, ... }: -with pkgs; -let - juliaWithRunic = - julia-bin.withPackages.override { setDefaultDepot = false; } [ "Runic" ]; - depotWithRunic = runCommand "getRunicDepot" { } '' - ${juliaWithRunic}/bin/julia -e 'println(first(DEPOT_PATH))' | tee $out - ''; -in writeShellScriptBin "runic" '' - export JULIA_DEPOT_PATH=$(< ${depotWithRunic}) - exec ${juliaWithRunic}/bin/julia --startup-file=no -e 'using Runic; exit(Runic.main(ARGS))' -- "$@" -'' diff --git a/playbooks/config.yaml b/playbooks/config.yaml index 156dc63..4aa2dd4 100644 --- a/playbooks/config.yaml +++ b/playbooks/config.yaml @@ -11,7 +11,7 @@ mode: "755" - name: Create Firefox DNS policy ansible.builtin.template: - src: "policies.json" + src: "{{ playbook_dir }}/../templates/policies.json" dest: /etc/firefox/policies/policies.json mode: "644" diff --git a/playbooks/nix.yaml b/playbooks/nix.yaml index 50d9952..672725f 100644 --- a/playbooks/nix.yaml +++ b/playbooks/nix.yaml @@ -45,8 +45,7 @@ register: home_manager_exists - name: Init home-manager ansible.builtin.shell: | - /nix/var/nix/profiles/default/bin/nix run home-manager -- switch \ - --flake git+https://code.millironx.com/millironx/nix-dotfiles#{{ ansible_user_id }}@{{ ansible_hostname }} + /nix/var/nix/profiles/default/bin/nix run home-manager -- switch --flake git+https://code.millironx.com/millironx/nix-dotfiles#{{ ansible_user_id }}@{{ ansible_hostname }} when: not home_manager_exists.stat.exists register: home_manager_init changed_when: home_manager_init.rc == 0 diff --git a/playbooks/packages.yaml b/playbooks/packages.yaml index f293815..612acde 100644 --- a/playbooks/packages.yaml +++ b/playbooks/packages.yaml @@ -1,33 +1,78 @@ --- -- name: Configure dnf packages +# These are repos and packages that are useless or unavailable on Asahi Linux, +# or have completely separate install procedures. +- name: Configure amd64-specific dnf packages + hosts: amd64 + become: true + tasks: + - name: Install x86-specific dnf packages + ansible.builtin.dnf: + name: + - libdvdcss + - mkvtoolnix + - mpv + - protontricks + - x264 + - x264-libs + state: present + - name: Install VeraCrypt + ansible.builtin.dnf: + name: https://launchpad.net/veracrypt/trunk/1.26.20/+download/veracrypt-1.26.20-Fedora-40-x86_64.rpm + state: present + disable_gpg_check: true + +- name: Configure amd64-specific Flatpaks + hosts: amd64 + become: false + tasks: + - name: Install x86-specific Flatpaks + community.general.flatpak: + name: + - com.bitwarden.desktop + - com.slack.Slack + - dev.deedles.Trayscale + - org.signal.Signal + state: latest + method: user + remote: flathub + +- name: Configure Asahi Linux-specific dnf packages + hosts: asahi + become: true + tasks: + - name: Install aarch64-specific dnf packages + ansible.builtin.dnf: + name: + - veracrypt + +- name: Configure common (all arch) dnf packages hosts: fedora become: true tasks: - - name: Install dnf packages + - name: Install common (all arch) dnf packages ansible.builtin.dnf: name: - chromium + - firefoxpwa - fontconfig-devel - freetype-devel - fribidi-devel + - ghostty - inkscape - jq - kate - kdenlive - kdiff3 - krita - - libdvdcss - libjpeg-devel - libpng-devel - libtiff-devel - libwebp-devel - - mkvtoolnix - - mpv + - musescore - nextcloud-client - nextcloud-client-dolphin - obs-studio - onedrive - - protontricks - qownnotes - qt - rssguard @@ -37,8 +82,6 @@ - thunderbird - vlc - vorta - - x264 - - x264-libs - yakuake - zed - zsh @@ -49,11 +92,6 @@ name: https://downloads.sourceforge.net/project/mscorefonts2/rpms/msttcore-fonts-installer-2.6-1.noarch.rpm state: present disable_gpg_check: true - - name: Install VeraCrypt - ansible.builtin.dnf: - name: https://launchpad.net/veracrypt/trunk/1.26.20/+download/veracrypt-1.26.20-Fedora-40-x86_64.rpm - state: present - disable_gpg_check: true - name: Install rig (R installation manager) ansible.builtin.dnf: name: https://github.com/r-lib/rig/releases/download/latest/r-rig-latest-1.{{ ansible_architecture }}.rpm @@ -71,23 +109,21 @@ name: "*" state: latest # noqa: package-latest -- name: Configure Flatpaks +- name: Configure common (all arch) Flatpaks hosts: fedora become: false tasks: - - name: Install Flatpaks + - name: Install common (all arch) Flatpaks community.general.flatpak: name: - - com.bitwarden.desktop - com.github.tchx84.Flatseal - com.logseq.Logseq - - com.slack.Slack - - dev.deedles.Trayscale + - io.freetubeapp.FreeTube - io.github.alainm23.planify - io.github.dweymouth.supersonic - io.openrct2.OpenRCT2 - - org.signal.Signal - org.zulip.Zulip + - net.ankiweb.Anki state: latest method: user remote: flathub diff --git a/playbooks/repos.yaml b/playbooks/repos.yaml index 476dfdb..b771518 100644 --- a/playbooks/repos.yaml +++ b/playbooks/repos.yaml @@ -1,6 +1,6 @@ --- -- name: Configure dnf package repositories - hosts: fedora +- name: Configure amd64-specific package repositories + hosts: amd64 become: true tasks: - name: Install RPM Fusion free repository @@ -20,6 +20,31 @@ - name: Install Zotero COPR repository community.general.copr: name: "mozes/zotero7" + +# Asahi Linux comes with its own strange version of RPMFusion installed, so +# RPMFusion is installed only on amd64 systems. In addition, VeraCrypt and +# Zotero *are* available via COPR, but from different repos than their amd64 +# counterparts. +# Also, Asahi has its own version string, so we have to manually specify the +# chroot for COPR repos added via Ansible. This is handled automatically when +# using `dnf copr enable ...`, but not via Ansible. +- name: Configure Asahi Linux-specific package repositories + hosts: asahi + become: true + tasks: + - name: Install Zotero COPR repository + community.general.copr: + name: "isaksamsten/Zotero" + chroot: "fedora-{{ ansible_distribution_major_version }}-aarch64" + - name: Install VeraCrypt COPR repository + community.general.copr: + name: "architektapx/veracrypt" + chroot: "fedora-{{ ansible_distribution_major_version }}-aarch64" + +- name: Configure common (all arch) package repositories + hosts: fedora + become: true + tasks: - name: Install Tailscale repo ansible.builtin.yum_repository: name: tailscale-stable @@ -28,6 +53,14 @@ enabled: true gpgcheck: true gpgkey: https://pkgs.tailscale.com/stable/fedora/repo.gpg + - name: Install FirefoxPWA repository + ansible.builtin.yum_repository: + name: firefoxpwa + description: FirefoxPWA repository + baseurl: https://packagecloud.io/filips/FirefoxPWA/fedora/$releasever/$basearch + gpgcheck: true + gpgkey: https://packagecloud.io/filips/FirefoxPWA/gpgkey + enabled: true # Note that I still have to specify the chroot for COPR repos b/c of Asahi - name: Install RStudio copr repository community.general.copr: @@ -77,7 +110,7 @@ register: terra_priority changed_when: terra_priority.rc != 0 -- name: Configure Flatpack remotes +- name: Configure Flathub remote hosts: fedora become: false tasks: diff --git a/programs/alttab.nix b/programs/alttab.nix index 907b6d1..1901f4d 100644 --- a/programs/alttab.nix +++ b/programs/alttab.nix @@ -1,7 +1,7 @@ { ... }: { defaults."AltTab" = { appearanceStyle = 0; - nextWindowGesture = 3; + nextWindowGesture = 1; screenRecordingPermissionSkipped = true; showFullscreenWindows = 0; showHiddenWindows = 1; diff --git a/programs/firefox.nix b/programs/firefox.nix index dcf0553..520a4ef 100644 --- a/programs/firefox.nix +++ b/programs/firefox.nix @@ -1,4 +1,4 @@ -{ pkgs, firefox-addons, buildFirefoxXpiAddon, lib, ... }: { +{ firefox-addons, buildFirefoxXpiAddon, lib, ... }: { programs.firefox = { enable = true; package = @@ -31,48 +31,49 @@ }; }; containersForce = true; - extensions.packages = with firefox-addons; - [ - bitwarden - multi-account-containers - old-reddit-redirect - ublock-origin - user-agent-string-switcher - zotero-connector - (buildFirefoxXpiAddon rec { - pname = "always_in_container"; - version = "1.0.7"; - addonId = "{a1e9543e-5f73-4763-b376-04e53fd12cbd}"; - url = - "https://addons.mozilla.org/firefox/downloads/file/4032840/${pname}-${version}.xpi"; - sha256 = "sha256-bLxjL2P6Sd06q98MSHYRTNigtcjGwn/C2r4ANWCqKrw="; - meta = with lib; { - homepage = "https://github.com/tiansh/always-in-container"; - description = - "Chose a container every time you try to open a page out of a container"; - license = licenses.mpl20; - platforms = platforms.all; - }; - }) - (buildFirefoxXpiAddon rec { - pname = "open_with"; - version = "7.2.6"; - addonId = "openwith@darktrojan.net"; - url = - "https://addons.mozilla.org/firefox/downloads/file/3831723/${pname}-${version}.xpi"; - sha256 = "sha256-f9eGhLxg4UyVn4o5e4DRkraLWzj11SGto/GOwsJa9kg="; - meta = with lib; { - homepage = "https://darktrojan.github.io/openwith/"; - description = - "Quickly test out your web pages in Chrome, Edge, Safari, or Opera. Open With opens the current page in your other browsers with just two clicks."; - license = licenses.mpl20; - platforms = platforms.all; - }; - }) - ] ++ (if pkgs.stdenv.hostPlatform.isDarwin then - [ ] - else - [ plasma-integration ]); + extensions.packages = with firefox-addons; [ + bitwarden + multi-account-containers + floccus + libredirect + old-reddit-redirect + plasma-integration + pwas-for-firefox + ublock-origin + user-agent-string-switcher + web-archives + zotero-connector + (buildFirefoxXpiAddon rec { + pname = "always_in_container"; + version = "1.0.7"; + addonId = "{a1e9543e-5f73-4763-b376-04e53fd12cbd}"; + url = + "https://addons.mozilla.org/firefox/downloads/file/4032840/${pname}-${version}.xpi"; + sha256 = "sha256-bLxjL2P6Sd06q98MSHYRTNigtcjGwn/C2r4ANWCqKrw="; + meta = with lib; { + homepage = "https://github.com/tiansh/always-in-container"; + description = + "Chose a container every time you try to open a page out of a container"; + license = licenses.mpl20; + platforms = platforms.all; + }; + }) + (buildFirefoxXpiAddon rec { + pname = "open_with"; + version = "7.2.6"; + addonId = "openwith@darktrojan.net"; + url = + "https://addons.mozilla.org/firefox/downloads/file/3831723/${pname}-${version}.xpi"; + sha256 = "sha256-f9eGhLxg4UyVn4o5e4DRkraLWzj11SGto/GOwsJa9kg="; + meta = with lib; { + homepage = "https://darktrojan.github.io/openwith/"; + description = + "Quickly test out your web pages in Chrome, Edge, Safari, or Opera. Open With opens the current page in your other browsers with just two clicks."; + license = licenses.mpl20; + platforms = platforms.all; + }; + }) + ]; search = { default = "Kagi"; privateDefault = "Milliron X Search"; @@ -245,6 +246,7 @@ "floccus_handmadeideas_org-browser-action" "7esoorv3_alefvanoon_anonaddy_me-browser-action" "plasma-browser-integration_kde_org-browser-action" + "firefoxpwa_filips_si-browser-action" "_d07ccf11-c0cd-4938-a265-2a4d6ad01189_-browser-action" # Web Archives "openwith_darktrojan_net-browser-action" "zotero_chnm_gmu_edu-browser-action" @@ -280,6 +282,7 @@ "floccus_handmadeideas_org-browser-action" "7esoorv3_alefvanoon_anonaddy_me-browser-action" "plasma-browser-integration_kde_org-browser-action" + "firefoxpwa_filips_si-browser-action" "ublock0_raymondhill_net-browser-action" "_d07ccf11-c0cd-4938-a265-2a4d6ad01189_-browser-action" "zotero_chnm_gmu_edu-browser-action" diff --git a/programs/ghostty.nix b/programs/ghostty.nix new file mode 100644 index 0000000..bd91415 --- /dev/null +++ b/programs/ghostty.nix @@ -0,0 +1,19 @@ +{ pkgs, ... }: { + programs.ghostty = + let modifierKey = if pkgs.stdenv.isDarwin then "cmd" else "ctrl"; + in { + enable = true; + package = null; + enableBashIntegration = true; + enableZshIntegration = true; + settings = { + quick-terminal-position = "top"; + quick-terminal-screen = "main"; + quick-terminal-autohide = true; + quick-terminal-size = "50%,50%"; + keybind = "global:${modifierKey}+backquote=toggle_quick_terminal"; + macos-hidden = "always"; + linux-cgroup = "always"; + }; + }; +} diff --git a/programs/git.nix b/programs/git.nix index 89064e0..b4d790d 100644 --- a/programs/git.nix +++ b/programs/git.nix @@ -1,16 +1,10 @@ { ... }: { programs.git = { enable = true; - settings = { - user = { - name = "Thomas A. Christensen II"; - email = "25492070+MillironX@users.noreply.github.com"; - }; - core = { - editor = "nvim"; - # git push/pull via ssh over ipv6 is slow, so force ipv4 instead - sshCommand = "ssh -4"; - }; + userName = "Thomas A. Christensen II"; + userEmail = "25492070+MillironX@users.noreply.github.com"; + extraConfig = { + core = { editor = "nvim"; }; credential = { helper = "store"; }; color = { ui = "auto"; }; init = { defaultBranch = "master"; }; @@ -46,11 +40,6 @@ }; merge = { conflictstyle = "zdiff3"; }; pull = { rebase = true; }; - "url \"ssh://git@github.com/\"".insteadOf = "https://github.com/"; - "url \"ssh://git@gitlab.com/\"".insteadOf = "https://gitlab.com/"; - "url \"ssh://git@codeberg.com/\"".insteadOf = "https://codeberg.com/"; - "url \"ssh://git@code.millironx.com/\"".insteadOf = - "https://code.millironx.com/"; }; }; } diff --git a/programs/konsole.nix b/programs/konsole.nix deleted file mode 100644 index 66043de..0000000 --- a/programs/konsole.nix +++ /dev/null @@ -1,23 +0,0 @@ -{ ... }: { - programs.konsole = { - enable = true; - defaultProfile = "millironx"; - profiles.millironx = { - colorScheme = "Breeze"; - font = { - name = "MesloLGS NF"; - size = 10; - }; - extraConfig = { - "Cursor Options".CursorShape = 1; - General.RemoteTabTitleFormat = "[SSH] %H"; - "Interaction Options" = { - CopyTextAsHTML = false; - MouseWheelZoomEnabled = false; - UnderlineFilesEnabled = true; - }; - "Terminal Features".BlinkingCursorEnabled = true; - }; - }; - }; -} diff --git a/programs/plasma.nix b/programs/plasma.nix index c2db348..ea0b6e7 100644 --- a/programs/plasma.nix +++ b/programs/plasma.nix @@ -1,178 +1,7 @@ { config, ... }: { - - imports = [ ./konsole.nix ./yakuake.nix ]; - programs.plasma = { enable = true; - overrideConfig = true; - shortcuts = { yakuake.toggle-window-state = "Ctrl+`"; }; - configFile = { - dolphinrc = { - DetailsMode.PreviewSize = 16; - General = { - BrowseThroughArchives = true; - EditableUrl = true; - GlobalViewProps = false; - ShowFullPath = true; - ShowStatusBar = "FullWidth"; - ShowZoomSlider = true; - ViewMode = 1; - }; - "KFileDialog Settings" = { - "Places Icons Auto-resize" = false; - "Places Icons Static Size" = 22; - }; - PreviewSettings.Plugins = - "audiothumbnail,avif,blenderthumbnail,comicbookthumbnail,cursorthumbnail,djvuthumbnail,ebookthumbnail,exrthumbnail,directorythumbnail,fontthumbnail,imagethumbnail,jpegthumbnail,jxl,kraorathumbnail,windowsexethumbnail,windowsimagethumbnail,mobithumbnail,opendocumentthumbnail,gsthumbnail,rawthumbnail,svgthumbnail,gdk-pixbuf-thumbnailer,ffmpegthumbs,gsf-office"; - }; - }; - input.mice = [{ - enable = true; - name = "Logitech M705"; - vendorId = "046d"; - productId = "406d"; - naturalScroll = true; - }]; - kwin = { - cornerBarrier = false; - titlebarButtons = { - left = [ "close" "minimize" "maximize" ]; - right = [ "help" ]; - }; - virtualDesktops = { - number = 2; - rows = 1; - }; - }; - panels = [ - ### Screen 0 panels ### - ##### Top: Fedora menu | App switcher | Menu bar | CPU monitor | Memory monitor | Network monitor | System tray | clock ##### - { - location = "top"; - floating = true; - height = 27; - lengthMode = "fill"; - opacity = "adaptive"; - hiding = "normalpanel"; - screen = 0; - widgets = [ - { kickoff = { icon = "fedora-logo-icon"; }; } - "org.kde.plasma.marginsseparator" - "org.kde.plasma.windowlist" - "org.kde.plasma.appmenu" - "org.kde.plasma.panelspacer" - { - name = "org.kde.plasma.systemmonitor.cpu"; - config = { - Appearance.chartFace = "org.kde.ksysguard.barchart"; - Sensors.highPrioritySensorIds = "[${ - builtins.concatStringsSep "," (builtins.genList - (i: ''"cpu/cpu${builtins.toString i}/usage"'') 32) - }]"; - }; - } - { - name = "org.kde.plasma.systemmonitor.memory"; - config.Appearance.chartFace = "org.kde.ksysguard.horizontalbars"; - } - { - name = "org.kde.plasma.systemmonitor.net"; - config = { - Appearance.chartFace = "org.kde.ksysguard.horizontalbars"; - Sensors.highPrioritySensorIds = - ''[ "network/all/download","network/all/upload" ]''; - # These are the values needed to make the network indicator - # actually useful, but it appears that plasma-manager doesn't - # support nesting this deep yet. Disable for now. - # "org.kde.ksysguard.horizontalbars".General = { - # rangeAuto = false; - # rangeFromMultiplier = 1048576; - # rangeFromUnit = 202; - # rangeToMultiplier = 1048576; - # rangeToUnit = 202; - # }; - }; - } - { systemTray = { }; } - { digitalClock = { }; } - ]; - } - ##### Bottom: Virtual desktop pager | Full-name taskbar w/ pins | Downloads folder | Trash folder - { - location = "bottom"; - floating = true; - height = 44; - lengthMode = "fill"; - opacity = "adaptive"; - hiding = "normalpanel"; - screen = 0; - widgets = [ - "org.kde.plasma.pager" - { - iconTasks = { - iconsOnly = false; - behavior.showTasks.onlyInCurrentScreen = true; - launchers = [ - "applications:systemsettings.desktop" - "applications:org.kde.discover.desktop" - "preferred://filemanager" - "preferred://browser" - "applications:net.thunderbird.Thunderbird.desktop" - "applications:io.github.alainm23.planify.desktop" - "applications:dev.zed.Zed.desktop" - "applications:com.logseq.Logseq.desktop" - "applications:net.lutris.Lutris.desktop" - ]; - }; - } - "org.kde.plasma.panelspacer" - "org.kde.plasma.marginsseparator" - { - name = "org.kde.plasma.folder"; - config = { - General.url = "file://${config.home.homeDirectory}/Downloads"; - }; - } - "org.kde.plasma.trash" - ]; - } - - ### Screen 1 panels ### - ##### Top: App switcher | Menu bar ##### - { - location = "top"; - floating = true; - height = 27; - lengthMode = "fill"; - opacity = "adaptive"; - hiding = "normalpanel"; - screen = 1; - widgets = [ "org.kde.plasma.windowlist" "org.kde.plasma.appmenu" ]; - } - ##### Bottom: Virtual desktop pager | Full-name taskbar w/o pins ##### - { - location = "bottom"; - floating = true; - height = 44; - lengthMode = "fill"; - opacity = "adaptive"; - hiding = "normalpanel"; - screen = 1; - widgets = [ - "org.kde.plasma.pager" - { - iconTasks = { - iconsOnly = false; - behavior.showTasks.onlyInCurrentScreen = true; - launchers = [ ]; - }; - } - ]; - } - ]; - powerdevil.AC.autoSuspend.action = "nothing"; workspace = { - lookAndFeel = "org.kde.breezedark.desktop"; wallpaperFillMode = "preserveAspectCrop"; wallpaperSlideShow = { interval = 86400; diff --git a/programs/shells.nix b/programs/shells.nix index edb0f18..93b2d9d 100644 --- a/programs/shells.nix +++ b/programs/shells.nix @@ -1,7 +1,7 @@ { pkgs, ... }: let conda_init = shell: '' - eval "$(${pkgs.mamba-cpp}/bin/mamba shell hook --shell ${shell})" + eval "$(${pkgs.micromamba}/bin/micromamba shell hook --shell ${shell})" ''; nd_bash_function = '' @@ -10,53 +10,11 @@ let } ''; - sourceCodeDirectory = - if pkgs.stdenv.hostPlatform.isDarwin then "~/Developer" else "~/src"; - clone_bash_function = '' - unalias gc - function gc() { - REPO_ID="$(echo "''${1}" | \ - awk '{ - sub(/^git@/, ""); - sub(/^https:\/\//, ""); - sub (/:/, "/"); - sub(/\.git$/, ""); - print - }')" - git clone "https://''${REPO_ID}.git" ${sourceCodeDirectory}/''${REPO_ID} - cd ${sourceCodeDirectory}/''${REPO_ID} - } - - ''; - repo_init_function = '' - function rinit() { - REPO_ID="$(echo "''${1}" | \ - awk '{ - sub(/^git@/, ""); - sub(/^https:\/\//, ""); - sub (/:/, "/"); - sub(/\.git$/, ""); - print - }')" - - mkdir -p ${sourceCodeDirectory}/''${REPO_ID} - cd ${sourceCodeDirectory}/''${REPO_ID} - - git init - - git remote add origin git@''${REPO_ID/\//:}.git - } - - ''; - - shell_functions = shell: - (conda_init shell) + nd_bash_function + clone_bash_function - + repo_init_function; in { programs = { bash = { enable = true; - initExtra = shell_functions "bash" + '' + initExtra = conda_init "bash" + nd_bash_function + '' export PS1="[\[\e[32m\]\u\[\e[m\]@\[\e[33m\]\h\[\e[m\] \[\e[34m\]\W\[\e[m\]] \\$ " ''; }; @@ -79,7 +37,7 @@ in { "zsh-users/zsh-completions" ]; }; - initContent = shell_functions "zsh"; + initContent = conda_init "zsh" + nd_bash_function; }; }; } diff --git a/programs/ssh.nix b/programs/ssh.nix deleted file mode 100644 index a094d44..0000000 --- a/programs/ssh.nix +++ /dev/null @@ -1,73 +0,0 @@ -{ pkgs, lib, config, hostname, ... }: -let - sshIdPath = host: "~/.ssh/id_ed25519__${host}"; - tailnetConfig = host: { identityFile = sshIdPath host; }; - gitConfig = host: tailnetConfig host // { user = "git"; }; - tailnetHosts = [ "anderson" "mcentire" "bosephus" ]; - gitHosts = [ "github.com" "gitlab.com" "codeberg.org" "code.millironx.com" ]; - tailnetMatchBlocks = - lib.genAttrs (lib.lists.remove hostname tailnetHosts) tailnetConfig; - gitMatchBlocks = lib.genAttrs gitHosts gitConfig // { - "code.millironx.com" = (gitConfig "code.millironx.com") // { - proxyCommand = "ssh anderson -W localhost:2222"; - hostname = "code.millironx.com"; - }; - }; -in { - programs.ssh = { - enable = true; - enableDefaultConfig = false; - matchBlocks = { - "*" = { identitiesOnly = true; }; - "aahz" = { - hostname = "nistac-108-37.dhcp.ksu.edu"; - user = "tchristensen"; - identityFile = sshIdPath "aahz"; - }; - "skeeve" = { - hostname = "129.130.108.157"; - user = "tchristensen"; - identityFile = sshIdPath "skeeve"; - }; - "ceres" = { - hostname = "ceres.scinet.usda.gov"; - user = "thomas.christensen"; - identitiesOnly = false; - serverAliveInterval = 20; - serverAliveCountMax = 30; - extraOptions = { TCPKeepAlive = "yes"; }; - }; - "atlas" = { - hostname = "Atlas-login-1.hpc.msstate.edu"; - user = "thomas.christensen"; - identitiesOnly = false; - serverAliveInterval = 20; - serverAliveCountMax = 30; - extraOptions = { TCPKeepAlive = "yes"; }; - }; - "atlas-dtn" = { - hostname = "Atlas-dtn.hpc.msstate.edu"; - user = "thomas.christensen"; - identitiesOnly = false; - }; - "code.millironx.com" = { - proxyCommand = "ssh anderson -W localhost:2222"; - }; - } // tailnetMatchBlocks // gitMatchBlocks; - }; - - home.packages = let - # Answer no to overwrite questions - keygen = host: '' - yes "n" | \ - ssh-keygen \ - -t ed25519 \ - -f ~/.ssh/id_ed25519__${host} \ - -C "millironx@${hostname}" \ - -N "" - ''; - in [ - (pkgs.writeShellScriptBin "ssh-bootstrap-keys" - (builtins.concatStringsSep "\n" (map keygen (tailnetHosts ++ gitHosts)))) - ]; -} diff --git a/programs/taskbar.nix b/programs/taskbar.nix index cff7787..757d42d 100644 --- a/programs/taskbar.nix +++ b/programs/taskbar.nix @@ -25,10 +25,6 @@ bundleIdentifier = "org.mozilla.thunderbird"; action = "launchOrActivateApp"; } - { - bundleIdentifier = "com.microsoft.Outlook"; - action = "launchOrActivateApp"; - } { bundleIdentifier = "dev.zed.Zed"; action = "launchOrActivateApp"; @@ -38,13 +34,11 @@ action = "launchOrActivateApp"; } { - # Instinct dashboard bundleIdentifier = "com.apple.Safari.WebApp.2F51A6D0-087A-438F-92D3-A73FE09CB4CC"; action = "launchOrActivateApp"; } { - # Carestream bundleIdentifier = "com.apple.Safari.WebApp.5EC6478E-03A6-4147-8A4D-6EF3DE3F06D3"; action = "launchOrActivateApp"; diff --git a/programs/tmux.nix b/programs/tmux.nix deleted file mode 100644 index f1d45dd..0000000 --- a/programs/tmux.nix +++ /dev/null @@ -1,7 +0,0 @@ -{ pkgs, ... }: { - programs.tmux = { - enable = true; - terminal = "tmux-256color"; - plugins = with pkgs.tmuxPlugins; [ tmux-powerline ]; - }; -} diff --git a/programs/yakuake.nix b/programs/yakuake.nix deleted file mode 100644 index f8b86a7..0000000 --- a/programs/yakuake.nix +++ /dev/null @@ -1,19 +0,0 @@ -# Note: this file uses the lower-level `programs.plasma.configFile` syntax -# since plasma-manager does not yet support a high-level module for Yakuake -{ ... }: { - programs.plasma.configFile.yakuakerc = { - "Desktop Entry".DefaultProfile = "millironx.profile"; - Shortcuts = { - next-session = "Shift+Right; Ctrl+Shift+Tab"; - previous-terminal = "none"; - }; - Window = { - DynamicTabTitles = true; - Height = 60; - Screen = 1; - ShowSystrayIcon = false; - Width = 60; - }; - Dialogs.FirstRun = false; - }; -} diff --git a/programs/zed.nix b/programs/zed.nix index 639bd20..19beb45 100644 --- a/programs/zed.nix +++ b/programs/zed.nix @@ -1,11 +1,9 @@ -{ pkgs, hostname, ... }: { +{ ... }: { programs.zed-editor = { enable = true; - package = null; extensions = [ "basher" "clean-vscode-icons" - "caddyfile" "clojure" "dockerfile" "earthfile" @@ -25,74 +23,42 @@ use_modifier_to_send = true; default_model = { provider = "zed.dev"; - model = "claude-sonnet-4-5"; + model = "claude-3-7-sonnet"; }; default_profile = "minimal"; }; buffer_font_family = "FiraCode Nerd Font"; buffer_font_size = 11; features = { edit_prediction_provider = "zed"; }; - git_hosting_providers = [ - { - provider = "forgejo"; - base_url = "https://code.millironx.com"; - name = "Milliron X Code"; - } - { - provider = "forgejo"; - base_url = "https://codeberg.org"; - name = "Codeberg"; - } - ]; languages = { - Caddyfile = { - tab_size = 2; - formatter.external = { - command = "${pkgs.caddy}/bin/caddy"; - arguments = [ "fmt" "-c" "-" ]; + Julia = { + formatter = { + external = { + command = "julia"; + arguments = [ + "--project=@JuliaFormatter" + "--startup-file=no" + "-e" + "using JuliaFormatter; print(format_text(String(read(stdin))));" + ]; + }; }; }; - Julia = { formatter = { external = { command = "jlfmt"; }; }; }; LaTeX = { formatter = { external = { - command = let - latexindent = (pkgs.texlive.combine { - inherit (pkgs.texlive) scheme-minimal latexindent; - }); - in "${latexindent}/bin/latexindent"; - arguments = [ "-m" "-tt" "-l" "-" ]; + command = "tex-fmt"; + arguments = [ "--stdin" ]; }; }; }; - Nix = { - formatter.external.command = "${pkgs.nixfmt-classic}/bin/nixfmt"; - }; }; lsp = { - nil = { settings.nix.flake.autoArchive = true; }; - nixd = { - settings.options.home-manager.expr = '' - (builtins.getFlake (builtins.toString ~/.config/home-manager)).homeConfigurations."millironx@${hostname}".options''; - }; - texlab = { - settings.texlab = { - build = { - onSave = true; - forwardSearchAfter = true; - }; - forwardSearch = if pkgs.stdenv.hostPlatform.isDarwin then { - executable = - "/Applications/Skim.app/Contents/SharedSupport/displayline"; - args = [ "-r" "-g" "%l" "%p" "%f" ]; - } else { - executable = "/usr/bin/okular"; - args = [ "--unique" "file:%p#src:%l%f" ]; - }; - }; + nil = { + initialization_options.formatting.command = [ "nixfmt" ]; + settings.nix.flake.autoArchive = true; }; tinymist = { - initialization_options = { preview.background.enabled = true; }; settings = { exportPdf = "onSave"; outputPath = "$root/$name"; @@ -115,28 +81,5 @@ ui_font_size = 16; wrap_guides = [ 80 92 120 ]; }; - userTasks = [ - { - label = "latexmk (project)"; - command = "latexmk"; - args = [ "-synctex=1" "-pdf" "-recorder" ]; - cwd = "$ZED_DIRNAME"; - tags = [ "latex-build" ]; - } - { - label = "Open Typst preview"; - command = "${ - if pkgs.stdenv.hostPlatform.isDarwin then "open" else "xdg-open" - } http://127.0.0.1:23635/"; - use_new_terminal = true; - allow_concurrent_runs = false; - reveal = "never"; - reveal_target = "dock"; - hide = "always"; - shell = "system"; - show_summary = true; - show_command = true; - } - ]; }; } diff --git a/secrets.nix b/secrets.nix index 8f38151..3b3ede4 100644 --- a/secrets.nix +++ b/secrets.nix @@ -6,58 +6,25 @@ let "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIxTfeg+GZsfmG8TuEV1xW1gXknAIKzZ3UjZ3guRY+EW root@nixos"; bosephus-millironx = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKaDPqRJHoqgY2pseh/mnhjaGWXprHk2s5I52LhHpHcF millironx@bosephus"; - corianne-host = - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHKKkucebeb1GcerOZAAs5GQsgTS8kXw5W41b9Fy9+hp root@corianne.local"; + odyssey-millironx = + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN9Aj7BtQp1Roa0tgopDrUo7g2am5WJ43lO1d1fDUz45 millironx@odyssey"; corianne-millironx = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOgL2lO9RJBdQYANoxGyWXcNKi5/NZkRHHo/rNqaYMc/ millironx@corianne"; - mcentire-host = - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINT51tQgsKzTIQc9WSQj01h/gPRvAD3k9jRhXppY7xmd root@nixos"; - mcentire-millironx = - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOdC6eNx2nBi3PWK/n4GJMbVf+NlQJv13aUqxse/h1kL millironx@mcentire"; - odyssey-millironx = - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKM5Q2zl3b91j+foqcVeQT+wb5DFEp+MbgotTTaKqZZi millironx@odyssey"; + harmony-millironx = + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFBYxsCkw+ObDzIvU8z/rSlYcQx0JIt1bCVxKcDxeNNZ millironx@harmony"; + system-administrators = [ anderson-millironx bosephus-millironx - corianne-millironx - mcentire-millironx odyssey-millironx + corianne-millironx + harmony-millironx ]; in { - "secrets/ansible-vault-password.age".publicKeys = system-administrators; - "secrets/authentik.toml.age".publicKeys = system-administrators - ++ [ mcentire-host ]; - "secrets/borgmatic-passphrase.age".publicKeys = system-administrators - ++ [ mcentire-host ]; - "secrets/borgmatic-ssh-config.age".publicKeys = system-administrators - ++ [ mcentire-host ]; - "secrets/darwin-policies-json.age".publicKeys = system-administrators - ++ [ corianne-host ]; - "secrets/fireflyiii.toml.age".publicKeys = system-administrators - ++ [ mcentire-host ]; - "secrets/freshrss.toml.age".publicKeys = system-administrators - ++ [ mcentire-host ]; - "secrets/immich.toml.age".publicKeys = system-administrators - ++ [ mcentire-host ]; - "secrets/millironx-books-s3.age".publicKeys = system-administrators - ++ [ mcentire-host ]; - "secrets/millironx-music-s3.age".publicKeys = system-administrators - ++ [ mcentire-host ]; - "secrets/millironx-photos-s3.age".publicKeys = system-administrators - ++ [ mcentire-host ]; - "secrets/navidrome.toml.age".publicKeys = system-administrators - ++ [ mcentire-host ]; "secrets/network-information.age".publicKeys = system-administrators ++ [ bosephus-host ]; - "secrets/peertube.toml.age".publicKeys = system-administrators - ++ [ mcentire-host ]; - "secrets/redis-immich-password.age".publicKeys = system-administrators - ++ [ mcentire-host ]; - "secrets/redis-password.age".publicKeys = system-administrators - ++ [ mcentire-host ]; - "secrets/redis-peertube-password.age".publicKeys = system-administrators - ++ [ mcentire-host ]; - "secrets/vaultwarden.toml.age".publicKeys = system-administrators - ++ [ mcentire-host ]; + "secrets/pihole.age".publicKeys = system-administrators ++ [ bosephus-host ]; + "secrets/ansible-vault-password.age".publicKeys = system-administrators; + "secrets/darwin-policies-json.age".publicKeys = system-administrators; } diff --git a/secrets/ansible-vault-password.age b/secrets/ansible-vault-password.age index 6c1379f..99a96bc 100644 --- a/secrets/ansible-vault-password.age +++ b/secrets/ansible-vault-password.age @@ -1,13 +1,13 @@ age-encryption.org/v1 --> ssh-ed25519 il3lzQ SoqTRahd/xUVe/pDmQI3jT5X0lTxOwhy8hct20fwil4 -UuYpQa5GpDALKQEMbSLnH2rp3kgPL+4zJZbJirkB5Q0 --> ssh-ed25519 1g/xww gYtrdwJlp1pxcZ7l+RvawRScFOh/ami3yJobbKPyLiM -oQ8dwIUIakV8WVvuknn87BYcmEBBT+UI3BxImd71/jE --> ssh-ed25519 dbKeHw KVdpRmBWRYd5NC3UK3e8Em3XefnVxxc9KfXzbksvTC0 -fwyK7ORnCadX8Czs0WKW3ZDa1jeu7Wjba7Vm9nKqCBs --> ssh-ed25519 3qPtug nEHt7lMjUrcehOGjtznFd+u60OdfG1dPJr/+aFP4OXY -DRtfbYQZJhMIfj1yHgpTdSU15z0Ld5/2wl0ATPN0W6w --> ssh-ed25519 FRQvIA a4zYtpYFVGSum3wD850lM/wEcokckt4mlDRsrb6QrHY -QF75fGiiKZc1oHSOdy+QvPnQ1hhaLRebaE7i0keZxHw ---- 8Y5Q9SlGWEzp9jeVcoHFrv3PR+eDyhOPFXIFRxZ1Koo -‘ÜJá¿ÞóóDlv\é÷÷lÅu$­0 ëë±{ˆÏri·œP7Ï¥PÚ锓…Äkr(ÇP¡ÅHWË]r ÌÆÙ‘r¸ \ No newline at end of file +-> ssh-ed25519 il3lzQ Ni2CHjeijXHfF62cUqVTm8MAOn6rRg8UrhqN6xvdkyk +DsT0Ysx88FlCLeRzoOGctX7KqatX9/UCr5WdtdLJAf4 +-> ssh-ed25519 1g/xww jRn91F29sISMyi41anAlzVCzt1t1DnUqxtryqkTQPlM +cysgZLQR0YhiJYXBl59DjKbm+N8FnjA46wkQtnAzBFA +-> ssh-ed25519 +kBihw t6wlSnDKGgSzGhNJnryXVbDR40DATaV3fHovtI/u7zo +zOyCZtzfLKeer9K6SMpfTxn6El4HB7gQFQqLOxIYB5U +-> ssh-ed25519 dbKeHw cn+8WTwis58bYm2pfEra6LeLvzEZ8GhZrOEeN+kkhCM +fnlUAj8JtG8+r7Cj8xYUgF+JM6Pwqawn4sGI1LOeN78 +-> ssh-ed25519 Svnssw zmDBR8TdRZ9NzNhwPYRN6c8naTxAkULyUZpKgk7Gshk +0XCwpegEIlGXhnzLLUtmciKQiYiZRgnSOSvCcYeXXk8 +--- D/lZ36n5sVste2NWfdOx8/klPh0CTmMjVQN74KIqDRY +]%“¾ÇC}ˆNí›êOÈÓ"vÎÈ#ò˱ªç×¢t­¤Ü_Q;^*!»+<+±àÈdB×/KÒýÉ` \ No newline at end of file diff --git a/secrets/authentik.toml.age b/secrets/authentik.toml.age deleted file mode 100644 index e3b6a25..0000000 Binary files a/secrets/authentik.toml.age and /dev/null differ diff --git a/secrets/borgmatic-passphrase.age b/secrets/borgmatic-passphrase.age deleted file mode 100644 index c3969d2..0000000 Binary files a/secrets/borgmatic-passphrase.age and /dev/null differ diff --git a/secrets/borgmatic-ssh-config.age b/secrets/borgmatic-ssh-config.age deleted file mode 100644 index 63dd59f..0000000 --- a/secrets/borgmatic-ssh-config.age +++ /dev/null @@ -1,16 +0,0 @@ -age-encryption.org/v1 --> ssh-ed25519 il3lzQ 6815+wa1JjdVUu8U8vaRah8kVsjR3Fsot99HKWl4SSA -hPYVZuN1yTKQYFIQvIRdmr400aijXleA22Bxh1nXKdc --> ssh-ed25519 1g/xww BPxSszlrjPTVJC+YOvo1N6ICUUdL7WKZX3DeambLjBY -JkJQFPGtxDtqeGj8Z1YtVq/pm6hgYKwzMW9MbtkvOwY --> ssh-ed25519 dbKeHw PU5cZrKCkAvUjI/opkboDQKSWJ8osAOQiI62f9lbfRY -ef1z6ZcBASkhC4fdcN+RRE7q28rB/DN8CVdoNVkC81I --> ssh-ed25519 3qPtug RWCMZiLQlS+bOOIBRGmoECOfqEI2uoaWCq/4ZuI86B4 -VOaLaH1VYnGoQzjb8seU6wVviB94W3qCdYW9Wf4PGIc --> ssh-ed25519 FRQvIA LCDwNMNVtTcI3GHPR2mcgtR16yAYYwLplI2nKUwNxDQ -vwXBIDlK7FBOsKt48Zv8mp0WFA/TKH2UJxtUxZoxzMI --> ssh-ed25519 +C0WRg a/R13LfNMjVjJxt2TtTHaqZOhsYJLY+HUGMHEDnkZWo -T2EfeE/a4W4bFvauynfh+4aJL1jhCpO8iBG2aTmKtyM ---- o7tyupfhbxh3dwSrBLsYX0V61va0USlqxheNsdBjVuQ -A ¤q,:_™aɪ”)Àžj›“¹1ß2 #¼¾–²t,G®£*« -X¿TÛ³(óŽòœ‹Uß5øtúñ6‡‹¡ÕB“’çš©èã8à0Í Ú*Ïâìèi׆Ðì^ÇÓߨ@ÔaóB@̃Ž+oF¯…ü÷w‰÷²¼åPciˆ2Ü7Y¨SXd²“ ÚØg±É̲ñJ \ No newline at end of file diff --git a/secrets/darwin-policies-json.age b/secrets/darwin-policies-json.age index 3f900dd..9fa2d2b 100644 Binary files a/secrets/darwin-policies-json.age and b/secrets/darwin-policies-json.age differ diff --git a/secrets/fireflyiii.toml.age b/secrets/fireflyiii.toml.age deleted file mode 100644 index 8d57f14..0000000 Binary files a/secrets/fireflyiii.toml.age and /dev/null differ diff --git a/secrets/freshrss.toml.age b/secrets/freshrss.toml.age deleted file mode 100644 index 096f601..0000000 Binary files a/secrets/freshrss.toml.age and /dev/null differ diff --git a/secrets/immich.toml.age b/secrets/immich.toml.age deleted file mode 100644 index dcdfc50..0000000 Binary files a/secrets/immich.toml.age and /dev/null differ diff --git a/secrets/millironx-books-s3.age b/secrets/millironx-books-s3.age deleted file mode 100644 index 2f57e3a..0000000 Binary files a/secrets/millironx-books-s3.age and /dev/null differ diff --git a/secrets/millironx-music-s3.age b/secrets/millironx-music-s3.age deleted file mode 100644 index 14e9b64..0000000 Binary files a/secrets/millironx-music-s3.age and /dev/null differ diff --git a/secrets/millironx-photos-s3.age b/secrets/millironx-photos-s3.age deleted file mode 100644 index 2158f18..0000000 Binary files a/secrets/millironx-photos-s3.age and /dev/null differ diff --git a/secrets/navidrome.toml.age b/secrets/navidrome.toml.age deleted file mode 100644 index 95d0fc8..0000000 Binary files a/secrets/navidrome.toml.age and /dev/null differ diff --git a/secrets/network-information.age b/secrets/network-information.age index 2d42ae1..0de69b7 100644 Binary files a/secrets/network-information.age and b/secrets/network-information.age differ diff --git a/secrets/peertube.toml.age b/secrets/peertube.toml.age deleted file mode 100644 index 3441ff0..0000000 Binary files a/secrets/peertube.toml.age and /dev/null differ diff --git a/secrets/pihole.age b/secrets/pihole.age new file mode 100644 index 0000000..babead9 --- /dev/null +++ b/secrets/pihole.age @@ -0,0 +1,15 @@ +age-encryption.org/v1 +-> ssh-ed25519 il3lzQ Q+/uqZhUWs5pb5T1ocD+/qTSo4DJbd/W1exruQ34zAE +8HFRvEblGVrkoVaqAl/Af6wrDn6A+3unZIMBipEkwgA +-> ssh-ed25519 1g/xww PqXxTvLaF6ZlcVov81VrVH130jFh2iGmHPRtBYV4ME4 +1VBknQzaNZyoz2wvgKX+IZGaOEnJ1xGvxPYxq10ar/U +-> ssh-ed25519 +kBihw QXNxY9OQeIM98OqmHoa/S2kMZqSX+ndgxGyCJpHJ+gg +b3DmfUswyPQ09sp57v3QMNEF/Ka3w9Qj2s1kGUSinmQ +-> ssh-ed25519 dbKeHw 5GzjKgjUX5e6Net7voWBykC17zRcdSFDFbDsSwp5FAU +GwTEg3YR9HdcQHPg+XjP2Lg1BpcWA4VunbZSBdxVaYU +-> ssh-ed25519 Svnssw imRjD5CJu/jOac3t/APHbYBnsyJVQdebR6K52A6GdwM +n+Q9kEEkYRBuEzWlSwbjJNsjF8uKloeUEWYxHa29B4U +-> ssh-ed25519 jb0ALQ 4qbGIofHcyhJVfL24peGqqzg0tFdxbWBHJFenwehIAI +Ta3ye4quyHvvE+2CGZwYvQMwWfdrLIdqADLvJYhllPY +--- 3hbht7PYqFafVmcQWQwv3q2gUXM8HXajtmAaMnrh59s + +óX9ð¾84R2ƒª,òôˆ±¨(#42ì#*, bùôŒç¦½Hã_z…œ…¨Í }ß… ®ë›xñ‚7Aœ!)ê)vÊž¨¨•W-÷¿eX-G‡<´¸@~â¢èEÜk¬?kG‘lQK¬4c&*JöÂå9V_Ä0Õö µzÓ+ɰ¯CÞ ÑžÀQ°ò«ÃGô§XÁ˜k¡g*£æð -Àjƒö¼‚l½ú3¿‰1ÏJš´üM·OE†[=S \ No newline at end of file diff --git a/secrets/redis-immich-password.age b/secrets/redis-immich-password.age deleted file mode 100644 index a92e560..0000000 --- a/secrets/redis-immich-password.age +++ /dev/null @@ -1,16 +0,0 @@ -age-encryption.org/v1 --> ssh-ed25519 il3lzQ Lqt1JIJtjTwggbhuJj/vG65IbDyr4EK5pOOKtVqdN3s -OBvcpByhzHT+0fmvLpgOCQaTbudVEdNmNDCJCf+9Tzs --> ssh-ed25519 1g/xww b1Gu6eFxAJwd+8P38D8HoEzApocQDwRpi7GF4tQH+zE -Js9XmUUcV4gGHvE37j6I3J1vYf7gkxOLbfPC2al0EsU --> ssh-ed25519 dbKeHw nNL9fDDfudbcHOshRKuxtcaZzPNbTEY2z4jAQMNYQTE -Xrz8nKSxzaEnAYeZTust6eZNhILs4dOutAaIfZ4wcGM --> ssh-ed25519 3qPtug JUTgaW4s68Gtr/kl+L4FLRldW97kk6vaALLSN3IgY24 -cyTIvPurE28TsE8Axl4x05OVcgEX7qA9X00B6u22/LI --> ssh-ed25519 FRQvIA CYliqiKWpSXwHWteHCyPxDjaVgx3tYH3+OXYtH+HAEM -iSmpVhv01x+g/bN0TpbeN5210YsuAKTWdEJy34lulw4 --> ssh-ed25519 +C0WRg 5O+LJgQPccaXNPvB/eRANbmq+4A5wNTGSwC6cCAecw4 -EkLahciiQbR8MmgJptjPVi2R/lMbXkZJYIFvOk4v5Vk ---- EcIUdYgRgZ1xHmTX+O1ULpDJKloyFquwZqFLHj1Lf4E -ô,y-]Ð@Ã5 -ôHÄÌíÎÚ€>á\ØÄ= O=,%õö»ZöÙ)q6É3©1ÔV¡l]µâ8wVè†s \ No newline at end of file diff --git a/secrets/redis-password.age b/secrets/redis-password.age deleted file mode 100644 index 6731da7..0000000 --- a/secrets/redis-password.age +++ /dev/null @@ -1,15 +0,0 @@ -age-encryption.org/v1 --> ssh-ed25519 il3lzQ 9+/0+lCYWH9ibqY7J0OWz4fyTJYNvjwVEQQgByg8eXo -DmqfjZYNCggmNwez+H0lNUmTuBUmlfOy9BMdo/mP1Ro --> ssh-ed25519 1g/xww 3v7NGaDyYM/Na5DTgbpv7DtVg6mqsgqd0xU7NmcDlTk -7Z8yymlYYx3fO8CNMcosa6hLAZ7rlkDA6qPat2IWsS0 --> ssh-ed25519 dbKeHw WlHTnJR3TyAuYm5NG+8WMXmeB3YUydDJ61SrWKMcByg -k5dwVAuUKNjFeCY7/L28Kx0ZHBiPUxndEQp1UyOPxIY --> ssh-ed25519 3qPtug YU9PSuEkJElN4EOFQTrXBrRB/3g/MzSbLEU5mWIl6CA -HBFN2uTQo0tr8cnJ2okFibZXVouaCy6WCq0+YK2jSYI --> ssh-ed25519 FRQvIA ufWjt9KuGr9Wx0kRbMK3WapeyOM9dnuy8nRpa9LcElY -WGB7xIuZOEGNlycHAlg3sE1W766/rMZGIb17VL54uYs --> ssh-ed25519 +C0WRg 9jXj4AKdCK5RdQOOmDFu9/RapWvQQ6MieaHO7m/wKSc -vkdJWxmBtjmLQXq1tvM+sAXAOKbJmTdM7klyiW1xW2g ---- lEbO55yAuhIUejggLmlQ9UAZdw8DQVC+2EZ6Qs0Vn9Y -8ÿ¸È/ÚW"F™ÓJ[DÉ<(O²9ª;‘lj³ô¯špM^À“Ò·•/Iù|9*…Øòx@ɪ±›˜¦Á›Ea¦:™Ký¥*íÌ~ \ No newline at end of file diff --git a/secrets/redis-peertube-password.age b/secrets/redis-peertube-password.age deleted file mode 100644 index 1ee6754..0000000 --- a/secrets/redis-peertube-password.age +++ /dev/null @@ -1,15 +0,0 @@ -age-encryption.org/v1 --> ssh-ed25519 il3lzQ BiSY+7dxt1jVDqysxYAqAGAXQ0SurqZXGgGqvwaQEXM -gzdbiaAo0nzVOIFEjAoKXSHfs+JQAbJWDJyrO4tt6gA --> ssh-ed25519 1g/xww 3MK5439qn8MkP5HrLLkY6a+IRGrjVIIe/OhaZ20THU0 -dKe0EkynB0G1zAZZ+VA/Of1x4Q6j+R4al7ohb6V6YWM --> ssh-ed25519 dbKeHw GfX7az0oBf1Nh6YQFqZuDrCZyK1Mm6w+SGAhQSGeJww -kgLWmzfZjBnds1fjAVme6M7fKD4NrJZ3X6vJU7055ac --> ssh-ed25519 3qPtug zUXACZya4MCbMyPLR59VN4GRQSOokgORvDhL/ByWbHM -dSfQVAGj8u+7L7GX53dWbs5rHo9H5TaVRwEFZUq3lJ8 --> ssh-ed25519 FRQvIA z2qGPHCG5wGlmmngy2d4L8kHz7pO/F4YPAWwsNjWQEI -HIVGXAxOfD7O8yP2piOfMLTM9EzWkHslCRFIf+XrXXY --> ssh-ed25519 +C0WRg BhTldebU1YLAxlQ5dYG/RuExT9czS//LUXwKg+Q7tT8 -mEiv5g1PWgdwZHrlqrv5wEVWvubsppUpryEwtdSNDXM ---- 2+fbTKQ8yZPOKxLvYhFO2laMF/gq2cWs7byzYOcuohM -™hçž ÕD VšÛ/0ØÀõ;î» îO§Ísý7ŽwrVáze¹½üÅÓ”WgŠ­•°Ë‡ëüvl}í \ No newline at end of file diff --git a/secrets/vaultwarden.toml.age b/secrets/vaultwarden.toml.age deleted file mode 100644 index 40b2803..0000000 --- a/secrets/vaultwarden.toml.age +++ /dev/null @@ -1,17 +0,0 @@ -age-encryption.org/v1 --> ssh-ed25519 il3lzQ 8JViVLQl/Y6buE2yIo/k9QhictchYRpvx3U+TtV88RY -bWMzX1yYCP11aGg85fCMEf3o00Ej6VeLrFW2fHyv9zo --> ssh-ed25519 1g/xww eDRfglbO+tyPhpXhl8RwI1f5CCocjtwpT5QqmpYab1I -s45uOqmgA1TnCthPASC5cA2pEBzriCt69noN3aHZTvg --> ssh-ed25519 dbKeHw PPnqWUiu/mwpTxRkXvNwELP2F4cETQdVgXL/SgyTMAE -mYQ1s393jTPVE5euXnq+a5Hs+nGG1VC3iaOb/6Mg6sQ --> ssh-ed25519 3qPtug z3Ho5K7RQD8mbFRq+rSC7mRDs5M/Kkb/O7z/ssdFLgg -6qmYTtOz7l9nRl8yEReS2iI52H+bYxjMJfCFwYWOqn8 --> ssh-ed25519 FRQvIA HZxjrRSKr+ofIai2x2tskTaBIrRfI+uJYISU0Wj0B1Y -tKbposXaqYHF6H7dvoG1iYGT8FOIkX8EF0viCHUvjdQ --> ssh-ed25519 +C0WRg 9GCzNbR9ZbTypzrkXWVBAC3LiIwl8ypxpG+DcWy1QU4 -BlQrkO8GchHE5e275o4Hk5fmTv2RIUtW71tOS+sCsZA ---- Fh46aD+7L1fe5O2BxitKMtJV+QgdbXhJ4O3a+0IhjP4 -"nmQ'*°y¸ç·Ë}TÅ¿]u‘k ^@Yʪqjñ×ß8H#$Jþ¤NÕŒ…·OSЛÄ4½Lš@'%C<ÞŒ\ømƒ‰¨ -ªjI3ä‰0^"e'èû…:Ó;Ã6! våe‹â–œÈ ~˜hã@@†¥¿4ÈåêÒƒaçæõËìMÔ Mçœ(œ0÷œ¶yðq³î3˜\žØ£ô¨¾Ž Ì2ÒÆ¿ºÎ¾0_¢ð€]ÌÛ¸]nbR?ˆ@ƒD½?™RaEç©Ìòz-ŸÇÓimîÍq^SYå»)“Síðwqf=acKB¤Ng‹9¿®)‘Q9ØNÓ ×aäëk Hi+ŸúÕ~4&{l5Þ 9Çùb̀¬3(žß(¼‘òy0 ¯,çÿV-»E:Ó}Ê¡È,´IBP ì¦&”jÕl¶C}ð˜àYy•QRûäPäÞ©Ñ„,uC§µ ž}‰UP½”.Mø-DïÀÑÀÒÈóLúùÆÖLywbÚ È2k$˜Å.Ë,c#ÎÇæÀ“±\ÅïbAfp*€K¸`-T6ØN³-ºhdŸoþ¡Î\1EÜãäd:¾«.‰á“?`³¿jt->ó17ïÍ:÷ˆa]aŽˆ6V8:íô~[×›QùfõHÏ€{_ æ§Ú.Ž=ü_¬gÄm<îŒÏ³%«Ž‹'ÝS;{ ch›!Ið'äB)ÈóãÅ\®sÀacȲ â‚Ê:{Í2ÐH.+5Ã$†0÷”xO¦ÈëîÃ>ͲfÒ«~¼±JF HÂ3=*/~ý,§™nJ%È'¼ÛË45†–G™ÒõO]ÿ94)y -Å´‚.8$õ(–h«•³¥9–ú”¦ìÿÞûšRMyÆ‘•#âX©‹0ÇŠ]“ÿûÜD±Èl²(¾–ì1ˆM_Ëâ+!8ÛuŠtW‡ÊÚ=­O«ÏÇWôÙí¹Ùð2*›¿cåÜ4Â\tSÆTÉ–_´žJÎP¤³”ú¯1VçLÿdŒ`“0ÊgF¶Êƒ÷‹‚&ÙYtÒ\kgþëE1BQ —D·–逃DõGMO¾4û!JtC6>óÙd[êá1ú7<䙋’˜.I¨ô8Þnood¼¹ÍYâ ù}΢eBR» ¯Ç2A°$^ÄOœˆÇ•bÎ>cˆ 3-%â­”z|€¹è;ar <§S.=„nÆ; \ No newline at end of file diff --git a/secrets_file.enc b/secrets_file.enc index 33fcb27..20df784 100644 --- a/secrets_file.enc +++ b/secrets_file.enc @@ -1,8 +1,10 @@ $ANSIBLE_VAULT;1.1;AES256 -33613635643765623937663135313833396162343134383466343966333964386364356134663264 -3137633339396462633431316634623834646437646162360a626564313831373761636161656232 -35316566336232666336646231356665366633303530623961666465366163306166623336656364 -3835353035333031620a633332376237336530343134623832363534383761616564616138363766 -30306361383462353361636161636335313461313835663362393839623735313738316465656537 -66396635323432376530346532353238346139376261366237343763373535623364633731323830 -333730373965613131336166626230333263 +65366137313461383534313965646333656565353061336361363661613033393264353661346337 +3838653162383134393463323631613439373663396363380a633339396236363962313333343465 +31623961393532666136616438633734366261353866383264323730383432326635626637343739 +3235313062623637380a386235316437396534353261383832643165316565386263396664363962 +62393364333335373631356161373263313930343565626433383539373030363662353630633933 +63336333613965653635313637336437653139616564313861336332323739653865383531356233 +31373530343766343131346663656566363038643230343462336332323135323337353539303763 +33366638393064323431323636346161343936643062323861313766613264336465326132333631 +33306666383561653965303539313366653030663330393363363565333439383133 diff --git a/secrets_harmony.enc b/secrets_harmony.enc new file mode 100644 index 0000000..e91177d --- /dev/null +++ b/secrets_harmony.enc @@ -0,0 +1,6 @@ +$ANSIBLE_VAULT;1.1;AES256 +38383539613238613864336630316433666436623334313334393762396536663530336264306661 +3338616565316138616666343862366638643134343931320a633366363539326461346636373738 +66393138653463663536313065623332383166386332303564323939336630333163623637386434 +6538393966633731660a616437356233643234363562366433663437383439326161353330356331 +63346432663036353332303266343361346266396437396131376531303265356233 diff --git a/secrets_odyssey.enc b/secrets_odyssey.enc index a7a96da..fba7129 100644 --- a/secrets_odyssey.enc +++ b/secrets_odyssey.enc @@ -1,9 +1,6 @@ $ANSIBLE_VAULT;1.1;AES256 -61363033383536303833366237323662663236313163663033306138383162383062643830616466 -6531636430613462646161343939343363663533373737340a613433363666353432383463356439 -33656266633131336565613433653062656563656637656464346232656238646339303961373265 -6639643637303433380a393163366331373964353261383662656664643031626432366231346332 -34303964346137616233343930333331306363326332383465653163386539306430303965316437 -30343333373565623431653436653832356366343937653136346535316166383262623730343831 -62376532346237323465653261316339353034323633623632313630666531373839633665333637 -34356162356565396564 +30343638643335363463653231623566623961613534323261393639623865633964653634333562 +3838613035393661656362383736313561366466396439390a383162366362643364636335613664 +39646137666437353762363764373562393736626530333336626261366232383063633732623238 +6531633638366335640a363461383535646663316533386137323966326237373836363561323462 +66646635383137333834363165666365366235333734646364616637383363666239 diff --git a/services/audiobookshelf.nix b/services/audiobookshelf.nix deleted file mode 100644 index c81b0dd..0000000 --- a/services/audiobookshelf.nix +++ /dev/null @@ -1,81 +0,0 @@ -{ config, pkgs, home-manager-quadlet-nix, ... }: -let - user = "audiobookshelf"; - port = "28346"; - stateDirectory = "/var/lib/${user}"; -in { - age.secrets = { - millironx-books-s3-token.file = ./../secrets/millironx-books-s3.age; - }; - - environment.systemPackages = [ pkgs.s3fs ]; - - fileSystems."millironx-books" = { - device = "millironx-books"; - mountPoint = "/mount/s3/millironx-books"; - fsType = "fuse./run/current-system/sw/bin/s3fs"; - noCheck = true; - options = [ - "_netdev" - "allow_other" - "use_path_request_style" - "url=https://us-east-1.linodeobjects.com/" - "passwd_file=${config.age.secrets.millironx-books-s3-token.path}" - "uid=${user}" - "gid=${user}" - "umask=0022" - ]; - }; - - systemd.tmpfiles.rules = - map (d: "d ${stateDirectory}/${d} 1775 ${user} ${user} -") [ - "" - "config" - "metadata" - ]; - - services.borgmatic.configurations."${config.networking.hostName}" = { - source_directories = - map (d: "${stateDirectory}/${d}") [ "config" "metadata" ]; - }; - - services.caddy.virtualHosts."books.millironx.com".extraConfig = '' - reverse_proxy http://127.0.0.1:${port} - ''; - - users.users."${user}" = { - group = "${user}"; - isNormalUser = true; - home = stateDirectory; - createHome = true; - linger = true; - autoSubUidGidRange = true; - }; - users.groups."${user}" = { }; - - home-manager.users."${user}" = { config, osConfig, ... }: { - imports = [ home-manager-quadlet-nix ]; - - home.stateVersion = "25.05"; - - virtualisation.quadlet = { - autoUpdate.enable = true; - containers.audiobookshelf = { - autoStart = true; - containerConfig = { - image = "ghcr.io/advplyr/audiobookshelf:latest"; - environments = { TZ = "America/New_York"; }; - volumes = [ - "/mount/s3/millironx-books/audiobooks:/audiobooks:U" - "/mount/s3/millironx-books/podcasts:/podcasts:U" - "${stateDirectory}/config:/config:U" - "${stateDirectory}/metadata:/metadata:U" - ]; - publishPorts = [ "127.0.0.1:${port}:80" ]; - addHosts = [ "auth.millironx.com:host-gateway" ]; - }; - }; - }; - }; - -} diff --git a/services/authentik.nix b/services/authentik.nix deleted file mode 100644 index 0349b87..0000000 --- a/services/authentik.nix +++ /dev/null @@ -1,233 +0,0 @@ -{ config, pkgs, home-manager-quadlet-nix, ... }: -let - user = "authentik"; - state-directory = "/var/lib/authentik"; - port = "9000"; - -in { - # Secrets are translated in the system NixOS scope, but performed by the user, - # via a user systemd unit, so are available in the user's Podman secrets - age.secrets = { - "authentik.toml" = { - file = ./../secrets/authentik.toml.age; - owner = "${user}"; - }; - }; - - millironx.podman-secrets.authentik = { - user = "${user}"; - secrets-files = [ config.age.secrets."authentik.toml".path ]; - }; - - # Podman, unlike Docker apparently, does not automatically create mount points - # within folders, so every mounted folder needs to be specified here. - systemd.tmpfiles.rules = [ - "d ${state-directory} 1775 ${user} ${user} -" - "d ${state-directory}/database 1775 ${user} ${user} -" - "d ${state-directory}/data 1775 ${user} ${user} -" - "d ${state-directory}/media 1775 ${user} ${user} -" - "d ${state-directory}/certs 1775 ${user} ${user} -" - "d ${state-directory}/custom-templates 1775 ${user} ${user} -" - ]; - - services.caddy.virtualHosts."auth.millironx.com".extraConfig = '' - reverse_proxy http://127.0.0.1:${port} - ''; - - services.borgmatic.configurations."${config.networking.hostName}" = { - source_directories = [ - "${state-directory}/data" - "${state-directory}/media" - "${state-directory}/certs" - "${state-directory}/custom-templates" - ]; - - postgresql_databases = [{ - name = "authentik"; - psql_command = - "/run/wrappers/bin/sudo -iu ${user} ${pkgs.podman}/bin/podman exec authentik-db psql --username=${user}"; - pg_dump_command = - "/run/wrappers/bin/sudo -iu ${user} ${pkgs.podman}/bin/podman exec authentik-db pg_dump --username=${user}"; - pg_restore_command = - "/run/wrappers/bin/sudo -iu ${user} ${pkgs.podman}/bin/podman exec authentik-db pg_restore --username=${user}"; - }]; - }; - - # Create a dedicated user for this service - users.users."${user}" = { - # Group is technically not mandatory, but NixOS complains that an unset - # group is "unsafe." The group has to be declared below - group = "${user}"; - - # System users don't have a shell. For security purposes, that *would* be - # superior, but that means that, e.g. borgmatic can't `sudo` into the - # account to access Podman commands - isNormalUser = true; - - # A home directory is mandatory in order to allow systemd user units to be - # created and run - home = "${state-directory}"; - createHome = true; - - # Settings for running containers while a login shell is not active - linger = true; - autoSubUidGidRange = true; - }; - users.groups."${user}" = { }; - - services.crowdsec = { - localConfig.acquisitions = [{ - source = "journalctl"; - journalctl_filter = [ "_SYSTEMD_USER_UNIT=${user}.service" ]; - labels.type = "authentik"; - }]; - hub.collections = [ "firix/authentik" ]; - }; - - home-manager.users."${user}" = { config, osConfig, ... }: { - imports = [ home-manager-quadlet-nix ]; - - home.stateVersion = "25.05"; - - virtualisation.quadlet = { - containers = { - authentik-db = { - autoStart = true; - containerConfig = { - image = "docker.io/library/postgres:16"; - environments = { - POSTGRES_DB = "${user}"; - POSTGRES_USER = "${user}"; - }; - secrets = [ - # POSTGRES_PASSWORD is used by the container to setup the - # database, PGPASSWORD is used by pg_dump to authenticate for - # backup purposes - "AUTHENTIK_POSTGRESQL__PASSWORD,type=env,target=POSTGRES_PASSWORD" - "AUTHENTIK_POSTGRESQL__PASSWORD,type=env,target=PGPASSWORD" - ]; - - # Double dollarsigns are required for use of *container* environment - # variables, Nix escaping creates the weird $\${} syntax - healthCmd = "pg_isready -d $\${POSTGRES_DB} -U $\${POSTGRES_USER}"; - healthInterval = "30s"; - healthRetries = 5; - healthStartPeriod = "20s"; - - # Volumes have to be bound with the :U label to allow for username - # remapping in rootless containers. :Z/:z is not needed b/c NixOS - # does not support SELinux - volumes = - [ "${state-directory}/database:/var/lib/postgresql/data:U" ]; - - # A network is actually required for these containers to talk to one - # another. I suppose the more idiomatic way would be for these - # related containers to be in a "pod," but I'm still struggling - # learning the idiosyncrasies of quadlet/rootless/podman, so we'll - # stick with this for now - networks = - [ config.virtualisation.quadlet.networks.authentik-net.ref ]; - - }; - - # Allowing this container to start before the secrets are translated - # will lead to errors. Use osConfig b/c secrets are declared in the - # system NixOS scope, even though it is a user process. - unitConfig.Requires = - [ osConfig.millironx.podman-secrets.authentik.ref ]; - unitConfig.After = - [ osConfig.millironx.podman-secrets.authentik.ref ]; - }; - - authentik-worker = { - autoStart = true; - containerConfig = { - image = "ghcr.io/goauthentik/server:2026.2"; - environments = { - AUTHENTIK_POSTGRESQL__HOST = "authentik-db"; - AUTHENTIK_POSTGRESQL__NAME = "${user}"; - AUTHENTIK_POSTGRESQL__USER = "${user}"; - AUTHENTIK_STORAGE__BACKEND = "s3"; - }; - exec = "worker"; - secrets = [ - "AUTHENTIK_POSTGRESQL__PASSWORD,type=env" - "AUTHENTIK_SECRET_KEY,type=env" - "AUTHENTIK_STORAGE__S3__ACCESS_KEY,type=env" - "AUTHENTIK_STORAGE__S3__SECRET_KEY,type=env" - "AUTHENTIK_STORAGE__S3__BUCKET_NAME,type=env" - "AUTHENTIK_STORAGE__S3__REGION,type=env" - "AUTHENTIK_STORAGE__S3__ENDPOINT,type=env" - "AUTHENTIK_STORAGE__S3__CUSTOM_DOMAIN,type=env" - ]; - volumes = [ - # Remount media folder into new location based on - # - "${state-directory}/data:/data:U" - "${state-directory}/media:/data/media:U" - "${state-directory}/custom-templates:/templates:U" - "${state-directory}/certs:/certs:U" - ]; - networks = - [ config.virtualisation.quadlet.networks.authentik-net.ref ]; - }; - unitConfig.Requires = - [ config.virtualisation.quadlet.containers.authentik-db.ref ]; - unitConfig.After = - [ config.virtualisation.quadlet.containers.authentik-db.ref ]; - }; - - authentik = { - autoStart = true; - containerConfig = { - image = "ghcr.io/goauthentik/server:2026.2"; - environments = { - AUTHENTIK_POSTGRESQL__HOST = "authentik-db"; - AUTHENTIK_POSTGRESQL__NAME = "${user}"; - AUTHENTIK_POSTGRESQL__USER = "${user}"; - AUTHENTIK_STORAGE__BACKEND = "s3"; - }; - exec = "server"; - secrets = [ - "AUTHENTIK_POSTGRESQL__PASSWORD,type=env" - "AUTHENTIK_SECRET_KEY,type=env" - "AUTHENTIK_EMAIL__HOST,type=env" - "AUTHENTIK_EMAIL__PORT,type=env" - "AUTHENTIK_EMAIL__USERNAME,type=env" - "AUTHENTIK_EMAIL__PASSWORD,type=env" - "AUTHENTIK_EMAIL__USE_SSL,type=env" - "AUTHENTIK_EMAIL__FROM,type=env" - "AUTHENTIK_STORAGE__S3__ACCESS_KEY,type=env" - "AUTHENTIK_STORAGE__S3__SECRET_KEY,type=env" - "AUTHENTIK_STORAGE__S3__BUCKET_NAME,type=env" - "AUTHENTIK_STORAGE__S3__REGION,type=env" - "AUTHENTIK_STORAGE__S3__ENDPOINT,type=env" - "AUTHENTIK_STORAGE__S3__CUSTOM_DOMAIN,type=env" - ]; - - # Change from Traefik: publish ports to localhost only via 127.0.0.1 - # and then reverse proxy to that port. Authentik does not appear to - # have a way to configure the port, so we will use the default of - # 9000 for non-secured traffic. - publishPorts = [ "127.0.0.1:${port}:${port}" ]; - volumes = [ - "${state-directory}/media:/media:U" - "${state-directory}/custom-templates:/templates:U" - ]; - networks = - [ config.virtualisation.quadlet.networks.authentik-net.ref ]; - }; - unitConfig.Requires = - [ config.virtualisation.quadlet.containers.authentik-db.ref ]; - unitConfig.After = - [ config.virtualisation.quadlet.containers.authentik-db.ref ]; - }; - }; - - networks.authentik-net = { }; - - # One of the main advantages of using Quadlet - autoUpdate.enable = true; - }; - }; -} diff --git a/services/borgmatic.nix b/services/borgmatic.nix deleted file mode 100644 index c028df2..0000000 --- a/services/borgmatic.nix +++ /dev/null @@ -1,35 +0,0 @@ -{ pkgs, config, ... }: { - - # We don't want to expose the location where borg backups are going, so we - # will setup an encrypted ssh config that references the host/username - # combo as simply 'borgserver' - age.secrets = { - borgmatic-ssh-config = { file = ./../secrets/borgmatic-ssh-config.age; }; - borgmatic-passphrase = { file = ./../secrets/borgmatic-passphrase.age; }; - }; - - services.borgmatic = { - enable = true; - - # This is the bare-bones way to get Borgmatic up and running. Other services - # are expected to declare their stateful directories by adding to - # `services.borgmatic.configurations."${config.networking.hostName}".source_directories` - # and to add their databases to - # `services.borgmatic.configurations."${config.networking.hostName}".[mariadb|postgresql|etc]_databases` - - configurations."${config.networking.hostName}" = { - source_directories = [ "/home" "/root" ]; - repositories = [{ - label = "${config.networking.hostName}-default"; - path = "ssh://borgserver/./repo"; - }]; - ssh_command = - "${pkgs.openssh}/bin/ssh -F ${config.age.secrets.borgmatic-ssh-config.path}"; - encryption_passcommand = - "${pkgs.coreutils}/bin/cat ${config.age.secrets.borgmatic-passphrase.path}"; - keep_daily = 7; - keep_weekly = 4; - keep_monthly = 6; - }; - }; -} diff --git a/services/caddy.nix b/services/caddy.nix deleted file mode 100644 index 2f80550..0000000 --- a/services/caddy.nix +++ /dev/null @@ -1,15 +0,0 @@ -{ config, ... }: { - services.caddy = { - enable = true; - logFormat = "level INFO"; - }; - - services.crowdsec = { - localConfig.acquisitions = [{ - filenames = [ "${config.services.caddy.logDir}/*.log" ]; - labels.type = "caddy"; - }]; - - hub.parsers = [ "crowdsecurity/caddy-logs" ]; - }; -} diff --git a/services/crowdsec.nix b/services/crowdsec.nix index 9f3f6d8..f7e2e5a 100644 --- a/services/crowdsec.nix +++ b/services/crowdsec.nix @@ -1,51 +1,90 @@ -{ pkgs, config, ... }: { +{ pkgs, config, ... }: +let + crowdsec-url = "127.0.0.1:2763"; + firewall-bouncer-name = "fw-bouncer"; + # Although this key can be reproduced by anyone who actually cares to, the + # Crowdsec API will not be exposed to the outside world, so keeping this key + # super secret really isn't that important to me. Still make it look random + # so that hungry botnets can't just slurp up the password in plaintext. + firewall-bouncer-key = builtins.hashString "sha256" + "${config.networking.hostName}-crowdsec-bouncer-salt"; + toMultiYAML = items: + pkgs.lib.concatMapStrings (item: + '' + + --- + '' + (pkgs.lib.generators.toYAML { } item) + "\n") items; +in { services = { crowdsec = { enable = true; - localConfig = { - acquisitions = [ - { - source = "journalctl"; - journalctl_filter = [ "_SYSTEMD_UNIT=sshd.service" ]; - labels.type = "syslog"; - } - { - filenames = [ "/var/log/auth.log" ]; - labels.type = "syslog"; - } - { - filenames = [ "/var/log/syslog" "/var/log/kern.log" ]; - labels.type = "syslog"; - } - ]; - }; - hub = { - collections = [ - "crowdsecurity/base-http-scenarios" - "crowdsecurity/http-cve" - "crowdsecurity/http-dos" - "crowdsecurity/iptables" - "crowdsecurity/linux" - "crowdsecurity/sshd" - "crowdsecurity/whitelist-good-actors" - ]; - }; settings = { - general = { api.server.enable = true; }; - # See https://github.com/NixOS/nixpkgs/issues/445342 - lapi.credentialsFile = "/var/lib/crowdsec/lapi-credentials.yaml"; + api.server = { listen_uri = crowdsec-url; }; + allowLocalJournalAccess = true; + crowdsec_service.acquisition_path = pkgs.writeText "acquisitions.yaml" + (toMultiYAML [ + { + source = "journalctl"; + journalctl_filter = [ "_SYSTEMD_UNIT=sshd.service" ]; + labels.type = "syslog"; + } + { + filenames = [ "/var/log/auth.log" ]; + labels.type = "syslog"; + } + { + filenames = [ "/var/log/syslog" "/var/log/kern.log" ]; + labels.type = "syslog"; + } + ]); }; - autoUpdateService = true; }; - crowdsec-firewall-bouncer = { enable = true; - registerBouncer.enable = true; + settings = { + api_url = firewall-bouncer-name; + api_key = firewall-bouncer-key; + }; }; }; - users.users."${config.services.crowdsec.user}".extraGroups = [ "adm" ]; + systemd.services.crowdsec.serviceConfig = { + ExecStartPre = let + bouncer-script = pkgs.writeScriptBin "register-bouncer" '' + #!${pkgs.runtimeShell} + set -eu + set -o pipefail - systemd.tmpfiles.rules = let cfg = config.services.crowdsec; - in [ "d /var/lib/crowdsec 0755 ${cfg.user} ${cfg.group}" ]; + if ! cscli bouncers list | grep -q "${firewall-bouncer-name}"; then + cscli bouncers add "${firewall-bouncer-name}" --key "${firewall-bouncer-key}" + fi + ''; + collection-check = collection: '' + + if ! cscli collections list | grep -q "${collection}"; then + cscli collections install "${collection}" + fi + + ''; + collections = [ + "crowdsecurity/base-http-scenarios" + "crowdsecurity/http-cve" + "crowdsecurity/http-dos" + "crowdsecurity/iptables" + "crowdsecurity/linux" + "crowdsecurity/sshd" + "crowdsecurity/whitelist-good-actors" + ]; + collection-script = pkgs.writeScriptBin "install-collections" '' + #!${pkgs.runtimeShell} + set -eu + set -o pipefail + + ${pkgs.lib.concatMapStrings collection-check collections} + ''; + in [ + "${bouncer-script}/bin/register-bouncer" + "${collection-script}/bin/install-collections" + ]; + }; } diff --git a/services/fireflyiii.nix b/services/fireflyiii.nix deleted file mode 100644 index c029444..0000000 --- a/services/fireflyiii.nix +++ /dev/null @@ -1,164 +0,0 @@ -{ config, pkgs, home-manager-quadlet-nix, ... }: -let - user = "fireflyiii"; - port = "34733"; - containerPort = "8080"; - authentikPort = "9000"; - stateDirectory = "/var/lib/${user}"; - servicePaths = [ "upload" ]; - databasePaths = [ "database" ]; -in { - age.secrets."fireflyiii.toml" = { - file = ./../secrets/fireflyiii.toml.age; - owner = user; - }; - - millironx.podman-secrets.fireflyiii = { - inherit user; - secrets-files = [ config.age.secrets."fireflyiii.toml".path ]; - }; - - systemd.tmpfiles.rules = - map (d: "d ${stateDirectory}/${d} 1775 ${user} ${user} -") - ([ "" ] ++ servicePaths ++ databasePaths); - - services.borgmatic.configurations."${config.networking.hostName}" = { - source_directories = map (d: "${stateDirectory}/${d}") servicePaths; - postgresql_databases = [{ - name = user; - psql_command = - "/run/wrappers/bin/sudo -iu ${user} ${pkgs.podman}/bin/podman exec ${user}-db psql --username=${user}"; - pg_dump_command = - "/run/wrappers/bin/sudo -iu ${user} ${pkgs.podman}/bin/podman exec ${user}-db pg_dump --username=${user}"; - pg_restore_command = - "/run/wrappers/bin/sudo -iu ${user} ${pkgs.podman}/bin/podman exec ${user}-db pg_restore --username=${user}"; - }]; - }; - - services.caddy.virtualHosts."money.millironx.com".extraConfig = '' - reverse_proxy /outpost.goauthentik.io/* http://127.0.0.1:${authentikPort} - @protected not path /oauth/* /api/* - forward_auth @protected http://127.0.0.1:${authentikPort} { - uri /outpost.goauthentik.io/auth/caddy - copy_headers X-Authentik-Username X-Authentik-Groups X-Authentik-Entitlements X-Authentik-Email X-Authentik-Name X-Authentik-Uid X-Authentik-Jwt X-Authentik-Meta-Jwks X-Authentik-Meta-Outpost X-Authentik-Meta-Provider X-Authentik-Meta-App X-Authentik-Meta-Version - } - reverse_proxy http://127.0.0.1:${port} - ''; - - users.users."${user}" = { - group = user; - isNormalUser = true; - home = stateDirectory; - createHome = true; - linger = true; - autoSubUidGidRange = true; - }; - users.groups."${user}" = { }; - - home-manager.users."${user}" = { config, osConfig, ... }: { - imports = [ home-manager-quadlet-nix ]; - - home.stateVersion = "25.05"; - - systemd.user = let inherit (config.virtualisation.quadlet) containers; - in { - services."${user}-cron" = { - Unit = { - Description = "Firefly III cron"; - Requires = [ containers."${user}".ref ]; - After = [ containers."${user}".ref ]; - }; - Service.ExecStart = - "${pkgs.podman}/bin/podman exec ${user} /usr/local/bin/php /var/www/html/artisan firefly-iii:cron"; - }; - timers."${user}-cron" = { - Unit.Description = "Firefly III cron"; - Timer.OnCalendar = "daily"; - }; - }; - - virtualisation.quadlet = let - inherit (config.virtualisation.quadlet) containers; - inherit (config.virtualisation.quadlet) networks; - secrets = osConfig.millironx.podman-secrets.fireflyiii; - in { - autoUpdate.enable = true; - autoEscape = true; - - networks."${user}" = { }; - - containers = { - "${user}-db" = { - autoStart = true; - containerConfig = { - image = "docker.io/library/postgres:16"; - environments = { - POSTGRES_DB = user; - POSTGRES_USER = user; - }; - secrets = [ - "POSTGRES_PASSWORD,type=env" - "POSTGRES_PASSWORD,type=env,target=PGPASSWORD" - ]; - healthCmd = "pg_isready -d $\${POSTGRES_DB} -U $\${POSTGRES_USER}"; - healthInterval = "30s"; - healthRetries = 5; - healthStartPeriod = "20s"; - volumes = - [ "${stateDirectory}/database:/var/lib/postgresql/data:U" ]; - networks = [ networks."${user}".ref ]; - }; - unitConfig.Requires = [ secrets.ref ]; - unitConfig.After = [ secrets.ref ]; - }; - - "${user}" = { - autoStart = true; - containerConfig = { - image = "docker.io/fireflyiii/core:version-6"; - environments = { - APP_ENV = "local"; - DEFAULT_LANGUAGE = "en_US"; - TZ = "America/New_York"; - TRUSTED_PROXIES = "*"; - DB_CONNECTION = "pgsql"; - DB_HOST = "${user}-db"; - DB_PORT = "5432"; - DB_DATABASE = user; - DB_USERNAME = user; - CACHE_DRIVER = "redis"; - SESSION_DRIVER = "redis"; - REDIS_SCHEME = "tcp"; - REDIS_HOST = "host.docker.internal"; - REDIS_PORT = "6379"; - REDIS_DB = "0"; - REDIS_CACHE_DB = "1"; - MAIL_MAILER = "smtp"; - APP_URL = "https://money.millironx.com"; - AUTHENTICATION_GUARD = "remote_user_guard"; - AUTHENTICATION_GUARD_HEADER = "HTTP_X_AUTHENTIK_USERNAME"; - AUTHENTICATION_GUARD_EMAIL = "HTTP_X_AUTHENTIK_EMAIL"; - }; - secrets = map (s: "${s},type=env") [ - "SITE_OWNER" - "APP_KEY" - "DB_PASSWORD" - "MAIL_HOST" - "MAIL_PORT" - "MAIL_FROM" - "MAIL_USERNAME" - "MAIL_PASSWORD" - "MAIL_ENCRYPTION" - "REDIS_PASSWORD" - ]; - volumes = [ "${stateDirectory}/upload:/var/html/storage/upload:U" ]; - networks = [ networks."${user}".ref ]; - publishPorts = [ "127.0.0.1:${port}:${containerPort}" ]; - }; - unitConfig.Requires = [ secrets.ref containers."${user}-db".ref ]; - unitConfig.After = [ secrets.ref containers."${user}-db".ref ]; - }; - }; - }; - }; -} diff --git a/services/freshrss.nix b/services/freshrss.nix deleted file mode 100644 index 2f142ff..0000000 --- a/services/freshrss.nix +++ /dev/null @@ -1,146 +0,0 @@ -{ config, pkgs, home-manager-quadlet-nix, ... }: - -let - user = "freshrss"; - port = "37374"; - stateDirectory = "/var/lib/freshrss"; - serviceContainer = "freshrss"; - stateSubDir = subDir: "${stateDirectory}/${subDir}"; - createTmpfilesRule = subDir: "d ${stateSubDir subDir} 1755 ${user} ${user}"; - - dbDirectories = [ "database" ]; - serviceDirectories = [ "data" "extensions" ]; -in { - age.secrets = { - "freshrss.toml" = { - file = ./../secrets/freshrss.toml.age; - owner = "${user}"; - }; - }; - - millironx.podman-secrets.freshrss = { - user = "${user}"; - secrets-files = [ config.age.secrets."freshrss.toml".path ]; - }; - - services.caddy.virtualHosts."feeds.millironx.com".extraConfig = '' - reverse_proxy http://127.0.0.1:${port} { - header_up X-Forwarded-Port 443 - } - ''; - - systemd.tmpfiles.rules = builtins.map createTmpfilesRule - ([ stateDirectory ] ++ dbDirectories ++ serviceDirectories); - - services.borgmatic.configurations."${config.networking.hostName}" = { - source_directories = builtins.map stateSubDir dbDirectories; - - postgresql_databases = [{ - name = serviceContainer; - psql_command = - "/run/wrappers/bin/sudo -iu ${user} ${pkgs.podman}/bin/podman exec ${serviceContainer}-db psql --username=${user}"; - pg_dump_command = - "/run/wrappers/bin/sudo -iu ${user} ${pkgs.podman}/bin/podman exec ${serviceContainer}-db pg_dump --username=${user}"; - pg_restore_command = - "/run/wrappers/bin/sudo -iu ${user} ${pkgs.podman}/bin/podman exec ${serviceContainer}-db pg_restore --username=${user}"; - }]; - }; - - users.users."${user}" = { - group = "${user}"; - isNormalUser = true; - home = "${stateDirectory}"; - createHome = true; - linger = true; - autoSubUidGidRange = true; - }; - users.groups."${user}" = { }; - - home-manager.users."${user}" = { config, osConfig, ... }: { - imports = [ home-manager-quadlet-nix ]; - - home.stateVersion = "25.05"; - - virtualisation.quadlet = let - inherit (config.virtualisation.quadlet) containers; - inherit (config.virtualisation.quadlet) networks; - secrets = osConfig.millironx.podman-secrets.freshrss; - - in { - containers = { - "${serviceContainer}-db" = { - autoStart = true; - containerConfig = { - image = "docker.io/library/postgres:16"; - environments = { - POSTGRES_DB = "${user}"; - POSTGRES_USER = "${user}"; - }; - secrets = [ - "POSTGRES_PASSWORD,type=env" - "POSTGRES_PASSWORD,type=env,target=PGPASSWORD" - ]; - healthCmd = "pg_isready -d $\${POSTGRES_DB} -U $\${POSTGRES_USER}"; - healthInterval = "30s"; - healthRetries = 5; - healthStartPeriod = "20s"; - volumes = - [ "${stateDirectory}/database:/var/lib/postgresql/data:U" ]; - networks = [ networks."${serviceContainer}".ref ]; - }; - unitConfig.Requires = [ secrets.ref ]; - unitConfig.After = [ secrets.ref ]; - }; - - "${serviceContainer}" = { - autoStart = true; - containerConfig = { - image = "docker.io/freshrss/freshrss:1"; - # Required to allow the container to talk to the host ports, in - # other words, to resolve Authentik correctly - addHosts = [ "auth.millironx.com:host-gateway" ]; - environments = { - TZ = osConfig.time.timeZone; - CRON_MIN = "2,32"; - LISTEN = "0.0.0.0:${port}"; - TRUSTED_PROXY = "172.16.0.1/12 192.168.0.1/16"; - OIDC_ENABLED = "1"; - OIDC_PROVIDER_METADATA_URL = - "https://auth.millironx.com/application/o/freshrss/.well-known/openid-configuration"; - OIDC_REMOTE_USER_CLAIM = "preferred_username"; - OIDC_SCOPES = "openid email profile"; - OIDC_X_FORWARDED_HEADERS = - "X-Forwarded-Host X-Forwarded-Port X-Forwarded-Proto"; - }; - secrets = [ - "OIDC_CLIENT_ID,type=env" - "OIDC_CLIENT_SECRET,type=env" - "OIDC_CLIENT_CRYPTO_KEY,type=env" - ]; - healthCmd = "cli/health.php"; - healthTimeout = "10s"; - healthStartPeriod = "60s"; - healthStartupInterval = "11s"; - healthInterval = "75s"; - healthRetries = 3; - networks = [ networks."${serviceContainer}".ref ]; - publishPorts = [ "127.0.0.1:${port}:${port}" ]; - volumes = [ - "${stateDirectory}/data:/var/www/FreshRSS/data:U" - "${stateDirectory}/extensions:/var/www/FreshRSS/extensions:U" - ]; - }; - unitConfig.Requires = - [ secrets.ref containers."${serviceContainer}-db".ref ]; - unitConfig.After = - [ secrets.ref containers."${serviceContainer}-db".ref ]; - }; - }; - - networks."${serviceContainer}" = { }; - - autoUpdate.enable = true; - autoEscape = true; - }; - }; -} diff --git a/services/gpg-agent.nix b/services/gpg-agent.nix index e4a7939..e34906a 100644 --- a/services/gpg-agent.nix +++ b/services/gpg-agent.nix @@ -2,7 +2,7 @@ services.gpg-agent = { enable = true; enableBashIntegration = true; - enableSshSupport = false; + enableSshSupport = true; enableZshIntegration = true; defaultCacheTtl = 604800; maxCacheTtl = 604800; diff --git a/services/immich.nix b/services/immich.nix deleted file mode 100644 index c2d998f..0000000 --- a/services/immich.nix +++ /dev/null @@ -1,182 +0,0 @@ -{ config, pkgs, home-manager-quadlet-nix, ... }: -let - user = "immich"; - port = "46642"; - containerPort = "2283"; - redisPort = 64664; - stateDirectory = "/var/lib/${user}"; - servicePaths = [ ]; - databasePaths = [ "database" ]; - s3BucketName = "millironx-photos"; - s3MountDirectory = "/mount/s3/${s3BucketName}"; - immich-version = "v2"; -in { - age.secrets = { - millironx-photos-s3-token.file = ./../secrets/millironx-photos-s3.age; - redis-immich-password.file = ./../secrets/redis-immich-password.age; - "immich.toml" = { - file = ./../secrets/immich.toml.age; - owner = user; - }; - }; - - millironx.podman-secrets.immich = { - inherit user; - secrets-files = [ config.age.secrets."immich.toml".path ]; - }; - - systemd.tmpfiles.rules = - map (d: "d ${stateDirectory}/${d} 1775 ${user} ${user} -") - ([ "" ] ++ servicePaths ++ databasePaths); - - environment.systemPackages = [ pkgs.s3fs ]; - - fileSystems."${s3BucketName}" = { - device = s3BucketName; - mountPoint = s3MountDirectory; - fsType = "fuse./run/current-system/sw/bin/s3fs"; - noCheck = true; - options = [ - "_netdev" - "allow_other" - "use_path_request_style" - "url=https://us-east-1.linodeobjects.com/" - "passwd_file=${config.age.secrets.millironx-photos-s3-token.path}" - "uid=${user}" - "gid=${user}" - "umask=0022" - ]; - }; - - services = { - borgmatic.configurations."${config.networking.hostName}" = { - source_directories = map (d: "${stateDirectory}/${d}") servicePaths; - postgresql_databases = [{ - name = user; - psql_command = - "/run/wrappers/bin/sudo -iu ${user} ${pkgs.podman}/bin/podman exec ${user}-db psql --username=${user}"; - pg_dump_command = - "/run/wrappers/bin/sudo -iu ${user} ${pkgs.podman}/bin/podman exec ${user}-db pg_dump --username=${user}"; - pg_restore_command = - "/run/wrappers/bin/sudo -iu ${user} ${pkgs.podman}/bin/podman exec ${user}-db pg_restore --username=${user}"; - }]; - }; - - caddy.virtualHosts."photos.millironx.com".extraConfig = '' - reverse_proxy http://127.0.0.1:${port} - ''; - - redis.servers."${user}" = { - enable = true; - port = redisPort; - bind = "0.0.0.0"; - requirePassFile = config.age.secrets.redis-immich-password.path; - }; - }; - - users.users."${user}" = { - group = user; - isNormalUser = true; - home = stateDirectory; - createHome = true; - linger = true; - autoSubUidGidRange = true; - }; - users.groups."${user}" = { }; - - home-manager.users."${user}" = { config, osConfig, ... }: { - imports = [ home-manager-quadlet-nix ]; - - home.stateVersion = "25.05"; - - virtualisation.quadlet = let - inherit (config.virtualisation.quadlet) containers; - inherit (config.virtualisation.quadlet) networks; - inherit (config.virtualisation.quadlet) volumes; - secrets = osConfig.millironx.podman-secrets.immich; - db-user = "postgres"; - in { - autoUpdate.enable = true; - autoEscape = true; - - networks."${user}" = { }; - - volumes.model-cache.volumeConfig = { }; - - containers = { - "${user}-db" = { - autoStart = true; - containerConfig = { - # For some reason, the -rootless variant seems to hang, so go with - # the rootful one (even though this user has no root access) - image = "docker.io/tensorchord/pgvecto-rs:pg16-v0.3.0"; - environments = { - POSTGRES_DB = user; - POSTGRES_USER = db-user; - POSTGRES_INITDB_ARGS = "--data-checksums"; - }; - secrets = [ - "POSTGRES_PASSWORD,type=env" - "POSTGRES_PASSWORD,type=env,target=PGPASSWORD" - ]; - healthCmd = "pg_isready -d $\${POSTGRES_DB} -U $\${POSTGRES_USER}"; - healthInterval = "30s"; - healthRetries = 5; - healthStartPeriod = "20s"; - volumes = - [ "${stateDirectory}/database:/var/lib/postgresql/data:U" ]; - networks = [ networks."${user}".ref ]; - }; - unitConfig.Requires = [ secrets.ref ]; - unitConfig.After = [ secrets.ref ]; - }; - - "${user}-ml" = { - autoStart = true; - containerConfig = { - image = - "ghcr.io/immich-app/immich-machine-learning:${immich-version}"; - networks = [ networks."${user}".ref ]; - volumes = [ "${volumes.model-cache.ref}:/cache" ]; - }; - }; - - "${user}" = { - autoStart = true; - containerConfig = { - image = "ghcr.io/immich-app/immich-server:${immich-version}"; - environments = { - DB_HOSTNAME = "${user}-db"; - DB_USERNAME = db-user; - DB_DATABASE_NAME = user; - REDIS_HOSTNAME = "host.docker.internal"; - REDIS_PORT = builtins.toString redisPort; - }; - secrets = - map (s: "${s},type=env") [ "DB_PASSWORD" "REDIS_PASSWORD" ]; - volumes = [ - # Generally, mounts need the :U directive, but in the case of - # mounting the root of a bucket, that hangs. Uploads are verified - # to work without that, so everything should be fine - "${s3MountDirectory}:/usr/src/app/upload" - "/etc/localtime:/etc/localtime:ro" - ]; - networks = [ networks."${user}".ref ]; - publishPorts = [ "127.0.0.1:${port}:${containerPort}" ]; - addHosts = [ "auth.millironx.com:host-gateway" ]; - }; - unitConfig.Requires = [ - secrets.ref - containers."${user}-db".ref - containers."${user}-ml".ref - ]; - unitConfig.After = [ - secrets.ref - containers."${user}-db".ref - containers."${user}-ml".ref - ]; - }; - }; - }; - }; -} diff --git a/services/navidrome.nix b/services/navidrome.nix deleted file mode 100644 index 9db322a..0000000 --- a/services/navidrome.nix +++ /dev/null @@ -1,132 +0,0 @@ -{ config, pkgs, home-manager-quadlet-nix, ... }: -let - user = "navidrome"; - port = "4533"; - authentikPort = "9000"; - stateDirectory = "/var/lib/${user}"; - s3BucketName = "millironx-music"; - s3MountDirectory = "/mount/s3/${s3BucketName}"; -in { - age.secrets = { - millironx-music-s3-token.file = ./../secrets/millironx-music-s3.age; - "navidrome.toml" = { - file = ./../secrets/navidrome.toml.age; - owner = user; - }; - }; - - millironx.podman-secrets.navidrome = { - inherit user; - secrets-files = [ config.age.secrets."navidrome.toml".path ]; - }; - - environment.systemPackages = [ pkgs.s3fs ]; - - fileSystems."${s3BucketName}" = { - device = s3BucketName; - mountPoint = s3MountDirectory; - fsType = "fuse./run/current-system/sw/bin/s3fs"; - noCheck = true; - options = [ - "_netdev" - "allow_other" - "use_path_request_style" - "url=https://us-east-1.linodeobjects.com/" - "passwd_file=${config.age.secrets.millironx-music-s3-token.path}" - "uid=${user}" - "gid=${user}" - "umask=0022" - ]; - }; - - systemd.tmpfiles.rules = - map (d: "d ${stateDirectory}/${d} 1775 ${user} ${user} -") [ "" "data" ]; - - services.borgmatic.configurations."${config.networking.hostName}" = { - source_directories = map (d: "${stateDirectory}/${d}") [ "data" ]; - }; - - # Modified from - # - - # - - # Modifications are exclusively changes from Docker hostnames to 127.0.0.1 and - # port numbers - services.caddy.virtualHosts."music.millironx.com".extraConfig = '' - # Authentik output endpoint - reverse_proxy /outpost.goauthentik.io/* http://127.0.0.1:${authentikPort} - - # Protect everything except share and subsonic endpoints - @protected not path /share/* /rest/* - forward_auth @protected http://127.0.0.1:${authentikPort} { - uri /outpost.goauthentik.io/auth/caddy - copy_headers X-Authentik-Username>Remote-User - } - - # Authentik uses the Authorization header if present, so should be able to - # authenticate subsonic clients that support BasicAuth. Requests from the - # Navidrome Web App will be authenticated via the existing session cookie. - # If you want to have Navidrome authenticate subsonic requests, remove this - # forward_auth block. - @subsonic path /rest/* - forward_auth @subsonic http://127.0.0.1:${authentikPort} { - uri /outpost.goauthentik.io/auth/caddy - copy_headers X-Authentik-Username>Remote-User - - # Some clients that claim to support basicauth still expect a subsonic - # response in case of authentication failure instead of a proper basicauth - # response. - @error status 1xx 3xx 4xx 5xx - handle_response @error { - respond < - - - SUBSONICERR 200 - } - } - - # Forward everything to Navidrome - reverse_proxy http://127.0.0.1:${port} - ''; - - users.users."${user}" = { - group = "${user}"; - isNormalUser = true; - home = stateDirectory; - createHome = true; - linger = true; - autoSubUidGidRange = true; - }; - users.groups."${user}" = { }; - - home-manager.users."${user}" = { config, osConfig, ... }: { - imports = [ home-manager-quadlet-nix ]; - - home.stateVersion = "25.05"; - - virtualisation.quadlet = { - autoUpdate.enable = true; - containers.navidrome = { - autoStart = true; - containerConfig = { - image = "docker.io/deluan/navidrome:latest"; - environments = { - ND_BASEURL = "https://music.millironx.com"; - # pasta appears to use the static host IP so trust that - ND_EXTAUTH_TRUSTEDSOURCES = "23.239.13.247/24"; - }; - secrets = - map (s: "${s},type=env") [ "ND_LASTFM_APIKEY" "ND_LASTFM_SECRET" ]; - volumes = [ - "${s3MountDirectory}:/music:ro" - "${stateDirectory}/data:/data:U" - ]; - publishPorts = [ "127.0.0.1:${port}:${port}" ]; - }; - unitConfig.Requires = - [ osConfig.millironx.podman-secrets.navidrome.ref ]; - unitConfig.After = [ osConfig.millironx.podman-secrets.navidrome.ref ]; - }; - }; - }; -} diff --git a/services/nixos-update.nix b/services/nixos-update.nix new file mode 100644 index 0000000..f0678ec --- /dev/null +++ b/services/nixos-update.nix @@ -0,0 +1,50 @@ +# This file is designed to be used in the imports +{ pkgs, config, ... }: + +{ + environment.systemPackages = [ + (pkgs.writeScriptBin "update-nixos" '' + #!${pkgs.bash}/bin/bash + echo "Requesting system update..." + ${pkgs.systemd}/bin/systemctl start nixos-update.service + '') + ]; + + # Service to update NixOS configuration from git repo + systemd.services."nixos-update" = { + description = "Update NixOS configuration from git repository"; + path = with pkgs; [ coreutils ]; + script = '' + # Rebuild the system directly from the remote flake + ${pkgs.nixos-rebuild}/bin/nixos-rebuild switch --flake git+https://code.millironx.com/millironx/nix-dotfiles.git#${config.networking.hostName} + ''; + serviceConfig = { + Type = "oneshot"; + User = "root"; + }; + }; + + # Timer to run the update service daily at 3am + systemd.timers."nixos-update" = { + wantedBy = [ "timers.target" ]; + description = "Run NixOS update daily at 3am"; + timerConfig = { + OnCalendar = "3:00"; + Persistent = true; + Unit = "nixos-update.service"; + }; + }; + + # Polkit rule to allow non-root users to trigger the update + security.polkit.extraConfig = '' + polkit.addRule(function(action, subject) { + if (action.id == "org.freedesktop.systemd1.manage-units" && + action.lookup("unit") == "nixos-update.service" && + action.lookup("verb") == "start" && + subject.isInGroup("wheel")) { + return polkit.Result.YES; + } + }); + ''; + +} diff --git a/services/openssh.nix b/services/openssh.nix deleted file mode 100644 index a315eac..0000000 --- a/services/openssh.nix +++ /dev/null @@ -1,9 +0,0 @@ -{ ... }: { - services.openssh = { - enable = true; - settings = { - PermitRootLogin = "no"; - PasswordAuthentication = false; - }; - }; -} diff --git a/services/peertube.nix b/services/peertube.nix deleted file mode 100644 index 89488c9..0000000 --- a/services/peertube.nix +++ /dev/null @@ -1,212 +0,0 @@ -{ config, pkgs, home-manager-quadlet-nix, ... }: -let - domain = "video.millironx.com"; - user = "peertube"; - port = "33788"; - containerPort = "9000"; - rtmpHostPort = "41936"; - rtmpContainerPort = "1935"; - redisPort = 63378; - stateDirectory = "/var/lib/${user}"; - servicePaths = [ "data" "config" "assets" ]; - databasePaths = [ "database" ]; - peertubeVersion = "v8.1.4"; - peertubeAssetsDir = "${pkgs.peertube}/client/dist"; -in { - age.secrets = { - "redis-${user}-password".file = ./../secrets/redis-${user}-password.age; - "${user}.toml" = { - file = ./../secrets/${user}.toml.age; - owner = user; - }; - }; - - millironx.podman-secrets.${user} = { - inherit user; - secrets-files = [ config.age.secrets."${user}.toml".path ]; - }; - - systemd.tmpfiles.rules = - map (d: "d ${stateDirectory}/${d} 1775 ${user} ${user} -") - ([ "" ] ++ servicePaths ++ databasePaths); - - services = { - borgmatic.configurations."${config.networking.hostName}" = { - source_directories = map (d: "${stateDirectory}/${d}") servicePaths; - postgresql_databases = [{ - name = user; - psql_command = - "/run/wrappers/bin/sudo -iu ${user} ${pkgs.podman}/bin/podman exec ${user}-db psql --username=${user}"; - pg_dump_command = - "/run/wrappers/bin/sudo -iu ${user} ${pkgs.podman}/bin/podman exec ${user}-db pg_dump --username=${user}"; - pg_restore_command = - "/run/wrappers/bin/sudo -iu ${user} ${pkgs.podman}/bin/podman exec ${user}-db pg_restore --username=${user}"; - }]; - }; - - caddy.virtualHosts.${domain}.extraConfig = - builtins.readFile ./../conf/peertube.caddyfile; - - redis.servers.${user} = { - enable = true; - port = redisPort; - bind = "0.0.0.0"; - requirePassFile = config.age.secrets."redis-${user}-password".path; - }; - }; - - # This is a hack - I'm deliberately hijacking the systemd service that is - # set up by `services.caddy` in order to sync the `let` variables with the - # external Caddyfile via environment variables - # This is safe for NixOS 25.11 - see - # - systemd.services.caddy.environment = { - MILLIRONX_PEERTUBE_PORT = port; - MILLIRONX_PEERTUBE_ASSETS_DIR = peertubeAssetsDir; - MILLIRONX_PEERTUBE_DATA_DIR = "${stateDirectory}/data"; - }; - # Another hack - allows the Caddy user to be able to read files that - # PeerTube writes into its dist/ folders - users.users.${config.services.caddy.user}.extraGroups = [ user ]; - - # Forward RTMP (privileged) port to container-accessible (non-privileged) port - systemd = { - sockets."peertube-rtmp" = { - description = "PeerTube RTMP Socket"; - wantedBy = [ "sockets.target" ]; - socketConfig = { - ListenStream = "0.0.0.0:${rtmpContainerPort}"; - Accept = false; - Service = "peertube-rtmp-forward.service"; - }; - }; - - services."peertube-rtmp-forward" = { - description = "PeerTube RTMP Port Forwarder"; - requires = [ "peertube-rtmp.socket" ]; - after = [ "network.target" ]; - serviceConfig = { - Type = "notify"; - ExecStart = - "${pkgs.systemd}/lib/systemd/systemd-socket-proxyd 127.0.0.1:${rtmpHostPort}"; - PrivateTmp = true; - }; - }; - }; - networking.firewall.allowedTCPPorts = [ 1935 ]; - - users.users.${user} = { - group = user; - isNormalUser = true; - home = stateDirectory; - createHome = true; - linger = true; - autoSubUidGidRange = true; - }; - users.groups.${user} = { }; - - home-manager.users.${user} = { config, osConfig, ... }: { - imports = [ home-manager-quadlet-nix ]; - - home.stateVersion = "25.05"; - - virtualisation.quadlet = let - inherit (config.virtualisation.quadlet) containers; - inherit (config.virtualisation.quadlet) networks; - secrets = osConfig.millironx.podman-secrets.${user}; - in { - autoUpdate.enable = true; - autoEscape = true; - - networks.${user} = { }; - - containers = { - "${user}-db" = { - autoStart = true; - containerConfig = { - image = "docker.io/library/postgres:16"; - environments = { - POSTGRES_DB = user; - POSTGRES_USER = user; - }; - secrets = [ - "POSTGRES_PASSWORD,type=env" - "POSTGRES_PASSWORD,type=env,target=PGPASSWORD" - ]; - healthCmd = "pg_isready -d $\${POSTGRES_DB} -U $\${POSTGRES_USER}"; - healthInterval = "30s"; - healthRetries = 5; - healthStartPeriod = "20s"; - volumes = - [ "${stateDirectory}/database:/var/lib/postgresql/data:U" ]; - networks = [ networks."${user}".ref ]; - }; - unitConfig.Requires = [ secrets.ref ]; - unitConfig.After = [ secrets.ref ]; - }; - - "${user}" = { - # TODO: Once data is migrated from anderson, turn this server to - # autostart true - autoStart = false; - containerConfig = { - image = "docker.io/chocobozzz/peertube:${peertubeVersion}"; - environments = { - PEERTUBE_DB_USERNAME = user; - PEERTUBE_DB_SSL = "false"; - PEERTUBE_DB_HOSTNAME = "${user}-db"; - PEERTUBE_WEBSERVER_HOSTNAME = domain; - PEERTUBE_TRUST_PROXY = - ''["127.0.0.1","loopback","172.18.0.0/16"]''; - PEERTUBE_REDIS_HOSTNAME = "host.docker.internal"; - PEERTUBE_REDIS_PORT = builtins.toString redisPort; - PEERTUBE_USER_VIDEO_QUOTA = "0"; - PEERTUBE_SIGNUP_ENABLED = "false"; - PEERTUBE_CONTACT_FORM_ENABLED = "false"; - PEERTUBE_TRANSCODING_ENABLED = "true"; - PEERTUBE_TRANSCODING_THREADS = "2"; - PEERTUBE_TRANSCODING_144P = "true"; - PEERTUBE_TRANSCODING_360P = "true"; - PEERTUBE_TRANSCODING_480P = "true"; - PEERTUBE_TRANSCODING_720P = "true"; - PEERTUBE_TRANSCODING_1080P = "true"; - PEERTUBE_TRANSCODING_HLS_ENABLED = "true"; - PEERTUBE_OBJECT_STORAGE_ENABLED = "true"; - PEERTUBE_OBJECT_STORAGE_WEB_VIDEOS_PREFIX = "videos"; - PEERTUBE_OBJECT_STORAGE_UPLOAD_ACL_PUBLIC = "public-read"; - PEERTUBE_OBJECT_STORAGE_STREAMING_PLAYLISTS_PREFIX = "playlists"; - }; - secrets = map (s: "${s},type=env") [ - "PEERTUBE_DB_PASSWORD" - "PEERTUBE_SECRET" - "PEERTUBE_SMTP_USERNAME" - "PEERTUBE_SMTP_PASSWORD" - "PEERTUBE_SMTP_HOSTNAME" - "PEERTUBE_SMTP_PORT" - "PEERTUBE_SMTP_FROM" - "PEERTUBE_ADMIN_EMAIL" - "PEERTUBE_REDIS_AUTH" - "PEERTUBE_OBJECT_STORAGE_ENDPOINT" - "PEERTUBE_OBJECT_STORAGE_REGION" - "PEERTUBE_OBJECT_STORAGE_CREDENTIALS_ACCESS_KEY_ID" - "PEERTUBE_OBJECT_STORAGE_CREDENTIALS_SECRET_ACCESS_KEY" - "PEERTUBE_OBJECT_STORAGE_STREAMING_PLAYLISTS_BUCKET_NAME" - "PEERTUBE_OBJECT_STORAGE_WEB_VIDEOS_BUCKET_NAME" - ]; - networks = [ networks."${user}".ref ]; - publishPorts = [ "127.0.0.1:${port}:${containerPort}" ]; - addHosts = [ "auth.millironx.com:host-gateway" ]; - volumes = [ - "${stateDirectory}/data:/data" - "${stateDirectory}/config:/config" - "${peertubeAssetsDir}:/app/client/dist:ro" - ]; - }; - - unitConfig.Requires = [ secrets.ref containers."${user}-db".ref ]; - unitConfig.After = [ secrets.ref containers."${user}-db".ref ]; - }; - }; - }; - }; -} diff --git a/services/pihole.nix b/services/pihole.nix new file mode 100644 index 0000000..ed4cd19 --- /dev/null +++ b/services/pihole.nix @@ -0,0 +1,27 @@ +{ config, ... }: + +{ + age.secrets = { + pihole-credentials = { + file = ./../secrets/pihole.age; + owner = "root"; + group = "root"; + }; + }; + virtualisation = { + quadlet = { + containers = { + pihole = { + containerConfig = { + image = "docker.io/pihole/pihole:2025.06.2"; + publishPorts = + [ "53:53/tcp" "53:53/udp" "80:80/tcp" "443:443/tcp" ]; + environmentFiles = [ config.age.secrets.pihole-credentials.path ]; + networks = [ "bridge" ]; + dns = [ "127.0.0.1" "194.242.2.9" "9.9.9.9" ]; + }; + }; + }; + }; + }; +} diff --git a/services/samba.nix b/services/samba.nix index b248d33..e6fa607 100644 --- a/services/samba.nix +++ b/services/samba.nix @@ -2,6 +2,7 @@ services.samba = { enable = true; package = pkgs.sambaFull; + securityType = "user"; openFirewall = true; settings = { global = { diff --git a/services/searxng.nix b/services/searxng.nix deleted file mode 100644 index d2c3587..0000000 --- a/services/searxng.nix +++ /dev/null @@ -1,49 +0,0 @@ -{ ... }: -let port = "7327"; -in { - services.searx = { - enable = true; - - configureUwsgi = true; - uwsgiConfig = { - disable-logging = true; - http = ":${port}"; - }; - - redisCreateLocally = true; - - settings = { - general = { - instance_name = "Milliron X Search"; - enable_metrics = false; - }; - search = { autocomplete = "duckduckgo"; }; - server = { - base_url = "https://search.millironx.com/"; - limiter = true; - public_instance = true; - image_proxy = true; - method = "GET"; - secret_key = "rC35eF8DRpJDqa"; - }; - ui = { query_in_title = false; }; - hostnames = { - replace = { "(www.)?reddit.com$" = "old.reddit.com"; }; - low_priority = [ - "(.*.)?facebooks.com$" - "(.*.)?youtube.com$" - "(.*.)?youtu.be$" - "(.*.)?reddit.com$" - "(.*.)?redd.it$" - "(www.)?twitter.com$" - "(www.)?x.com$" - ]; - high_priority = [ "(.*.)?wikipedia.org$" ]; - }; - }; - }; - - services.caddy.virtualHosts."search.millironx.com".extraConfig = '' - reverse_proxy http://127.0.0.1:${port} - ''; -} diff --git a/services/syncthing.nix b/services/syncthing.nix deleted file mode 100644 index 85ca1ed..0000000 --- a/services/syncthing.nix +++ /dev/null @@ -1,49 +0,0 @@ -{ hostname, ... }: { - services.syncthing = let - devices = { - bracket.id = - "6I5AHYC-IWSO3SZ-TZY4SSR-Z7MGB2V-QMCMJXE-QW5JBQV-DBDU5YV-4LRLKQW"; - boozer.id = - "JKLIUHR-SBAVQCX-43ETUQR-M4ZZA75-JXK7EOF-F5RJBG7-PT363R6-MJ6WLQ4"; - } // (if hostname != "odyssey" then { - odyssey.id = - "YC6NDSU-2JRS4MY-BSM4B5V-FWPXKSJ-S573II2-HDOSWSN-DVIDORQ-UUHTKQB"; - } else - { }) // (if hostname != "corianne" then { - corianne.id = - "EN5KDDZ-F6DYDSR-KK35M2M-BVGBU4W-MVC4ENT-5EPWA6M-BBJPIBU-EQTPRQX"; - } else - { }); - in { - enable = true; - settings = { - inherit devices; - folders = let deviceNames = builtins.attrNames devices; - in { - Logseq = { - label = "Logseq"; - id = "kkqs5-4upcf"; - path = "~/Logseq"; - type = "sendreceive"; - versioning = { - type = "trashcan"; - params.cleanoutDays = 14; - }; - devices = deviceNames; - }; - SyncBucket = { - label = "SyncBucket"; - id = "9l6gb-rkyou"; - path = "~/SyncBucket"; - type = "sendreceive"; - versioning = { - type = "trashcan"; - params.cleanoutDays = 14; - }; - devices = deviceNames; - }; - }; - options = { urAccepted = -1; }; - }; - }; -} diff --git a/services/tailscale.nix b/services/tailscale.nix deleted file mode 100644 index 327afc6..0000000 --- a/services/tailscale.nix +++ /dev/null @@ -1,6 +0,0 @@ -{ ... }: { - services.tailscale = { - enable = true; - useRoutingFeatures = "server"; - }; -} diff --git a/services/vaultwarden.nix b/services/vaultwarden.nix deleted file mode 100644 index d58a40e..0000000 --- a/services/vaultwarden.nix +++ /dev/null @@ -1,170 +0,0 @@ -{ config, pkgs, home-manager-quadlet-nix, ... }: -let - user = "vaultwarden"; - port = "9285"; - containerPort = port; - authentikPort = "9000"; - stateDirectory = "/var/lib/${user}"; - servicePaths = [ "data" ]; - databasePaths = [ "database" ]; -in { - age.secrets."vaultwarden.toml" = { - file = ./../secrets/vaultwarden.toml.age; - owner = user; - }; - - millironx.podman-secrets.vaultwarden = { - inherit user; - secrets-files = [ config.age.secrets."vaultwarden.toml".path ]; - }; - - systemd.tmpfiles.rules = - map (d: "d ${stateDirectory}/${d} 1775 ${user} ${user} -") - ([ "" ] ++ servicePaths ++ databasePaths); - - services.borgmatic.configurations."${config.networking.hostName}" = { - source_directories = map (d: "${stateDirectory}/${d}") servicePaths; - postgresql_databases = [{ - name = user; - psql_command = - "/run/wrappers/bin/sudo -iu ${user} ${pkgs.podman}/bin/podman exec ${user}-db psql --username=${user}"; - pg_dump_command = - "/run/wrappers/bin/sudo -iu ${user} ${pkgs.podman}/bin/podman exec ${user}-db pg_dump --username=${user}"; - pg_restore_command = - "/run/wrappers/bin/sudo -iu ${user} ${pkgs.podman}/bin/podman exec ${user}-db pg_restore --username=${user}"; - }]; - }; - - services.caddy.virtualHosts."vault.millironx.com".extraConfig = '' - # See - encode zstd gzip - header / { - Strict-Transport-Security "max-age=31536000;" - X-XSS-Protection "0" - X-Frame-Options "DENY" - X-Robots-Tag "noindex, nofollow" - X-Content-Type-Options "nosniff" - -Server - -X-Powered-By - -Last-Modified - } - - @admin { - path /admin* - not remote_ip private_ranges 100.64.0.0/10 - } - respond @admin "Access denied to remote clients. Use localhost or VPN." 403 - - reverse_proxy http://127.0.0.1:${port} { - header_up X-Real-IP {remote_host} - } - ''; - - services.crowdsec = { - localConfig.acquisitions = [{ - source = "journalctl"; - journalctl_filter = [ "_SYSTEMD_USER_UNIT=${user}.service" ]; - labels.type = "bitwarden"; - }]; - hub.collections = [ "MariuszKociubinski/bitwarden" ]; - }; - - users.users."${user}" = { - group = user; - isNormalUser = true; - home = stateDirectory; - createHome = true; - linger = true; - autoSubUidGidRange = true; - }; - users.groups."${user}" = { }; - - home-manager.users."${user}" = { config, osConfig, ... }: { - imports = [ home-manager-quadlet-nix ]; - - home.stateVersion = "25.05"; - - virtualisation.quadlet = let - inherit (config.virtualisation.quadlet) containers; - inherit (config.virtualisation.quadlet) networks; - secrets = osConfig.millironx.podman-secrets.vaultwarden; - in { - autoUpdate.enable = true; - autoEscape = true; - - networks."${user}" = { }; - - containers = { - "${user}-db" = { - autoStart = true; - containerConfig = { - image = "docker.io/library/postgres:16"; - environments = { - POSTGRES_DB = user; - POSTGRES_USER = user; - }; - secrets = [ - "POSTGRES_PASSWORD,type=env" - "POSTGRES_PASSWORD,type=env,target=PGPASSWORD" - ]; - healthCmd = "pg_isready -d $\${POSTGRES_DB} -U $\${POSTGRES_USER}"; - healthInterval = "30s"; - healthRetries = 5; - healthStartPeriod = "20s"; - volumes = - [ "${stateDirectory}/database:/var/lib/postgresql/data:U" ]; - networks = [ networks."${user}".ref ]; - }; - unitConfig.Requires = [ secrets.ref ]; - unitConfig.After = [ secrets.ref ]; - }; - - "${user}" = { - autoStart = true; - containerConfig = { - image = "ghcr.io/dani-garcia/vaultwarden:latest"; - addHosts = [ "auth.millironx.com:host-gateway" ]; - environments = { - DOMAIN = "https://vault.millironx.com"; - ROCKET_PORT = port; - PUSH_ENABLED = "true"; - SIGNUPS_ALLOWED = "false"; - SMTP_FROM_NAME = "Milliron X Vault"; - SMTP_SECURITY = "force_tls"; - SSO_ENABLED = "true"; - SSO_ONLY = "true"; - SSO_AUTHORITY = - "https://auth.millironx.com/application/o/vaultwarden/"; - SSO_SCOPES = "openid profile email offline_access"; - # Needed to keep token expiration errors from happening - # See - SSO_AUTH_ONLY_NOT_SESSION = "true"; - }; - secrets = map (s: "${s},type=env") [ - "ADMIN_TOKEN" - "DATABASE_URL" - "PUSH_INSTALLATION_ID" - "PUSH_INSTALLATION_KEY" - "SMTP_FROM" - "SMTP_HOST" - "SMTP_PORT" - "SMTP_PASSWORD" - "SMTP_USERNAME" - "SSO_CLIENT_ID" - "SSO_CLIENT_SECRET" - "YUBICO_CLIENT_ID" - "YUBICO_SECRET_KEY" - ]; - volumes = [ "${stateDirectory}/data:/data:U" ]; - networks = [ networks."${user}".ref ]; - publishPorts = [ "127.0.0.1:${port}:${containerPort}" ]; - }; - unitConfig.Requires = [ secrets.ref containers."${user}-db".ref ]; - unitConfig.After = [ secrets.ref containers."${user}-db".ref ]; - }; - }; - }; - - }; - -} diff --git a/systems/darwin/corianne.nix b/systems/darwin/corianne.nix index 40d240b..db34258 100644 --- a/systems/darwin/corianne.nix +++ b/systems/darwin/corianne.nix @@ -15,8 +15,6 @@ in { rig-install ]; - age.secrets.firefox-policy.file = ./../../secrets/darwin-policies-json.age; - # Use a custom configuration.nix location. # $ darwin-rebuild switch -I darwin-config=$HOME/.config/nixpkgs/darwin/configuration.nix environment.darwinConfig = "$HOME/.config/home-manager/configuration.nix"; @@ -26,35 +24,9 @@ in { }; # Auto upgrade nix package and the daemon service. - nix = { - enable = true; - gc = { - automatic = true; - interval = { Weekday = 1; }; - options = '' - --delete-older-than 90d - ''; - }; - settings = { - substituters = - [ "https://nix-community.cachix.org" "https://cache.nixos.org/" ]; - trusted-public-keys = [ - "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" - ]; - }; - - # Needed for rosetta-builder, see - # - # - linux-builder = { - enable = true; - ephemeral = true; - }; - extraOptions = '' - extra-platforms = x86_64-darwin - ''; - }; - nix-rosetta-builder.onDemand = true; + nix.enable = true; + #services.nix-daemon.tempDir = "/nix/tmp"; + nix.package = pkgs.nix; # Create /etc/zshrc that loads the nix-darwin environment. programs.zsh.enable = true; # default shell on catalina @@ -99,12 +71,11 @@ in { in [ (sysApp "Firefox") (sysApp "Thunderbird") - (sysApp "Microsoft Outlook") - (sysApp "Zed") (sysApp "Logseq") + (sysApp "Zed") (sysApp "Steam") - (localApp "Instinct Dashboard") - (localApp "Carestream") + (chromeApp "Instinct Dashboard") + (chromeApp "Carestream") ]; show-process-indicators = true; show-recents = false; @@ -159,11 +130,6 @@ in { --user=${config.system.primaryUser} \ --set-home \ _rig-install ${r-version} - - echo "Applying custom defaults..." - /usr/bin/defaults import \ - /Library/Preferences/org.mozilla.firefox \ - ${config.age.secrets.firefox-policy.path} ''; nix.settings.experimental-features = [ "nix-command" "flakes" ]; @@ -192,7 +158,15 @@ in { no_quarantine = true; }; - taps = [ "r-lib/rig" ]; + taps = [ + "homebrew/services" + { + name = "millironx/millironx"; + clone_target = + "https://code.millironx.com/millironx/homebrew-millironx.git"; + } + "r-lib/rig" + ]; brews = [ "borgbackup/tap/borgbackup-fuse" "buildkit" @@ -203,17 +177,23 @@ in { "docker" "docker-buildx" "docker-credential-helper" + "firefoxpwa" "mpv" ]; casks = [ "alt-tab" - "dash" + "anki" "db-browser-for-sqlite" + "dolphin" "firefox" + "freetube" + "ghostty" "inkscape" "iterm2" + "logi-options+" "logseq" "macfuse" + "musescore" "nextcloud" "openrct2" "qownnotes" @@ -221,7 +201,6 @@ in { "rig" "rstudio" "signal" - "skim" "slack" "stats" "steam" @@ -231,7 +210,6 @@ in { "ungoogled-chromium" "veracrypt" "vlc" - "vienna" "vorta" "zed" "zotero" diff --git a/systems/linux/bosephus.nix b/systems/linux/bosephus.nix index 6c8d181..3a0a271 100644 --- a/systems/linux/bosephus.nix +++ b/systems/linux/bosephus.nix @@ -8,7 +8,9 @@ imports = [ ./hardware-configuration/bosephus.nix ./hardware-configuration/bosephus-external-drives.nix + ./../../services/nixos-update.nix ./../../services/samba.nix + ./../../services/pihole.nix ]; # Bootloader. @@ -16,8 +18,8 @@ boot.loader.efi.canTouchEfiVariables = true; # Ignore lid - so I can close without having the system go into sleep mode - services.logind.settings.Login.HandleLidSwitch = "ignore"; - services.logind.settings.Login.HandleLidSwitchDocked = "ignore"; + services.logind.lidSwitch = "ignore"; + services.logind.lidSwitchDocked = "ignore"; # Secrets age.secrets = { diff --git a/systems/linux/mcentire.nix b/systems/linux/mcentire.nix index c5645d1..07135d1 100644 --- a/systems/linux/mcentire.nix +++ b/systems/linux/mcentire.nix @@ -3,21 +3,8 @@ { imports = [ # Include the results of the hardware scan. ./hardware-configuration/mcentire.nix - ./../../modules/podman-secrets.nix - ./../../services/borgmatic.nix - ./../../services/caddy.nix + ./../../services/nixos-update.nix ./../../services/crowdsec.nix - ./../../services/authentik.nix - ./../../services/audiobookshelf.nix - ./../../services/fireflyiii.nix - ./../../services/freshrss.nix - ./../../services/immich.nix - ./../../services/navidrome.nix - ./../../services/openssh.nix - ./../../services/peertube.nix - ./../../services/searxng.nix - ./../../services/tailscale.nix - ./../../services/vaultwarden.nix ]; # Use the GRUB 2 boot loader. @@ -28,7 +15,6 @@ useDHCP = false; interfaces.eth0.useDHCP = true; hostName = "mcentire"; # Define your hostname. - firewall.allowedTCPPorts = [ 80 443 ]; }; # Set your time zone. @@ -54,7 +40,7 @@ millironx = { isNormalUser = true; description = "Thomas A. Christensen II"; - extraGroups = [ "adm" "wheel" ]; + extraGroups = [ "wheel" ]; }; }; @@ -65,30 +51,11 @@ environment.systemPackages = with pkgs; [ neovim inetutils mtr sysstat git ]; - age.secrets.redis-password = { - file = ./../../secrets/redis-password.age; - owner = config.services.redis.servers.redis.user; - }; - services = { - # Do not "enable" database services, but include the package configuration - # so that borgmatic does not freak out about unset variables - postgresql.package = pkgs.postgresql_17; - - redis.servers.redis = { - enable = true; - # Apparently, a port is actually required, see - # - # Evaluating this in the Nix repl confirms that the port is set - # incorrectly in the final config when left out - port = 6379; - bind = "0.0.0.0"; - requirePassFile = config.age.secrets.redis-password.path; - }; + openssh.enable = true; + tailscale.enable = true; }; - virtualisation.quadlet.enable = true; - system.stateVersion = "25.05"; # Did you read the comment? nix = { extraOptions = "experimental-features = nix-command flakes"; }; } diff --git a/playbooks/templates/policies.json b/templates/policies.json similarity index 100% rename from playbooks/templates/policies.json rename to templates/policies.json