From cd92d6c9394f34dd0e95eee9fbd239dec265dfba Mon Sep 17 00:00:00 2001 From: Bryan Ramos Date: Thu, 12 Mar 2026 13:26:21 -0400 Subject: [PATCH 01/18] changed forgejo shell --- src/system/modules/forgejo/default.nix | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/system/modules/forgejo/default.nix b/src/system/modules/forgejo/default.nix index b6500f0..9542d95 100644 --- a/src/system/modules/forgejo/default.nix +++ b/src/system/modules/forgejo/default.nix @@ -19,7 +19,7 @@ in isSystemUser = true; group = "git"; home = "/var/lib/forgejo"; - shell = "${pkgs.git}/bin/git-shell"; + shell = "${pkgs.shadow}/bin/nologin"; }; users.users.nginx = mkIf nginx.enable { @@ -28,6 +28,7 @@ in systemd.tmpfiles.rules = [ "d /var/lib/forgejo 0750 git git -" + "d /var/lib/forgejo/.ssh 0700 git git -" "d /var/lib/forgejo/custom 0750 git git -" "d /var/lib/forgejo/data 0750 git git -" ]; From 830063e8383bce46d60b9992b3ee5d35de335316 Mon Sep 17 00:00:00 2001 From: Bryan Ramos Date: Thu, 12 Mar 2026 13:34:51 -0400 Subject: [PATCH 02/18] added bash --- src/system/modules/forgejo/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/system/modules/forgejo/default.nix b/src/system/modules/forgejo/default.nix index 9542d95..e9780d2 100644 --- a/src/system/modules/forgejo/default.nix +++ b/src/system/modules/forgejo/default.nix @@ -19,7 +19,7 @@ in isSystemUser = true; group = "git"; home = "/var/lib/forgejo"; - shell = "${pkgs.shadow}/bin/nologin"; + shell = "${pkgs.bash}/bin/bash"; }; users.users.nginx = mkIf nginx.enable { From 72b49e6f41a7a4186ed416e7802f1ded13328839 Mon Sep 17 00:00:00 2001 From: Bryan Ramos Date: Thu, 12 Mar 2026 13:55:58 -0400 Subject: [PATCH 03/18] server configs --- src/system/modules/forgejo/default.nix | 30 +++++++++++++++++++------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/src/system/modules/forgejo/default.nix b/src/system/modules/forgejo/default.nix index e9780d2..8d2a3a9 100644 --- a/src/system/modules/forgejo/default.nix +++ b/src/system/modules/forgejo/default.nix @@ -39,14 +39,28 @@ in group = "git"; stateDir = "/var/lib/forgejo"; - settings.server = { - DOMAIN = "git.${domain}"; - ROOT_URL = "https://git.${domain}/"; - PROTOCOL = "http+unix"; - HTTP_ADDR = socketPath; - SSH_DOMAIN = "git.${domain}"; - SSH_PORT = 22; - START_SSH_SERVER = false; + settings = { + DEFAULT = { + APP_NAME = "Git Server"; + APP_SLOGAN = ""; + }; + + server = { + DOMAIN = "git.${domain}"; + ROOT_URL = "https://git.${domain}/"; + PROTOCOL = "http+unix"; + HTTP_ADDR = socketPath; + SSH_DOMAIN = "git.${domain}"; + SSH_PORT = 22; + START_SSH_SERVER = false; + LANDING_PAGE = "explore"; + }; + + service = { + REGISTER_MANUAL_CONFIRM = true; + DISABLE_REGISTRATION = false; + DISABLE_ORGANIZATIONS = true; + }; }; database = { From 5db04c82102cf353181af4b37dab9900a49bd3fc Mon Sep 17 00:00:00 2001 From: Bryan Ramos Date: Thu, 12 Mar 2026 13:59:15 -0400 Subject: [PATCH 04/18] org creation --- src/system/modules/forgejo/default.nix | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/system/modules/forgejo/default.nix b/src/system/modules/forgejo/default.nix index 8d2a3a9..9c70bd0 100644 --- a/src/system/modules/forgejo/default.nix +++ b/src/system/modules/forgejo/default.nix @@ -59,7 +59,11 @@ in service = { REGISTER_MANUAL_CONFIRM = true; DISABLE_REGISTRATION = false; - DISABLE_ORGANIZATIONS = true; + DEFAULT_ALLOW_CREATE_ORGANIZATION = false; + }; + + admin = { + DISABLE_REGULAR_ORG_CREATION = true; }; }; From 570a321e53cbd862ca9e3388185c3bda29e23926 Mon Sep 17 00:00:00 2001 From: Bryan Ramos Date: Thu, 12 Mar 2026 14:40:18 -0400 Subject: [PATCH 05/18] configed backup and removed redundant keys --- src/system/machines/server/system.nix | 12 ++ src/system/modules/backup/default.nix | 95 +++++++++++++++ src/system/modules/forgejo/default.nix | 4 + src/user/config/keys/pgp/windows.pub.key | 109 ------------------ src/user/config/keys/ssh/windows.pub.key | 1 - .../modules/security/modules/gpg/default.nix | 5 - 6 files changed, 111 insertions(+), 115 deletions(-) create mode 100644 src/system/modules/backup/default.nix delete mode 100644 src/user/config/keys/pgp/windows.pub.key delete mode 100644 src/user/config/keys/ssh/windows.pub.key diff --git a/src/system/machines/server/system.nix b/src/system/machines/server/system.nix index 7a465a8..b0e8be6 100644 --- a/src/system/machines/server/system.nix +++ b/src/system/machines/server/system.nix @@ -8,6 +8,18 @@ nginx.enable = true; forgejo.enable = true; frigate.enable = false; + + backup = { + enable = true; + recipients = [ + # TODO: Add your age recipients + # "${config.user.keys.age.yubikey}" + # "${config.user.keys.ssh.desktop}" + ]; + destination = "gdrive:backups/server"; # TODO: configure rclone remote + schedule = "daily"; + keepLast = 7; + }; }; users.users = { diff --git a/src/system/modules/backup/default.nix b/src/system/modules/backup/default.nix new file mode 100644 index 0000000..834e024 --- /dev/null +++ b/src/system/modules/backup/default.nix @@ -0,0 +1,95 @@ +{ pkgs, lib, config, ... }: + +with lib; +let + cfg = config.modules.system.backup; + + recipientArgs = concatMapStrings (r: "-r '${r}' ") cfg.recipients; + + # Convert absolute paths to relative for tar, preserving structure + # e.g., /var/lib/forgejo -> var/lib/forgejo + tarPaths = map (p: removePrefix "/" p) cfg.paths; + + backupScript = pkgs.writeShellScript "backup" '' + set -euo pipefail + + TIMESTAMP=$(date +%Y%m%d-%H%M%S) + BACKUP_NAME="backup-$TIMESTAMP.tar.age" + TEMP_DIR=$(mktemp -d) + trap "rm -rf $TEMP_DIR" EXIT + + echo "Starting backup: $BACKUP_NAME" + echo "Paths: ${concatStringsSep " " cfg.paths}" + + ${pkgs.gnutar}/bin/tar -C / -cf - ${concatStringsSep " " tarPaths} | \ + ${pkgs.age}/bin/age ${recipientArgs} -o "$TEMP_DIR/$BACKUP_NAME" + + ${pkgs.rclone}/bin/rclone copy "$TEMP_DIR/$BACKUP_NAME" "${cfg.destination}" + + # Prune old backups + ${pkgs.rclone}/bin/rclone lsf "${cfg.destination}" | \ + sort -r | \ + tail -n +$((${toString cfg.keepLast} + 1)) | \ + while read -r old; do + ${pkgs.rclone}/bin/rclone delete "${cfg.destination}/$old" + done + + echo "Backup complete" + ''; + +in +{ + options.modules.system.backup = { + enable = mkEnableOption "Encrypted backups"; + + paths = mkOption { + type = types.listOf types.str; + default = []; + description = "Absolute paths to include in backup (structure preserved)"; + }; + + recipients = mkOption { + type = types.listOf types.str; + default = []; + description = "Age public keys for encryption"; + }; + + destination = mkOption { + type = types.str; + default = ""; + description = "Rclone destination"; + }; + + schedule = mkOption { + type = types.str; + default = "daily"; + description = "Systemd calendar expression"; + }; + + keepLast = mkOption { + type = types.int; + default = 3; + description = "Number of backups to keep"; + }; + }; + + config = mkIf cfg.enable { + environment.systemPackages = [ pkgs.rclone ]; + + systemd.services.backup = { + description = "Encrypted backup"; + serviceConfig = { + Type = "oneshot"; + ExecStart = backupScript; + }; + }; + + systemd.timers.backup = { + wantedBy = [ "timers.target" ]; + timerConfig = { + OnCalendar = cfg.schedule; + Persistent = true; + }; + }; + }; +} diff --git a/src/system/modules/forgejo/default.nix b/src/system/modules/forgejo/default.nix index 9c70bd0..ed6b461 100644 --- a/src/system/modules/forgejo/default.nix +++ b/src/system/modules/forgejo/default.nix @@ -73,6 +73,10 @@ in }; }; + modules.system.backup.paths = [ + "/var/lib/forgejo" + ]; + services.nginx.virtualHosts."git.${domain}" = mkIf nginx.enable { useACMEHost = domain; forceSSL = true; diff --git a/src/user/config/keys/pgp/windows.pub.key b/src/user/config/keys/pgp/windows.pub.key deleted file mode 100644 index cf9f326..0000000 --- a/src/user/config/keys/pgp/windows.pub.key +++ /dev/null @@ -1,109 +0,0 @@ ------BEGIN PGP PUBLIC KEY BLOCK----- - -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 -HRncE+dM4PA+Ge8YbBCL6pU= -=X5C7 ------END PGP PUBLIC KEY BLOCK----- diff --git a/src/user/config/keys/ssh/windows.pub.key b/src/user/config/keys/ssh/windows.pub.key deleted file mode 100644 index c44f5ba..0000000 --- a/src/user/config/keys/ssh/windows.pub.key +++ /dev/null @@ -1 +0,0 @@ -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCo2BuGY1zz2UjY7/4Rq6rse3dDbxkSA+GyqI2xJi86dqzpmnsQPDYCM61xBNGIJWCQRSRPvNMhQjL8zFo2+u3EyFZXP7twO9mtZCyo5guBRUYuzoCNMtxHt7ZERVei2NI+T7ZmU34L1cuo+fSluhC62hGGD8mMO/wQURO9CwXN+JGAgP5jxLnHKfS6xP7FHDvH7XbbgiC1M7B1B7mCyjzLadQqQebkmJYDnKcdz424VBljxVHlrSjDU0wsnBNpj/nP4eTsnzL+dGTWxkLwUzCDeSIvNoFjSe617iGfYK7y9imZsIb6zAUY7zwFqCN9co9PRJzBDKKhygFNkoZ9/OjIRm0MXWEn7eFsiaO7mB+tSoGCgi+/R34tRaaelmDS6D09HdWBgnOSsqW8VIa1YhAuDzSk3p0UQrSNSTuwMLh5fwDF8fpZ5c7M4U6oJzzfRp/ssWuq6XUnrVt43OqlacgCctFzRcdyZjQedF//ucUoG5dudmvYOGX9NnYEuIYdGtMVneMzsoGTycSi7fAtLC7ORyj6Q3LiOR+rEE+t+Wvw7pmnzmc2PH/C3yVBZhLGPgR+rH0NIjPQa6TnX8Y2NOCn4T4vL7LGxVfVOYoMzRcgYdB1JmrUxz6TweBX3IIpkbV+EmGpq3f0vhJAF1kE6fsrcrw/jWzIIVbymV0fim+ZGQ== bryan@ramos.codes diff --git a/src/user/modules/security/modules/gpg/default.nix b/src/user/modules/security/modules/gpg/default.nix index 170b570..79b5ec5 100644 --- a/src/user/modules/security/modules/gpg/default.nix +++ b/src/user/modules/security/modules/gpg/default.nix @@ -21,11 +21,6 @@ in text = "${config.user.keys.pgp.primary}"; trust = 5; } - ] ++ optionals (osConfig.networking.hostName == "desktop") [ - { - text = "${config.user.keys.pgp.windows}"; - trust = 5; - } ] ++ optionals (osConfig.networking.hostName == "workstation") [ { text = "${config.user.keys.pgp.work}"; From 960904cbd9a96def4d27bc5b5e67c285f6d20713 Mon Sep 17 00:00:00 2001 From: Bryan Ramos Date: Thu, 12 Mar 2026 15:17:46 -0400 Subject: [PATCH 06/18] Add machines.keys config and reorganize key structure - Add config.machines.keys for machine-specific keys (private keys live on that machine) - Move desktop SSH key to machines.keys.desktop.ssh - Fix extractName to preserve "yubikey" (only strip .key/.pub extensions) - Rename key files for clarity (android -> graphone, primary -> yubikey) - Add age yubikey key for encrypted backups - Add README files to document key purposes - Update all machine configs to import system config --- src/system/config/default.nix | 14 ++++++++ src/system/config/keys/default.nix | 33 +++++++++++++++++++ src/system/config/keys/desktop/README.md | 3 ++ .../config/keys/desktop/ssh.pub.key} | 0 src/system/machines/desktop/default.nix | 1 + src/system/machines/desktop/system.nix | 2 +- src/system/machines/server/default.nix | 1 + src/system/machines/server/system.nix | 9 +++-- src/system/machines/vm/default.nix | 1 + src/system/machines/vm/system.nix | 2 +- src/system/machines/workstation/default.nix | 1 + src/system/machines/workstation/system.nix | 2 +- src/system/machines/wsl/default.nix | 1 + src/system/machines/wsl/system.nix | 3 +- src/user/config/default.nix | 2 +- src/user/config/keys/age/README.md | 3 ++ src/user/config/keys/age/yubikey.pub.key | 1 + src/user/config/keys/default.nix | 23 ++++++++----- src/user/config/keys/pgp/README.md | 5 +++ .../pgp/{primary.pub.key => yubikey.pub.key} | 0 src/user/config/keys/ssh/README.md | 5 +++ .../ssh/{android.pub.key => graphone.pub.key} | 0 .../ssh/{primary.pub.key => yubikey.pub.key} | 0 .../modules/security/modules/gpg/default.nix | 2 +- 24 files changed, 94 insertions(+), 20 deletions(-) create mode 100644 src/system/config/default.nix create mode 100644 src/system/config/keys/default.nix create mode 100644 src/system/config/keys/desktop/README.md rename src/{user/config/keys/ssh/desktop.pub.key => system/config/keys/desktop/ssh.pub.key} (100%) create mode 100644 src/user/config/keys/age/README.md create mode 100644 src/user/config/keys/age/yubikey.pub.key create mode 100644 src/user/config/keys/pgp/README.md rename src/user/config/keys/pgp/{primary.pub.key => yubikey.pub.key} (100%) create mode 100644 src/user/config/keys/ssh/README.md rename src/user/config/keys/ssh/{android.pub.key => graphone.pub.key} (100%) rename src/user/config/keys/ssh/{primary.pub.key => yubikey.pub.key} (100%) diff --git a/src/system/config/default.nix b/src/system/config/default.nix new file mode 100644 index 0000000..4bb4315 --- /dev/null +++ b/src/system/config/default.nix @@ -0,0 +1,14 @@ +{ lib, pkgs, config, ... }: + +with lib; +{ + options = { + machines = mkOption { + description = "Machine Configurations"; + type = types.attrs; + default = { + keys = import ./keys { inherit lib; }; + }; + }; + }; +} diff --git a/src/system/config/keys/default.nix b/src/system/config/keys/default.nix new file mode 100644 index 0000000..e3f3aaf --- /dev/null +++ b/src/system/config/keys/default.nix @@ -0,0 +1,33 @@ +{ lib }: + +with builtins; +let + extractName = filename: + let + # Remove .key extension + noKey = lib.removeSuffix ".key" filename; + # Remove .pub/.priv/.public/.private markers + noMarkers = replaceStrings + [ ".pub" ".priv" ".public" ".private" ] + [ "" "" "" "" ] + noKey; + in noMarkers; + + constructKeys = dir: ( + listToAttrs ( + map (subdir: { + name = subdir; + value = listToAttrs ( + map (file: { + name = extractName file; + value = readFile "${dir}/${subdir}/${file}"; + }) (filter (file: + (readDir "${dir}/${subdir}").${file} == "regular" && + lib.hasSuffix ".key" file + ) (attrNames (readDir "${dir}/${subdir}"))) + ); + }) (filter (node: (readDir dir).${node} == "directory") (attrNames (readDir dir))) + ) + ); +in + constructKeys ./. diff --git a/src/system/config/keys/desktop/README.md b/src/system/config/keys/desktop/README.md new file mode 100644 index 0000000..355d803 --- /dev/null +++ b/src/system/config/keys/desktop/README.md @@ -0,0 +1,3 @@ +# Desktop Keys + +ssh.pub.key - ~/.ssh/id_rsa diff --git a/src/user/config/keys/ssh/desktop.pub.key b/src/system/config/keys/desktop/ssh.pub.key similarity index 100% rename from src/user/config/keys/ssh/desktop.pub.key rename to src/system/config/keys/desktop/ssh.pub.key diff --git a/src/system/machines/desktop/default.nix b/src/system/machines/desktop/default.nix index 8a29c89..99a49af 100644 --- a/src/system/machines/desktop/default.nix +++ b/src/system/machines/desktop/default.nix @@ -3,6 +3,7 @@ { imports = [ ../../../user/config + ../../config ./hardware.nix ./system.nix ./modules/disko diff --git a/src/system/machines/desktop/system.nix b/src/system/machines/desktop/system.nix index 402fa85..e09b06b 100644 --- a/src/system/machines/desktop/system.nix +++ b/src/system/machines/desktop/system.nix @@ -13,7 +13,7 @@ in isNormalUser = true; extraGroups = config.user.groups ++ [ "video" "audio" "kvm" "libvirtd" "dialout" ]; - openssh.authorizedKeys.keys = [ "${config.user.keys.ssh.android}" ]; + openssh.authorizedKeys.keys = [ "${config.user.keys.ssh.graphone}" ]; }; }; diff --git a/src/system/machines/server/default.nix b/src/system/machines/server/default.nix index 6e64b71..c71ec8a 100644 --- a/src/system/machines/server/default.nix +++ b/src/system/machines/server/default.nix @@ -3,6 +3,7 @@ { imports = [ ../../../user/config + ../../config ./hardware.nix ./system.nix ]; diff --git a/src/system/machines/server/system.nix b/src/system/machines/server/system.nix index b0e8be6..8d289dd 100644 --- a/src/system/machines/server/system.nix +++ b/src/system/machines/server/system.nix @@ -12,13 +12,12 @@ backup = { enable = true; recipients = [ - # TODO: Add your age recipients - # "${config.user.keys.age.yubikey}" - # "${config.user.keys.ssh.desktop}" + "${config.user.keys.age.yubikey}" + "${config.machines.keys.desktop.ssh}" ]; destination = "gdrive:backups/server"; # TODO: configure rclone remote schedule = "daily"; - keepLast = 7; + keepLast = 2; }; }; @@ -27,7 +26,7 @@ isNormalUser = true; extraGroups = config.user.groups; openssh.authorizedKeys.keys = [ - "${config.user.keys.ssh.desktop}" + "${config.machines.keys.desktop.ssh}" ]; }; }; diff --git a/src/system/machines/vm/default.nix b/src/system/machines/vm/default.nix index 6e64b71..c71ec8a 100644 --- a/src/system/machines/vm/default.nix +++ b/src/system/machines/vm/default.nix @@ -3,6 +3,7 @@ { imports = [ ../../../user/config + ../../config ./hardware.nix ./system.nix ]; diff --git a/src/system/machines/vm/system.nix b/src/system/machines/vm/system.nix index f63f65e..444b180 100644 --- a/src/system/machines/vm/system.nix +++ b/src/system/machines/vm/system.nix @@ -8,7 +8,7 @@ ${config.user.name} = { isNormalUser = true; extraGroups = config.user.groups; - openssh.authorizedKeys.keys = [ "${config.user.keys.ssh.primary}" ]; + openssh.authorizedKeys.keys = [ "${config.user.keys.ssh.yubikey}" ]; }; }; diff --git a/src/system/machines/workstation/default.nix b/src/system/machines/workstation/default.nix index 6e64b71..c71ec8a 100644 --- a/src/system/machines/workstation/default.nix +++ b/src/system/machines/workstation/default.nix @@ -3,6 +3,7 @@ { imports = [ ../../../user/config + ../../config ./hardware.nix ./system.nix ]; diff --git a/src/system/machines/workstation/system.nix b/src/system/machines/workstation/system.nix index 9e3463a..e26e5ea 100644 --- a/src/system/machines/workstation/system.nix +++ b/src/system/machines/workstation/system.nix @@ -10,7 +10,7 @@ with lib; extraGroups = config.user.groups ++ [ "video" "audio" "kvm" "libvirtd" "dialout" ]; openssh.authorizedKeys.keys = [ - "${config.user.keys.ssh.primary}" + "${config.user.keys.ssh.yubikey}" "${config.user.keys.ssh.work}" ]; }; diff --git a/src/system/machines/wsl/default.nix b/src/system/machines/wsl/default.nix index 97c4a4c..9af8cf1 100644 --- a/src/system/machines/wsl/default.nix +++ b/src/system/machines/wsl/default.nix @@ -3,6 +3,7 @@ { imports = [ ../../../user/config + ../../config ./system.nix ]; } diff --git a/src/system/machines/wsl/system.nix b/src/system/machines/wsl/system.nix index 89bb887..729213f 100644 --- a/src/system/machines/wsl/system.nix +++ b/src/system/machines/wsl/system.nix @@ -9,8 +9,7 @@ isNormalUser = true; extraGroups = config.user.groups; openssh.authorizedKeys.keys = [ - "${config.user.keys.ssh.primary}" - "${config.user.keys.ssh.windows}" + "${config.user.keys.ssh.yubikey}" ]; }; }; diff --git a/src/user/config/default.nix b/src/user/config/default.nix index 3740db7..b539c79 100644 --- a/src/user/config/default.nix +++ b/src/user/config/default.nix @@ -14,7 +14,7 @@ in name = "bryan"; email = "bryan@ramos.codes"; shell = bash; - keys = import ./keys; + keys = import ./keys { inherit lib; }; groups = [ "wheel" "networkmanager" "home-manager" "input" ]; bookmarks = import ./bookmarks; diff --git a/src/user/config/keys/age/README.md b/src/user/config/keys/age/README.md new file mode 100644 index 0000000..92284a8 --- /dev/null +++ b/src/user/config/keys/age/README.md @@ -0,0 +1,3 @@ +# Age Keys + +yubikey.pub.key - Cold storage backup for age encryption diff --git a/src/user/config/keys/age/yubikey.pub.key b/src/user/config/keys/age/yubikey.pub.key new file mode 100644 index 0000000..559bc52 --- /dev/null +++ b/src/user/config/keys/age/yubikey.pub.key @@ -0,0 +1 @@ +age1yubikey1qfapxqnnkh92zkgayzzm9n0gtpkwaqcvrzy4d4xa4rxnjua8vjhy72hh9r9 diff --git a/src/user/config/keys/default.nix b/src/user/config/keys/default.nix index 6808c06..e3f3aaf 100644 --- a/src/user/config/keys/default.nix +++ b/src/user/config/keys/default.nix @@ -1,13 +1,17 @@ +{ lib }: + with builtins; let - extractName = string: + extractName = filename: let - metadata = [ - "pub" "public" "priv" "private" - "key" "file" "." "_" "-" "pk" - ]; - in - replaceStrings metadata (builtins.map (_: "") metadata) string; + # Remove .key extension + noKey = lib.removeSuffix ".key" filename; + # Remove .pub/.priv/.public/.private markers + noMarkers = replaceStrings + [ ".pub" ".priv" ".public" ".private" ] + [ "" "" "" "" ] + noKey; + in noMarkers; constructKeys = dir: ( listToAttrs ( @@ -17,7 +21,10 @@ let map (file: { name = extractName file; value = readFile "${dir}/${subdir}/${file}"; - }) (filter (node: (readDir "${dir}/${subdir}").${node} == "regular") (attrNames (readDir "${dir}/${subdir}"))) + }) (filter (file: + (readDir "${dir}/${subdir}").${file} == "regular" && + lib.hasSuffix ".key" file + ) (attrNames (readDir "${dir}/${subdir}"))) ); }) (filter (node: (readDir dir).${node} == "directory") (attrNames (readDir dir))) ) diff --git a/src/user/config/keys/pgp/README.md b/src/user/config/keys/pgp/README.md new file mode 100644 index 0000000..50fb051 --- /dev/null +++ b/src/user/config/keys/pgp/README.md @@ -0,0 +1,5 @@ +# PGP Keys + +yubikey.pub.key - +work.pub.key -> bryan.ramos@concurrent-rt.com +ccur.pub.key -> ? diff --git a/src/user/config/keys/pgp/primary.pub.key b/src/user/config/keys/pgp/yubikey.pub.key similarity index 100% rename from src/user/config/keys/pgp/primary.pub.key rename to src/user/config/keys/pgp/yubikey.pub.key diff --git a/src/user/config/keys/ssh/README.md b/src/user/config/keys/ssh/README.md new file mode 100644 index 0000000..2ebbe16 --- /dev/null +++ b/src/user/config/keys/ssh/README.md @@ -0,0 +1,5 @@ +# SSH Keys + +yubikey.pub.key -> PGP derived from `pgp.yubikey.pub.key` +work.pub.key - ? +graphone.pub.key -> For Android `pass` diff --git a/src/user/config/keys/ssh/android.pub.key b/src/user/config/keys/ssh/graphone.pub.key similarity index 100% rename from src/user/config/keys/ssh/android.pub.key rename to src/user/config/keys/ssh/graphone.pub.key diff --git a/src/user/config/keys/ssh/primary.pub.key b/src/user/config/keys/ssh/yubikey.pub.key similarity index 100% rename from src/user/config/keys/ssh/primary.pub.key rename to src/user/config/keys/ssh/yubikey.pub.key diff --git a/src/user/modules/security/modules/gpg/default.nix b/src/user/modules/security/modules/gpg/default.nix index 79b5ec5..1751008 100644 --- a/src/user/modules/security/modules/gpg/default.nix +++ b/src/user/modules/security/modules/gpg/default.nix @@ -18,7 +18,7 @@ in }; publicKeys = [ { - text = "${config.user.keys.pgp.primary}"; + text = "${config.user.keys.pgp.yubikey}"; trust = 5; } ] ++ optionals (osConfig.networking.hostName == "workstation") [ From 91804d14070a96ebf4f1f0055ef79812a67327d2 Mon Sep 17 00:00:00 2001 From: Bryan Ramos Date: Thu, 12 Mar 2026 15:52:07 -0400 Subject: [PATCH 07/18] changed to weekly --- src/system/machines/server/system.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/system/machines/server/system.nix b/src/system/machines/server/system.nix index 8d289dd..36a4503 100644 --- a/src/system/machines/server/system.nix +++ b/src/system/machines/server/system.nix @@ -15,8 +15,8 @@ "${config.user.keys.age.yubikey}" "${config.machines.keys.desktop.ssh}" ]; - destination = "gdrive:backups/server"; # TODO: configure rclone remote - schedule = "daily"; + destination = "gdrive:backups/server"; + schedule = "weekly"; keepLast = 2; }; }; From b8b25478e92c862542511c673512d9eb23203a70 Mon Sep 17 00:00:00 2001 From: Bryan Ramos Date: Thu, 12 Mar 2026 16:00:55 -0400 Subject: [PATCH 08/18] fix --- src/system/modules/backup/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/system/modules/backup/default.nix b/src/system/modules/backup/default.nix index 834e024..1c5ccff 100644 --- a/src/system/modules/backup/default.nix +++ b/src/system/modules/backup/default.nix @@ -4,7 +4,7 @@ with lib; let cfg = config.modules.system.backup; - recipientArgs = concatMapStrings (r: "-r '${r}' ") cfg.recipients; + recipientArgs = concatMapStrings (r: "-r '${lib.strings.trim r}' ") cfg.recipients; # Convert absolute paths to relative for tar, preserving structure # e.g., /var/lib/forgejo -> var/lib/forgejo From bfad2975cd22162933f0ab236fc0cc082a039c10 Mon Sep 17 00:00:00 2001 From: Bryan Ramos Date: Thu, 12 Mar 2026 16:04:55 -0400 Subject: [PATCH 09/18] added age-plugin-yubikey --- src/system/modules/backup/default.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/src/system/modules/backup/default.nix b/src/system/modules/backup/default.nix index 1c5ccff..735fc68 100644 --- a/src/system/modules/backup/default.nix +++ b/src/system/modules/backup/default.nix @@ -21,6 +21,7 @@ let echo "Starting backup: $BACKUP_NAME" echo "Paths: ${concatStringsSep " " cfg.paths}" + export PATH="${pkgs.age-plugin-yubikey}/bin:$PATH" ${pkgs.gnutar}/bin/tar -C / -cf - ${concatStringsSep " " tarPaths} | \ ${pkgs.age}/bin/age ${recipientArgs} -o "$TEMP_DIR/$BACKUP_NAME" From 09d58fa5408e955164a2dab16a9e4502f5417811 Mon Sep 17 00:00:00 2001 From: Bryan Ramos Date: Thu, 12 Mar 2026 16:09:08 -0400 Subject: [PATCH 10/18] rebuild --- src/system/modules/backup/default.nix | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/system/modules/backup/default.nix b/src/system/modules/backup/default.nix index 735fc68..07a3895 100644 --- a/src/system/modules/backup/default.nix +++ b/src/system/modules/backup/default.nix @@ -25,14 +25,14 @@ let ${pkgs.gnutar}/bin/tar -C / -cf - ${concatStringsSep " " tarPaths} | \ ${pkgs.age}/bin/age ${recipientArgs} -o "$TEMP_DIR/$BACKUP_NAME" - ${pkgs.rclone}/bin/rclone copy "$TEMP_DIR/$BACKUP_NAME" "${cfg.destination}" + ${pkgs.rclone}/bin/rclone --config /root/.config/rclone/rclone.conf copy "$TEMP_DIR/$BACKUP_NAME" "${cfg.destination}" # Prune old backups - ${pkgs.rclone}/bin/rclone lsf "${cfg.destination}" | \ + ${pkgs.rclone}/bin/rclone --config /root/.config/rclone/rclone.conf lsf "${cfg.destination}" | \ sort -r | \ tail -n +$((${toString cfg.keepLast} + 1)) | \ while read -r old; do - ${pkgs.rclone}/bin/rclone delete "${cfg.destination}/$old" + ${pkgs.rclone}/bin/rclone --config /root/.config/rclone/rclone.conf delete "${cfg.destination}/$old" done echo "Backup complete" From adccda4d54be93dbd45e97bf59b3f24a54337fe1 Mon Sep 17 00:00:00 2001 From: Bryan Ramos Date: Thu, 12 Mar 2026 16:21:20 -0400 Subject: [PATCH 11/18] fixed malformed pubkeys --- src/user/config/keys/ssh/graphone.pub.key | 2 +- src/user/config/keys/ssh/yubikey.pub.key | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/user/config/keys/ssh/graphone.pub.key b/src/user/config/keys/ssh/graphone.pub.key index 190c93f..d07e510 100644 --- a/src/user/config/keys/ssh/graphone.pub.key +++ b/src/user/config/keys/ssh/graphone.pub.key @@ -1 +1 @@ -"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBJM1HutPcWXdeTaAXY7ha8SlgeZFtLJGwNa3Kd/DL/R38fq5+fkh3iCoHgv+iiKcordtVTMhbOsHhz3H+Jm274c=" +ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBJM1HutPcWXdeTaAXY7ha8SlgeZFtLJGwNa3Kd/DL/R38fq5+fkh3iCoHgv+iiKcordtVTMhbOsHhz3H+Jm274c= diff --git a/src/user/config/keys/ssh/yubikey.pub.key b/src/user/config/keys/ssh/yubikey.pub.key index d031f50..a840349 100644 --- a/src/user/config/keys/ssh/yubikey.pub.key +++ b/src/user/config/keys/ssh/yubikey.pub.key @@ -1 +1 @@ -"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDl4895aB9P5p/lp8Hq5rHun4clvhyTSHFi3U2d6OOBoW5Fm+VcQnW/xbjmCBsXk5BdiowsBxQhwnzdfz/KJL7J5RobomUEaVRwb9UwT88eJveLp14BG8j2J3SjfyhrCX+4jkPx0bPQk1HGcuYY+tPEXf1q/ps88Dhu0CARBIzYQOTYY6b1qWzxpDoFZGHjKG8g5iY6FIu65yKKvvVy1f8IgZ3l3IpwBWVamxgkTcYY0QYSrmzo1n7TXxwrWbvenAqBsQ0cBPs+gVa3uIr+1TJl0Az5SElBVGu3LvUdlk58trtPUj6TQR3YUkg7Vjll7WHOdqhux5ZQNhjkOsHerf0Tw86e6cEzgeTuIbQHIb0LcsUunwKcuh2+au7RO599cvHn0+xZE5MZBxloDDaJ3JsiliM8kyPP/U3ERj03cWLW7BqbT+sfjAOl21RCzk0iQxk1wt/8VmtCr9Adv7IyrtaYvf/bwRP+g+9ldmzKGt8Mdb605uVzZ70H/LLm17f40Te+QHaex5by/6p6cuwEEZtgIg53Wpglu0rA6UxrBfQEHKl/Jt3FLeE0mnEyYkkR2MnHNtyWRIXtuqYZMAm2Ub1pFHH7jQV1gGiDVTw6a2eIwK21a/hXtRjFUpFd1nB1n+KNfJBE4zT3wm3Ud7mKw/6rWnoRyhYZvGXkFdp+iEs49Q==" +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDl4895aB9P5p/lp8Hq5rHun4clvhyTSHFi3U2d6OOBoW5Fm+VcQnW/xbjmCBsXk5BdiowsBxQhwnzdfz/KJL7J5RobomUEaVRwb9UwT88eJveLp14BG8j2J3SjfyhrCX+4jkPx0bPQk1HGcuYY+tPEXf1q/ps88Dhu0CARBIzYQOTYY6b1qWzxpDoFZGHjKG8g5iY6FIu65yKKvvVy1f8IgZ3l3IpwBWVamxgkTcYY0QYSrmzo1n7TXxwrWbvenAqBsQ0cBPs+gVa3uIr+1TJl0Az5SElBVGu3LvUdlk58trtPUj6TQR3YUkg7Vjll7WHOdqhux5ZQNhjkOsHerf0Tw86e6cEzgeTuIbQHIb0LcsUunwKcuh2+au7RO599cvHn0+xZE5MZBxloDDaJ3JsiliM8kyPP/U3ERj03cWLW7BqbT+sfjAOl21RCzk0iQxk1wt/8VmtCr9Adv7IyrtaYvf/bwRP+g+9ldmzKGt8Mdb605uVzZ70H/LLm17f40Te+QHaex5by/6p6cuwEEZtgIg53Wpglu0rA6UxrBfQEHKl/Jt3FLeE0mnEyYkkR2MnHNtyWRIXtuqYZMAm2Ub1pFHH7jQV1gGiDVTw6a2eIwK21a/hXtRjFUpFd1nB1n+KNfJBE4zT3wm3Ud7mKw/6rWnoRyhYZvGXkFdp+iEs49Q== From bb0f973aa18e54e35e8d24cc1c9f0397bc6db967 Mon Sep 17 00:00:00 2001 From: Bryan Ramos Date: Thu, 12 Mar 2026 16:27:07 -0400 Subject: [PATCH 12/18] removed tomb --- src/user/modules/security/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/user/modules/security/default.nix b/src/user/modules/security/default.nix index 7f8a286..4b07f68 100644 --- a/src/user/modules/security/default.nix +++ b/src/user/modules/security/default.nix @@ -7,7 +7,7 @@ let pass-audit pass-otp pass-update - pass-tomb + #pass-tomb ]); in From e3a031753a60fa6fc5038811ab6716b26799e3bd Mon Sep 17 00:00:00 2001 From: Bryan Ramos Date: Thu, 12 Mar 2026 16:51:58 -0400 Subject: [PATCH 13/18] http auth --- src/system/modules/forgejo/default.nix | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/system/modules/forgejo/default.nix b/src/system/modules/forgejo/default.nix index ed6b461..8732e7a 100644 --- a/src/system/modules/forgejo/default.nix +++ b/src/system/modules/forgejo/default.nix @@ -65,6 +65,10 @@ in admin = { DISABLE_REGULAR_ORG_CREATION = true; }; + + "auth" = { + ENABLE_BASIC_AUTHENTICATION = true; + }; }; database = { From fb0bc5666a80b2d8670bb8924cfeace915c6891e Mon Sep 17 00:00:00 2001 From: Bryan Ramos Date: Thu, 12 Mar 2026 16:54:52 -0400 Subject: [PATCH 14/18] fix --- src/system/modules/forgejo/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/system/modules/forgejo/default.nix b/src/system/modules/forgejo/default.nix index 8732e7a..7c04407 100644 --- a/src/system/modules/forgejo/default.nix +++ b/src/system/modules/forgejo/default.nix @@ -66,7 +66,7 @@ in DISABLE_REGULAR_ORG_CREATION = true; }; - "auth" = { + auth = { ENABLE_BASIC_AUTHENTICATION = true; }; }; From a36841f12f74f80162241cbb59f6d08e92421452 Mon Sep 17 00:00:00 2001 From: Bryan Ramos Date: Thu, 12 Mar 2026 17:25:04 -0400 Subject: [PATCH 15/18] dnsmasq --- src/system/machines/desktop/system.nix | 15 +-------------- src/system/machines/server/system.nix | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/system/machines/desktop/system.nix b/src/system/machines/desktop/system.nix index e09b06b..ba97169 100644 --- a/src/system/machines/desktop/system.nix +++ b/src/system/machines/desktop/system.nix @@ -94,20 +94,7 @@ in enable = true; allowedTCPPorts = [ 22 80 443 ]; }; - nameservers = [ "127.0.0.1" ]; - }; - - services.dnsmasq = { - enable = true; - settings = { - # Only specific subdomains go to local server - address = [ - "/git.ramos.codes/192.168.0.154" - "/frigate.ramos.codes/192.168.0.154" - "/test.ramos.codes/192.168.0.154" - ]; - server = [ "1.1.1.1" "8.8.8.8" ]; - }; + nameservers = [ "192.168.0.154" ]; }; services = { diff --git a/src/system/machines/server/system.nix b/src/system/machines/server/system.nix index 36a4503..da10a7a 100644 --- a/src/system/machines/server/system.nix +++ b/src/system/machines/server/system.nix @@ -109,6 +109,23 @@ }; }; + services.dnsmasq = { + enable = true; + settings = { + # All *.ramos.codes subdomains -> local server + address = "/.ramos.codes/192.168.0.154"; + # Except www -> forward to upstream + server = [ + "/www.ramos.codes/1.1.1.1" + "1.1.1.1" + "8.8.8.8" + ]; + cache-size = 1000; + }; + }; + + networking.firewall.allowedUDPPorts = [ 53 ]; + services.fail2ban = { enable = true; maxretry = 5; From 37ebd2d6b6b29fbaae85d3201f1b48b319b91ca9 Mon Sep 17 00:00:00 2001 From: Bryan Ramos Date: Thu, 12 Mar 2026 19:21:38 -0400 Subject: [PATCH 16/18] more dns --- src/system/machines/server/system.nix | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/system/machines/server/system.nix b/src/system/machines/server/system.nix index da10a7a..a52d6e4 100644 --- a/src/system/machines/server/system.nix +++ b/src/system/machines/server/system.nix @@ -114,9 +114,12 @@ settings = { # All *.ramos.codes subdomains -> local server address = "/.ramos.codes/192.168.0.154"; - # Except www -> forward to upstream + # Except www, http, https and bare domain -> forward to upstream server = [ "/www.ramos.codes/1.1.1.1" + "/http.ramos.codes/1.1.1.1" + "/https.ramos.codes/1.1.1.1" + "/ramos.codes/1.1.1.1" "1.1.1.1" "8.8.8.8" ]; From cf4cf866c91309d344a5d7432e0f5b4003a98b07 Mon Sep 17 00:00:00 2001 From: Bryan Ramos Date: Thu, 12 Mar 2026 19:48:38 -0400 Subject: [PATCH 17/18] immich init --- src/system/machines/server/system.nix | 4 ++- src/system/modules/immich/default.nix | 39 +++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 src/system/modules/immich/default.nix diff --git a/src/system/machines/server/system.nix b/src/system/machines/server/system.nix index a52d6e4..5dad7cf 100644 --- a/src/system/machines/server/system.nix +++ b/src/system/machines/server/system.nix @@ -8,6 +8,7 @@ nginx.enable = true; forgejo.enable = true; frigate.enable = false; + immich.enable = true; backup = { enable = true; @@ -15,8 +16,9 @@ "${config.user.keys.age.yubikey}" "${config.machines.keys.desktop.ssh}" ]; + paths = [ "/root/.config/rclone" ]; destination = "gdrive:backups/server"; - schedule = "weekly"; + schedule = "daily"; keepLast = 2; }; }; diff --git a/src/system/modules/immich/default.nix b/src/system/modules/immich/default.nix new file mode 100644 index 0000000..6a32160 --- /dev/null +++ b/src/system/modules/immich/default.nix @@ -0,0 +1,39 @@ +{ pkgs, lib, config, ... }: + +with lib; +let + cfg = config.modules.system.immich; + nginx = config.modules.system.nginx; + domain = "ramos.codes"; + port = 2283; + +in +{ + options.modules.system.immich = { + enable = mkEnableOption "Immich Photo Server"; + }; + + config = mkIf cfg.enable { + services.immich = { + enable = true; + port = port; + host = "127.0.0.1"; + mediaLocation = "/var/lib/immich"; + machine-learning.enable = false; + }; + + modules.system.backup.paths = [ + "/var/lib/immich" + ]; + + services.nginx.virtualHosts."photos.${domain}" = mkIf nginx.enable { + useACMEHost = domain; + forceSSL = true; + clientMaxBodySize = "50G"; + locations."/" = { + proxyPass = "http://127.0.0.1:${toString port}"; + proxyWebsockets = true; + }; + }; + }; +} From cf9b8b1951e998fe8b333a53404233a3c8954924 Mon Sep 17 00:00:00 2001 From: Bryan Ramos Date: Thu, 12 Mar 2026 19:49:07 -0400 Subject: [PATCH 18/18] fix --- src/system/modules/immich/default.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/src/system/modules/immich/default.nix b/src/system/modules/immich/default.nix index 6a32160..7ea2c54 100644 --- a/src/system/modules/immich/default.nix +++ b/src/system/modules/immich/default.nix @@ -29,7 +29,6 @@ in services.nginx.virtualHosts."photos.${domain}" = mkIf nginx.enable { useACMEHost = domain; forceSSL = true; - clientMaxBodySize = "50G"; locations."/" = { proxyPass = "http://127.0.0.1:${toString port}"; proxyWebsockets = true;