{ config, pkgs, ... }: { imports = [ ../hardware-configuration.nix ]; # === System Packages === environment.systemPackages = with pkgs; [ # Core development tools qmd nodejs bun git zsh curl wget # System utilities htop fastfetch ripgrep fd jq tree tmux unzip neovim # SSH essentials openssh mosh # SMB/CIFS mount support cifs-utils mount-truenas-shared ]; # === Network Shares === # TrueNAS "Shared" volume — tries LAN IP first, falls back to Tailscale # Credentials stored at /etc/nixos/smb-credentials (NOT in repo) systemd.tmpfiles.rules = [ "d /mnt/shared 0755 root root -" ]; systemd.services.mount-truenas-shared = { description = "Mount TrueNAS Shared SMB volume"; after = [ "network-online.target" "tailscaled.service" ]; wants = [ "network-online.target" ]; wantedBy = [ "multi-user.target" ]; serviceConfig = { Type = "oneshot"; RemainAfterExit = true; ExecStart = "${pkgs.mount-truenas-shared}/bin/mount-truenas-shared"; ExecStop = "${pkgs.mount-truenas-shared}/bin/mount-truenas-shared umount"; }; }; nixpkgs.overlays = [ (final: prev: { mount-truenas-shared = prev.writeShellScriptBin "mount-truenas-shared" '' set -o pipefail SHARE="Shared" MOUNTPOINT="/mnt/shared" CREDENTIALS="/etc/nixos/smb-credentials" MOUNT_OPTS="credentials=$CREDENTIALS,vers=3.0,uid=1000,gid=100,nodfs,noperm,iocharset=utf8,file_mode=0644,dir_mode=0755" LAN_IP="192.168.168.93" TAILSCALE_IP="100.70.3.101" # Already mounted? if grep -qs "$MOUNTPOINT" /proc/mounts; then exit 0 fi # Find a reachable NAS SERVER="" timeout 2 bash -c "/dev/null && SERVER="$LAN_IP" if [ -z "$SERVER" ]; then timeout 2 bash -c "/dev/null && SERVER="$TAILSCALE_IP" fi CMD="''${1:-mount}" case "$CMD" in mount) if [ -z "$SERVER" ]; then echo "No NAS reachable (tried $LAN_IP and $TAILSCALE_IP) — mount deferred" exit 0 fi echo "Mounting $SHARE from $SERVER..." mount -t cifs "//$SERVER/$SHARE" "$MOUNTPOINT" -o "$MOUNT_OPTS" ;; umount) if grep -qs "$MOUNTPOINT" /proc/mounts; then umount "$MOUNTPOINT" fi ;; esac ''; }) ]; # === Shell === programs.zsh = { enable = true; autosuggestions.enable = true; syntaxHighlighting.enable = true; shellAliases = { ll = "ls -la"; la = "ls -A"; l = "ls -CF"; nix-rebuild = "sudo nixos-rebuild switch --flake ~/laptop-config#laptop"; nix-clean = "sudo nix-collect-garbage -d && nix-collect-garbage -d"; vault-search = "qmd query"; pi-run = "pi"; }; ohMyZsh = { enable = true; plugins = [ "git" "node" "npm" "ssh-agent" "sudo" "history" ]; theme = "robbyrussell"; }; }; # Default to zsh users.defaultUserShell = pkgs.zsh; # === SSH === programs.ssh = { startAgent = true; extraConfig = '' Host n97-mini HostName 192.168.168.41 User sscoble ForwardAgent yes IdentityFile ~/.ssh/id_ed25519 Host n97-mini-ext HostName os.scoble.me Port 22 User sscoble ForwardAgent yes IdentityFile ~/.ssh/id_ed25519 Host forgejo HostName os.scoble.me User git IdentityFile ~/.ssh/id_ed25519 ''; }; # === Fonts (for pi TUI) === fonts.packages = with pkgs; [ nerd-fonts.jetbrains-mono nerd-fonts.fira-code ]; # === Nix Settings === nix = { settings = { experimental-features = [ "nix-command" "flakes" ]; auto-optimise-store = true; }; gc = { automatic = true; dates = "weekly"; options = "--delete-older-than 30d"; }; }; # === User === users.users.sscoble = { isNormalUser = true; description = "Scott Scoble"; extraGroups = [ "networkmanager" "wheel" "docker" ]; shell = pkgs.zsh; packages = with pkgs; [ neovim tmux ripgrep fd bat eza delta ]; }; # === Locale === time.timeZone = "America/Los_Angeles"; i18n.defaultLocale = "en_US.UTF-8"; # === Boot === boot.loader.systemd-boot.enable = true; boot.loader.efi.canTouchEfiVariables = true; } # === SSH Server === services.openssh = { enable = true; settings.PasswordAuthentication = false; openFirewall = true; };