aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--flake.nix2
-rw-r--r--home/profiles/eza.nix4
-rw-r--r--home/profiles/kitty.nix8
-rw-r--r--home/profiles/minimal.nix1
-rw-r--r--home/profiles/restic.nix197
-rw-r--r--home/profiles/ssh.nix8
-rw-r--r--justfile1
-rw-r--r--machines/mba-m2.nix1
-rw-r--r--machines/rivendell.nix88
-rw-r--r--profiles/defaults.nix5
-rw-r--r--profiles/storage-media.nix61
-rw-r--r--profiles/users/fcuny.nix2
-rw-r--r--secrets/rsync-ssh-nas.agebin0 -> 721 bytes
-rw-r--r--secrets/secrets.nix6
14 files changed, 329 insertions, 55 deletions
diff --git a/flake.nix b/flake.nix
index ec2f077..f6a9b91 100644
--- a/flake.nix
+++ b/flake.nix
@@ -155,7 +155,7 @@
};
modules = [
{
- system.configurationRevision = nixpkgs.lib.mkIf (self ? rev) self.rev;
+ system.configurationRevision = self.rev or self.dirtyRev or null;
system.nixos.versionSuffix = nixpkgs.lib.mkForce "git.${builtins.substring 0 11 nixpkgs.rev}";
nixpkgs.pkgs = pkgs;
environment.systemPackages = [ pkgs.git ];
diff --git a/home/profiles/eza.nix b/home/profiles/eza.nix
index f71b9b6..0952201 100644
--- a/home/profiles/eza.nix
+++ b/home/profiles/eza.nix
@@ -2,15 +2,15 @@
{
programs.eza = {
enable = true;
- icons = "never";
+ icons = "auto";
colors = "always";
git = true;
+ # I setup my own aliases
enableFishIntegration = false;
extraOptions = [
"--group-directories-first"
"--no-quotes"
"--git-ignore"
- "--icons=never"
];
};
diff --git a/home/profiles/kitty.nix b/home/profiles/kitty.nix
index f5fceeb..8bfcf0c 100644
--- a/home/profiles/kitty.nix
+++ b/home/profiles/kitty.nix
@@ -5,9 +5,13 @@
themeFile = "Modus_Operandi_Tinted";
settings = {
copy_on_select = "yes";
+ bold_font = "auto";
+ italic_font = "auto";
+ bold_italic_font = "auto";
+ window_padding_width = "3 10";
enable_audio_bell = "no";
- window_padding_width = 5;
- tab_title_template = "{index}{title}";
+ tab_bar_edge = "bottom";
+ tab_title_template = "{title}{' :{}:'.format(num_windows) if num_windows > 1 else ''}";
tab_bar_style = "powerline";
font_family = "Source Code Pro";
font_size = "15.0";
diff --git a/home/profiles/minimal.nix b/home/profiles/minimal.nix
index ac0d84f..4bccdb5 100644
--- a/home/profiles/minimal.nix
+++ b/home/profiles/minimal.nix
@@ -8,6 +8,7 @@ in
];
programs.bat.enable = true;
+ programs.tmux.enable = true;
home.homeDirectory = "/home/${username}";
home.stateVersion = "25.05";
diff --git a/home/profiles/restic.nix b/home/profiles/restic.nix
new file mode 100644
index 0000000..96ae8d4
--- /dev/null
+++ b/home/profiles/restic.nix
@@ -0,0 +1,197 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+
+let
+ nasHost = "nas";
+ repoPath = "/backups/workstation";
+
+ resticRepository = "sftp:${nasHost}:${repoPath}";
+
+ backupPaths = [
+ "${config.home.homeDirectory}/Documents"
+ "${config.home.homeDirectory}/Pictures"
+ ];
+
+ excludeFile = "${config.home.homeDirectory}/.config/restic/exclude";
+ includeFile = "${config.home.homeDirectory}/.config/restic/includes";
+in
+{
+ home.packages = with pkgs; [ restic ];
+
+ age.secrets.restic-password = {
+ file = ../../secrets/restic-pw.age;
+ path = "${config.home.homeDirectory}/.config/restic/password";
+ mode = "400";
+ };
+
+ home.sessionVariables = {
+ RESTIC_REPOSITORY = resticRepository;
+ RESTIC_PASSWORD_FILE = config.age.secrets.restic-password.path;
+ };
+
+ home.file.".config/restic/includes" = {
+ text = lib.concatStringsSep "\n" backupPaths;
+ onChange = ''
+ echo "Restic backup paths updated"
+ '';
+ };
+
+ home.file.".config/restic/exclude" = {
+ text = ''
+ # macOS specific
+ .DS_Store
+ .Trash
+ .Spotlight-V100
+ .fseventsd
+ .TemporaryItems
+ .DocumentRevisions-V100
+ .VolumeIcon.icns
+ .AppleDouble
+ .LSOverride
+ Library/Caches
+ Library/Logs
+
+ # Development artifacts
+ **/node_modules
+ **/.venv
+ **/__pycache__
+ **/*.pyc
+ **/venv
+ **/target # Rust
+ **/dist
+ **/build
+ **/.tox
+ **/.pytest_cache
+ **/.coverage
+ **/.mypy_cache
+
+ # Large files that might not need backup
+ *.dmg
+ *.iso
+ *.pkg
+
+ # Version control
+ **/.git/objects
+ **/.git/lfs
+
+ # IDE
+ **/.idea
+ **/.vscode
+ *.swp
+ *~
+ '';
+ };
+
+ home.file.".local/bin/restic-now" = {
+ executable = true;
+ text = ''
+ #!/usr/bin/env bash
+ set -euo pipefail
+
+ # Colors for output
+ RED='\033[0;31m'
+ GREEN='\033[0;32m'
+ YELLOW='\033[1;33m'
+ NC='\033[0m' # No Color
+
+ echo -e "''${GREEN}Starting restic backup...''${NC}"
+
+ # Check if repository exists, initialize if not
+ echo -e "''${YELLOW}Checking repository...''${NC}"
+ if ! ${pkgs.restic}/bin/restic cat config > /dev/null 2>&1; then
+ echo -e "''${YELLOW}Repository not found. Initializing...''${NC}"
+ ${pkgs.restic}/bin/restic init
+ fi
+
+ # Run backup
+ echo -e "''${GREEN}Running backup...''${NC}"
+ ${pkgs.restic}/bin/restic backup \
+ --compression max \
+ --files-from="${includeFile}" \
+ --exclude-file="${excludeFile}" \
+ --verbose=1 \
+ --host="$(hostname -s)"
+
+ # Unlock in case of stale locks
+ echo -e "''${YELLOW}Checking for stale locks...''${NC}"
+ ${pkgs.restic}/bin/restic unlock || true
+
+ # Prune old snapshots
+ echo -e "''${GREEN}Pruning old snapshots...''${NC}"
+ ${pkgs.restic}/bin/restic forget \
+ --prune \
+ --keep-daily=7 \
+ --keep-weekly=4 \
+ --keep-monthly=12 \
+ --compression max \
+ --verbose=1
+
+ # Check repository integrity (optional, can be slow)
+ echo -e "''${GREEN}Checking repository integrity...''${NC}"
+ ${pkgs.restic}/bin/restic check --read-data-subset=5%
+
+ echo -e "''${GREEN}Backup completed successfully!''${NC}"
+ '';
+ };
+
+ home.file.".local/bin/restic-status" = {
+ executable = true;
+ text = ''
+ #!/usr/bin/env bash
+ set -euo pipefail
+
+ echo "Repository: $RESTIC_REPOSITORY"
+ echo ""
+ echo "=== Latest snapshots ==="
+ ${pkgs.restic}/bin/restic snapshots --latest 5 --compact
+ echo ""
+ echo "=== Repository stats ==="
+ ${pkgs.restic}/bin/restic stats
+ '';
+ };
+
+ home.file.".local/bin/restic-mount" = {
+ executable = true;
+ text = ''
+ #!/usr/bin/env bash
+ set -euo pipefail
+
+ MOUNT_POINT="''${1:-$HOME/mnt/restic}"
+
+ if [ ! -d "$MOUNT_POINT" ]; then
+ echo "Creating mount point: $MOUNT_POINT"
+ mkdir -p "$MOUNT_POINT"
+ fi
+
+ echo "Mounting restic repository at $MOUNT_POINT"
+ echo "Press Ctrl+C to unmount"
+ ${pkgs.restic}/bin/restic mount "$MOUNT_POINT"
+ '';
+ };
+
+ home.file.".local/bin/restic-restore" = {
+ executable = true;
+ text = ''
+ #!/usr/bin/env bash
+ set -euo pipefail
+
+ if [ $# -lt 1 ]; then
+ echo "Usage: $0 <snapshot-id> [target-directory]"
+ echo ""
+ echo "Available snapshots:"
+ ${pkgs.restic}/bin/restic snapshots --compact
+ exit 1
+ fi
+
+ SNAPSHOT="$1"
+ TARGET="''${2:-$HOME/restic-restore}"
+
+ echo "Restoring snapshot $SNAPSHOT to $TARGET"
+ ${pkgs.restic}/bin/restic restore "$SNAPSHOT" --target "$TARGET"
+ '';
+ };
+}
diff --git a/home/profiles/ssh.nix b/home/profiles/ssh.nix
index f1ef16f..004b082 100644
--- a/home/profiles/ssh.nix
+++ b/home/profiles/ssh.nix
@@ -14,6 +14,14 @@
"rivendell" = {
hostname = "192.168.1.114";
};
+ "riv-unlock" = {
+ hostname = "192.168.1.114";
+ user = "root";
+ port = 911;
+ };
+ "nas" = {
+ hostname = "192.168.1.68";
+ };
"bree" = {
hostname = "192.168.1.50";
};
diff --git a/justfile b/justfile
index 81bf05f..7f62818 100644
--- a/justfile
+++ b/justfile
@@ -42,6 +42,7 @@ rbuild hostname:
[group('linux')]
rswitch hostname:
@echo "switching {{hostname}} to new config..."
+ nixos-rebuild switch --keep-going --flake ".#{{hostname}}" --target-host {{hostname}} --fast --use-remote-sudo --use-substitutes
# sync agenix key from 1password
[group('secrets')]
diff --git a/machines/mba-m2.nix b/machines/mba-m2.nix
index 398bf6d..e9fd500 100644
--- a/machines/mba-m2.nix
+++ b/machines/mba-m2.nix
@@ -43,6 +43,7 @@
../home/profiles/mac.nix
../home/profiles/media.nix
../home/profiles/security.nix
+ ../home/profiles/restic.nix
];
userinfo = {
email = "franck@fcuny.net";
diff --git a/machines/rivendell.nix b/machines/rivendell.nix
index 4940ea3..83dcb2e 100644
--- a/machines/rivendell.nix
+++ b/machines/rivendell.nix
@@ -13,6 +13,7 @@
../profiles/remote-unlock.nix
../profiles/restic-backup.nix
../profiles/server.nix
+ ../profiles/storage-media.nix
../profiles/users/builder.nix
../profiles/users/fcuny.nix
../profiles/wireguard.nix
@@ -23,56 +24,51 @@
networking.useDHCP = lib.mkDefault true;
systemd.network.wait-online.anyInterface = lib.mkDefault config.networking.useDHCP;
- services.website = {
- enable = true;
- openFirewall = true;
- };
-
- services.restic.backups.local.paths = [ "/var/lib/gitolite/repositories" ];
- services.restic.backups.synology.paths = [
- "/data/archives"
- "/data/media"
- "/var/lib/gitolite/repositories"
- ];
-
- services.samba = {
- enable = true;
- openFirewall = true;
- settings = {
- global = {
- security = "user";
- workgroup = "WORKGROUP";
- "server string" = config.networking.hostName;
- "netbios name" = config.networking.hostName;
- "hosts allow" = "192.168.1.0/24 10.100.0.0/24 localhost";
- "guest account" = "nobody";
- "map to guest" = "bad user";
- "use sendfile" = "yes";
- "load printers" = "no";
- "vfs objects" = "catia fruit streams_xattr";
- "fruit:metadata" = "stream";
- };
+ services = {
+ website = {
+ enable = true;
+ openFirewall = true;
+ };
+ restic.backups.local.paths = [ "/var/lib/gitolite/repositories" ];
+ restic.backups.synology.paths = [
+ "/data/archives"
+ "/data/media/music"
+ "/var/lib/gitolite/repositories"
+ ];
+ samba = {
+ enable = true;
+ openFirewall = true;
+ settings = {
+ global = {
+ security = "user";
+ workgroup = "WORKGROUP";
+ "server string" = config.networking.hostName;
+ "netbios name" = config.networking.hostName;
+ "hosts allow" = "192.168.1.0/24 10.100.0.0/24 localhost";
+ "guest account" = "nobody";
+ "map to guest" = "bad user";
+ "use sendfile" = "yes";
+ "load printers" = "no";
+ "vfs objects" = "catia fruit streams_xattr";
+ "fruit:metadata" = "stream";
+ };
- media = {
- path = "/data/media";
- browseable = "yes";
- "read only" = "yes";
- "guest ok" = "yes";
+ media = {
+ path = "/data/media";
+ browseable = "yes";
+ "read only" = "yes";
+ "guest ok" = "yes";
+ };
};
};
+ avahi = {
+ enable = true;
+ nssmdns4 = true;
+ openFirewall = true;
+ };
};
- services.avahi = {
- enable = true;
- nssmdns4 = true;
- openFirewall = true;
- };
-
- system.stateVersion = "23.11"; # Did you read the comment?
+ system.stateVersion = "23.11";
- home-manager.users.fcuny = {
- imports = [
- ../home/profiles/minimal.nix
- ];
- };
+ home-manager.users.fcuny.imports = [ ../home/profiles/minimal.nix ];
}
diff --git a/profiles/defaults.nix b/profiles/defaults.nix
index d98daa0..6ada4c7 100644
--- a/profiles/defaults.nix
+++ b/profiles/defaults.nix
@@ -1,5 +1,4 @@
{
- self,
config,
pkgs,
lib,
@@ -100,8 +99,8 @@
environment.etc.motd.text = ''
Machine ${config.networking.hostName}
- NixOS ${config.system.nixos.release}
- @ ${self.shortRev or self.dirtyShortRev}
+ NixOS ${config.system.nixos.versionSuffix}
+ @ ${config.system.configurationRevision}
'';
## disable that slow "building man-cache" step
diff --git a/profiles/storage-media.nix b/profiles/storage-media.nix
new file mode 100644
index 0000000..30fb9e4
--- /dev/null
+++ b/profiles/storage-media.nix
@@ -0,0 +1,61 @@
+{ pkgs, config, ... }:
+let
+ syncJobs = [
+ {
+ name = "movies";
+ source = "/data/media/movies/";
+ destination = "/volume1/media/movies/";
+ }
+ {
+ name = "videos";
+ source = "/data/media/videos/";
+ destination = "/volume1/media/videos/";
+ }
+ ];
+ remoteHost = "192.168.1.68";
+ remoteUser = "nas";
+in
+{
+ age.secrets.rsync-ssh-key.file = ../secrets/rsync-ssh-nas.age;
+
+ systemd.timers = pkgs.lib.listToAttrs (
+ map (job: {
+ name = "rsync-backup-${job.name}";
+ value = {
+ wantedBy = [ "timers.target" ];
+ timerConfig = {
+ OnCalendar = "daily";
+ Persistent = true;
+ RandomizedDelaySec = "1h";
+ };
+ };
+ }) syncJobs
+ );
+
+ systemd.services = pkgs.lib.listToAttrs (
+ map (job: {
+ name = "rsync-backup-${job.name}";
+ value = {
+ description = "Rsync backup for ${job.name}";
+
+ serviceConfig = {
+ Type = "oneshot";
+ DynamicUser = true;
+ LoadCredential = "ssh-key:${config.age.secrets.rsync-ssh-key.path}";
+ PrivateTmp = true;
+ NoNewPrivileges = true;
+ ProtectSystem = "strict";
+ ProtectHome = true;
+
+ ExecStart = pkgs.writeShellScript "rsync-backup-${job.name}" ''
+ ${pkgs.rsync}/bin/rsync \
+ -avz \
+ -e "${pkgs.openssh}/bin/ssh -i ''${CREDENTIALS_DIRECTORY}/ssh-key -o StrictHostKeyChecking=accept-new" \
+ ${job.source} \
+ ${remoteUser}@${remoteHost}:${job.destination}
+ '';
+ };
+ };
+ }) syncJobs
+ );
+}
diff --git a/profiles/users/fcuny.nix b/profiles/users/fcuny.nix
index 1a2b490..9d4e1e2 100644
--- a/profiles/users/fcuny.nix
+++ b/profiles/users/fcuny.nix
@@ -5,7 +5,7 @@
uid = 1000;
shell = pkgs.fish;
isNormalUser = true;
- hashedPassword = "$6$Llw8m62nKMLLN9mm$3.a4CKUFlqwkG8vjBryLlBNwTwgH63vpg2nhYwRoQzG76Q91vTXnlYDujS4G5yGrWoatkKZx5epCx4/NAvRh2/";
+ hashedPassword = "$y$j9T$U3mXpCzXC1VUp8wV5snJz/$32vTk0KwVXvP/jLO13nMlGPHy0nCe4ZtebdvqU4hwmD";
openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINBkozy+X96u5ciX766bJ/AyQ3xm1tXZTIr5+4PVFZFi"
];
diff --git a/secrets/rsync-ssh-nas.age b/secrets/rsync-ssh-nas.age
new file mode 100644
index 0000000..b71e4ca
--- /dev/null
+++ b/secrets/rsync-ssh-nas.age
Binary files differ
diff --git a/secrets/secrets.nix b/secrets/secrets.nix
index 155a88b..adb15e1 100644
--- a/secrets/secrets.nix
+++ b/secrets/secrets.nix
@@ -25,6 +25,12 @@ in
hosts.rivendell
];
+ # ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINE3mdcVS7+DPr7MZzIh3JsuI5t4z83j7ZAdAYxFLW4S rsync-nas
+ "rsync-ssh-nas.age".publicKeys = [
+ users.fcuny
+ hosts.rivendell
+ ];
+
# this is the SSH key we use to access the remote builder.
"ssh-remote-builder.age".publicKeys = [
users.fcuny