{ description = "Stationette nix config"; inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixos-25.11"; nixpkgs-unstable.url = "github:nixos/nixpkgs/nixos-unstable"; disko.url = "github:nix-community/disko/latest"; impermanence.url = "github:nix-community/impermanence"; home-manager = { url = "github:nix-community/home-manager/release-25.11"; inputs.nixpkgs.follows = "nixpkgs"; }; firefox-addons = { url = "gitlab:rycee/nur-expressions?dir=pkgs/firefox-addons"; inputs.nixpkgs.follows = "nixpkgs"; }; try-cli.url = "github:tobi/try-cli"; elephant.url = "github:abenz1267/elephant"; }; outputs = { self, nixpkgs, nixpkgs-unstable, impermanence, disko, home-manager, try-cli, elephant, ... } @ inputs: let lib = nixpkgs.lib; system = "x86_64-linux"; pkgs = nixpkgs.legacyPackages.${system}; pkgs-unstable = nixpkgs-unstable.legacyPackages.${system}; in { nixosConfigurations = { stationette = nixpkgs.lib.nixosSystem { modules = [ ./hardware-configuration.nix disko.nixosModules.disko impermanence.nixosModules.impermanence home-manager.nixosModules.home-manager { # nix --extra-experimental-features "nix-command flakes" run github:nix-community/disko/latest#disko-install -- --flake ./#stationette --disk stationette --write-efi-boot-entries /dev/sda disko.devices = { disk = { stationette = { type = "disk"; device = "/dev/sda"; # Check this with lsblk content = { type = "gpt"; partitions = { ESP = { size = "512M"; type = "EF00"; content = { type = "filesystem"; format = "vfat"; mountpoint = "/boot"; mountOptions = [ "fmask=0022" "dmask=0022" "umask=0077" ]; }; }; root = { size = "100%"; content = { type = "btrfs"; extraArgs = [ "-f" ]; # Force overwrite subvolumes = { "/root" = { mountpoint = "/"; mountOptions = [ "compress=zstd" "noatime" ]; }; "/nix" = { mountpoint = "/nix"; mountOptions = [ "compress=zstd" "noatime" ]; }; "/persist" = { mountpoint = "/persist"; mountOptions = [ "compress=zstd" "noatime" ]; }; "/swap" = { mountpoint = "/.swapvol"; swap.swapfile.size = "8G"; }; }; }; }; }; }; }; }; }; boot.loader = { systemd-boot.enable = true; efi.canTouchEfiVariables = true; }; environment = { persistence."/persist" = { hideMounts = true; directories = [ "/var/log" "/var/lib/bluetooth" "/var/lib/networkmanager" "/var/lib/nixos" "/etc/ssh" "/var/lib/systemd/coredump" "/etc/NetworkManager/system-connections" ]; files = [ "/etc/machine-id" ]; }; systemPackages = with pkgs; [ hyprpaper libnotify mako qt6.qtwayland hypridle hyprlock hyprpicker wlogout wl-clipboard waybar bat highlight btop eza fzf neovim ripgrep tldr unzip openssl wget zip zoxide jq git lazygit less tree tmux tmuxinator wget zenity gum pkgs-unstable.yazi rsync p7zip impala xdg-terminal-exec ]; }; networking = { hostName = "stationette"; networkmanager.enable = true; wireless = { iwd.enable = true; networks = { ssid = "Outskirt Stable"; psk = "SidonPhlegm"; }; }; firewall = { enable = true; allowedTCPPorts = [ 53317 ]; allowedUDPPorts = [ 53317 ]; # Optional: Extra commands for specific DNS rules extraCommands = '' ip46tables -A INPUT -p udp -s 172.16.0.0/12 -d 172.17.0.1 --dport 53 -m comment --comment "allow-docker-dns" -j ACCEPT ''; }; }; users.users.chris = { uid = 1000; isNormalUser = true; initialPassword = "changeme123"; shell = pkgs.zsh; extraGroups = [ "chris" "wheel" "networkmanager" ]; }; nixpkgs.config.allowUnfree = true; programs = { zsh = { enable = true; }; hyprland = { enable = true; package = pkgs-unstable.hyprland; xwayland.enable = true; }; steam = { enable = true; remotePlay.openFirewall = true; # Open ports in the firewall for Steam Remote Play dedicatedServer.openFirewall = true; # Open ports in the firewall for Source Dedicated Server localNetworkGameTransfers.openFirewall = true; # Open ports in the firewall for Steam Local Network Game Transfers }; }; services = { openssh.enable = true; dbus.enable = true; envfs.enable = true; # This ensures normal shebangs work (#!/bin/bash) expressvpn.enable = true; locate.enable = true; displayManager = { sddm = { enable = true; wayland.enable = true; theme = "maya"; }; autoLogin.enable = true; autoLogin.user = "chris"; defaultSession = "hyprland"; }; }; system.stateVersion = "25.11"; home-manager = { users.chris = { pkgs, lib, ... }: { home = { file.".mozilla/firefox/default/search.json.mozlz4".force = lib.mkForce true; username = "chris"; homeDirectory = "/home/chris"; enableNixpkgsReleaseCheck = false; stateVersion = "25.11"; persistence."/persist" = { directories = [ "Downloads" "Tower" "Code" ".steam" ".config/dotfiles" ".mozilla/firefox" ".config/nvim" ".config/yazi/plugins" ".config/nixos" ".config/sinew.in" ".local/share/direnv" ".local/share/nvim" ".local/share/zoxide" ".local/share/Enpass" ".local/share/Steam" ".ssh" ]; files = [ ".config/shell/.env" ]; }; activation = { setupDotfiles = lib.hm.dag.entryAfter ["writeBoundary"] '' if [[ -v DRY_RUN ]]; then echo "Dry run: Would bootstrap dotfiles from labs.scarif.space" exit fi TEMP_DIR=$(mktemp -d) DOTFILES_DIR="$HOME/.config/dotfiles" DOTFILES_GIT_DIR="$DOTFILES_DIR/.git" if [ ! -d "$DOTFILES_GIT_DIR" ]; then echo "No local repository so cloning from remote" SOURCE="https://labs.scarif.space/chris/dotfiles.git" ${pkgs.git}/bin/git clone -b main "$SOURCE" "$TEMP_DIR" mv "$TEMP_DIR/.git" "$DOTFILES_GIT_DIR" else echo "Local repository found so cloning from there" ${pkgs.git}/bin/git clone -b main "$DOTFILES_GIT_DIR" "$TEMP_DIR" ${pkgs.git}/bin/git --git-dir="$DOTFILES_GIT_DIR" --work-tree="$TEMP_DIR" pull --rebase || true fi echo "Copying dot files to home" ${pkgs.coreutils}/bin/cp -rfT "$TEMP_DIR" "$HOME" NVIM_DIR="$HOME/.config/nvim" echo "Neovim config not initialised so initialising from remote" ${pkgs.git}/bin/git --git-dir="$DOTFILES_GIT_DIR" --work-tree="$HOME" submodule set-url ".config/nvim" https://labs.scarif.space/chris/nvim.git ${pkgs.git}/bin/git --git-dir="$DOTFILES_GIT_DIR" --work-tree="$HOME" submodule update --init || true ${pkgs.git}/bin/git --git-dir="$DOTFILES_GIT_DIR" --work-tree="$HOME" submodule set-url ".config/nvim" git@labs.scarif.space:chris/nvim.git cd "$HOME" echo "Cleanup" ${pkgs.coreutils}/bin/rm -rf "$TEMP_DIR" ${pkgs.coreutils}/bin/rm -rf "$HOME/.git" || true echo "Dotfiles bootstrapped successfully." ''; setupDevDirectories = lib.hm.dag.entryAfter ["writeBoundary"] '' if [[ -v DRY_RUN ]]; then echo "Dry run: Would create dev directories" exit fi echo "Creating development directories" for dir in "DevOps" "FSharp" "JavaScript" "Scala" "Rust" "PHP" "Tutorials" "Sites" "MobileApps" "Tries"; do if [ ! -d "$HOME/Code/$dir" ]; then mkdir -p "$HOME/Code/$dir" fi done ''; }; packages = with pkgs; [ # jetbrains.rider # android-studio # beekeeper-studio # brave # go # lua direnv wiremix bluetui spotify nodePackages.pnpm try-cli.packages.${system}.default elephant.packages.${system}.default walker # (python3.withPackages (python-pkgs: [ python-pkgs.pip python-pkgs.requests ])) # rustup # zig obsidian mailspring # thunderbird # libreoffice-qt # pkgs-unstable.nerd-fonts.fira-code # hunspell # blueberry # pkgs-unstable.hyprshot # catppuccin-cursors.macchiatoBlue # catppuccin-gtk # papirus-folders # pkgs-unstable.php84Packages.composer # pkgs-unstable.php84Packages.xdebug # pkgs-unstable.php84Extensions.sqlite3 # pkgs-unstable.php84Extensions.redis # pkgs-unstable.php84Extensions.sodium # pkgs-unstable.php84Extensions.pgsql # pkgs-unstable.php84Extensions.iconv # pkgs-unstable.php84Extensions.gd # pkgs-unstable.php84Extensions.zip # php antigravity gimp # kdePackages.dolphin nautilus enpass enpass-cli expressvpn # jellyfin-ffmpeg inkscape krita libreoffice-fresh nextcloud-client nodejs_24 signal-desktop sxiv tenacity zathura ghostty yarn uwsm wally-cli kdePackages.wacomtablet # kdePackages.print-manager mpv vlc imv # telegram-desktop ]; }; xdg.mimeApps = { enable = true; defaultApplications = { # Directories "inode/directory" = [ "org.gnome.Nautilus.desktop" ]; # Images "image/png" = [ "imv.desktop" ]; "image/jpeg" = [ "imv.desktop" ]; "image/gif" = [ "imv.desktop" ]; "image/webp" = [ "imv.desktop" ]; "image/bmp" = [ "imv.desktop" ]; "image/tiff" = [ "imv.desktop" ]; # Documents "application/pdf" = [ "zathura.desktop" ]; # Web and Browser "x-scheme-handler/http" = [ "firefox.desktop" ]; "x-scheme-handler/https" = [ "firefox.desktop" ]; "text/html" = [ "firefox.desktop" ]; # Video "video/mp4" = [ "mpv.desktop" ]; "video/x-msvideo" = [ "mpv.desktop" ]; "video/x-matroska" = [ "mpv.desktop" ]; "video/x-flv" = [ "mpv.desktop" ]; "video/x-ms-wmv" = [ "mpv.desktop" ]; "video/mpeg" = [ "mpv.desktop" ]; "video/ogg" = [ "mpv.desktop" ]; "video/webm" = [ "mpv.desktop" ]; "video/quicktime" = [ "mpv.desktop" ]; "video/3gpp" = [ "mpv.desktop" ]; "video/3gpp2" = [ "mpv.desktop" ]; "video/x-ms-asf" = [ "mpv.desktop" ]; "video/x-ogm+ogg" = [ "mpv.desktop" ]; "video/x-theora+ogg" = [ "mpv.desktop" ]; "application/ogg" = [ "mpv.desktop" ]; # Mail "x-scheme-handler/mailto" = [ "mailspring.desktop" ]; # Text and Code "text/plain" = [ "nvim.desktop" ]; "text/english" = [ "nvim.desktop" ]; "text/x-makefile" = [ "nvim.desktop" ]; "text/x-c++hdr" = [ "nvim.desktop" ]; "text/x-c++src" = [ "nvim.desktop" ]; "text/x-chdr" = [ "nvim.desktop" ]; "text/x-csrc" = [ "nvim.desktop" ]; "text/x-java" = [ "nvim.desktop" ]; "text/x-moc" = [ "nvim.desktop" ]; "text/x-pascal" = [ "nvim.desktop" ]; "text/x-tcl" = [ "nvim.desktop" ]; "text/x-tex" = [ "nvim.desktop" ]; "application/x-shellscript" = [ "nvim.desktop" ]; "text/x-c" = [ "nvim.desktop" ]; "text/x-c++" = [ "nvim.desktop" ]; "application/xml" = [ "nvim.desktop" ]; "text/xml" = [ "nvim.desktop" ]; }; }; programs = let lock-false = { Value = false; Status = "locked"; }; lock-true = { Value = true; Status = "locked"; }; in { firefox = { enable = true; package = pkgs.wrapFirefox pkgs.firefox-unwrapped { extraPolicies = { DisableTelemetry = true; DisableFirefoxStudies = true; EnableTrackingProtection = { Value= true; Locked = true; Cryptomining = true; Fingerprinting = true; }; DisablePocket = true; DisableFirefoxAccounts = false; DisableAccounts = false; DisableFirefoxScreenshots = true; OverrideFirstRunPage = ""; OverridePostUpdatePage = ""; DontCheckDefaultBrowser = true; DisplayBookmarksToolbar = "always"; # alternatives: "always" or "newtab" DisplayMenuBar = "default-off"; # alternatives: "always", "never" or "default-on" SearchBar = "unified"; # alternative: "separate" /* ---- EXTENSIONS ---- */ ExtensionSettings = { "*".installation_mode = "allowed"; # blocks all addons except the ones specified below # Enpass "firefox-enpass@enpass.io" = { install_url = "https://dl.enpass.io/stable/extensions/firefox/versions/v6.11.10.2/enpass_password_manager-6.11.10.2.xpi"; installation_mode = "force_installed"; }; }; /* ---- PREFERENCES ---- */ # Set preferences shared by all profiles. Preferences = { "browser.contentblocking.category" = { Value = "strict"; Status = "locked"; }; "extensions.pocket.enabled" = lock-false; "extensions.screenshots.disabled" = lock-true; "browser.topsites.contile.enabled" = lock-false; "browser.formfill.enable" = lock-false; "browser.search.suggest.enabled" = lock-false; "browser.search.suggest.enabled.private" = lock-false; "browser.urlbar.suggest.searches" = lock-false; "browser.urlbar.showSearchSuggestionsFirst" = lock-false; "browser.newtabpage.activity-stream.feeds.section.topstories" = lock-false; "browser.newtabpage.activity-stream.feeds.snippets" = lock-false; "browser.newtabpage.activity-stream.section.highlights.includePocket" = lock-false; "browser.newtabpage.activity-stream.section.highlights.includeBookmarks" = lock-false; "browser.newtabpage.activity-stream.section.highlights.includeDownloads" = lock-false; "browser.newtabpage.activity-stream.section.highlights.includeVisited" = lock-false; "browser.newtabpage.activity-stream.showSponsored" = lock-false; "browser.newtabpage.activity-stream.system.showSponsored" = lock-false; "browser.newtabpage.activity-stream.showSponsoredTopSites" = lock-false; "browser.newtabpage.activity-stream.feeds.section.highlights" = false; }; }; }; profiles = { default = { id = 0; name = "default"; isDefault = true; search = { default = "holocron"; order = [ "holocron" "google" ]; engines= { holocron = { name = "Holocron"; urls = [{ template = "https://holocron.scarif.space/search"; params = [ { name = "q"; value = "{searchTerms}"; } ]; }]; icon = "https://holocron.scarif.space/favicon.ico"; definedAliases = [ "@h" ]; }; bing.metaData.hidden = true; ebay.metaData.hidden = true; perplexity.metaData.hidden = true; }; }; }; }; }; }; nixpkgs = { config = { allowUnfree = true; allowUnfreePredicate = (_: true); permittedInsecurePackages = [ "electron-25.9.0" # Obsidian "beekeeper-studio-5.3.4" ]; }; }; }; extraSpecialArgs = { inherit inputs; }; }; } ]; }; }; # Standalone home-manager configuration entrypoint #homeConfigurations = { # chris = home-manager.lib.homeManagerConfiguration { # inherit pkgs; # extraSpecialArgs = { # inherit inputs; # }; # modules = [ # ./home # ]; # }; #}; }; }