commit 11ce3ba32fc66f7584920849c50e41afd57b3ac9 Author: DerGrumpf Date: Wed Feb 18 21:23:56 2026 +0100 Init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6bc3095 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Nix build outputs +result +result-* +*.img +*.img.zst +*.qcow2 + +# Nix store +.dirlocals + +# Build artifacts +*.o +*.a +*.so +*.dylib + +# IDE/Editor +.vscode/ +.idea/ +*.swp +*.swo +*~ +.DS_Store + +# OS +.DS_Store +Thumbs.db + +# Archives +*.tar.gz +*.tar.bz2 +*.zip + +# Local development +.envrc +direnv.allow + +# Flake lock (optional - usually committed, but some prefer not to) +# flake.lock + +# Temporary files +*.tmp +*.bak diff --git a/README.md b/README.md new file mode 100644 index 0000000..ed59ff0 --- /dev/null +++ b/README.md @@ -0,0 +1,110 @@ +# cyper-servers + +NixOS flake configuration for x86_64 server infrastructure. + +## Hosts + +| Host | IP | DNS | Role | +|------|----|-----|------| +| `cyper-controller` | `192.168.2.2` (static) | `127.0.0.1`, `1.1.1.1` | k3s master, PostgreSQL, DNS/DHCP | +| `cyper-node1` | `192.168.2.30` (static) | `192.168.2.2` | k3s agent | +| `cyper-node2` | `192.168.2.31` (static) | `192.168.2.2` | k3s agent | +| `cyper-cluster` | DHCP | `1.1.1.1`, `8.8.8.8` | k3s agent, Helm | +| `cyper-cloud` | DHCP | `1.1.1.1`, `8.8.8.8` | Cloud tooling (Terraform, AWS CLI) | + +## Directory Structure + +``` +cyper-servers/ +├── flake.nix # Main flake — declares all hosts +├── nixos/ +│ ├── default.nix # Shared NixOS config (users, SSH, Nix settings) +│ ├── hardware.nix # x86_64 bootloader & filesystem config +│ ├── settings.nix # Locale & timezone +│ └── packages.nix # Common system packages +├── home/ # Home Manager (shared across all hosts) +│ ├── default.nix +│ ├── packages.nix +│ ├── git.nix +│ ├── shell.nix +│ └── neovim/ +└── hosts/ + ├── services/ + │ ├── k3s-master.nix # Reusable k3s server module + │ └── k3s-agent.nix # Reusable k3s agent module + ├── cyper-controller/ + │ ├── configuration.nix # Static IP, imports master + postgres + dns + │ ├── postgres.nix # PostgreSQL (x86_64 tuned) + │ └── dns.nix # dnsmasq DNS + DHCP server + ├── cyper-node1/ + │ └── configuration.nix # Static 192.168.2.30, k3s agent + ├── cyper-node2/ + │ └── configuration.nix # Static 192.168.2.31, k3s agent + ├── cyper-cluster/ + │ └── configuration.nix # DHCP, k3s agent + Helm + └── cyper-cloud/ + └── configuration.nix # DHCP, Terraform + AWS CLI +``` + +## Quick Start + +### 1. Install NixOS on each machine + +Boot from a standard NixOS x86_64 ISO and partition your disk with labels `boot` (FAT32) and `nixos` (ext4), then: + +```bash +nixos-generate-config --root /mnt +``` + +### 2. Clone and apply + +```bash +git clone /etc/nixos +cd /etc/nixos +nixos-rebuild switch --flake .#cyper-controller # on the controller +nixos-rebuild switch --flake .#cyper-node1 # on node1 +# ... etc +``` + +### 3. k3s cluster setup + +After `cyper-controller` is up, retrieve the node token and apply it on each agent: + +```bash +# On cyper-controller: +cat /var/lib/rancher/k3s/server/node-token + +# On each agent, set the token in the k3s service environment: +# Edit hosts/services/k3s-agent.nix and add: +# tokenFile = "/etc/k3s-token"; +# Then create /etc/k3s-token with the token value and rebuild. +``` + +## Customization + +### Change username + +Edit `flake.nix`: +```nix +primaryUser = "your-username"; +``` + +### Add packages per host + +Edit `hosts//configuration.nix` and add to `environment.systemPackages`. + +### Adjust PostgreSQL + +Edit `hosts/cyper-controller/postgres.nix` — memory settings are pre-tuned for x86_64 with 8GB+ RAM. + +### DNS entries + +Edit `hosts/cyper-controller/dns.nix` to add static A records or adjust DHCP ranges. + +## Locale & Timezone + +Defaults (same as cyper-rpi): +- **Timezone**: `Europe/Berlin` +- **Locale**: `en_US.UTF-8` with German regional settings + +Change in `nixos/settings.nix`. diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..502c2c3 --- /dev/null +++ b/flake.lock @@ -0,0 +1,122 @@ +{ + "nodes": { + "flake-parts": { + "inputs": { + "nixpkgs-lib": [ + "nixvim", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1769996383, + "narHash": "sha256-AnYjnFWgS49RlqX7LrC4uA+sCCDBj0Ry/WOJ5XWAsa0=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "57928607ea566b5db3ad13af0e57e921e6b12381", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "home-manager": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1770995331, + "narHash": "sha256-MZOF7PVKDOMAOp6bJpzuKOb1DVcyUT84568r8y3iVGg=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "5e90b62996d56da9acb21e502c078e7c4e6ab40f", + "type": "github" + }, + "original": { + "owner": "nix-community", + "ref": "master", + "repo": "home-manager", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1770843696, + "narHash": "sha256-LovWTGDwXhkfCOmbgLVA10bvsi/P8eDDpRudgk68HA8=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "2343bbb58f99267223bc2aac4fc9ea301a155a16", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1770380644, + "narHash": "sha256-P7dWMHRUWG5m4G+06jDyThXO7kwSk46C1kgjEWcybkE=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "ae67888ff7ef9dff69b3cf0cc0fbfbcd3a722abe", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixvim": { + "inputs": { + "flake-parts": "flake-parts", + "nixpkgs": "nixpkgs_2", + "systems": "systems" + }, + "locked": { + "lastModified": 1770954048, + "narHash": "sha256-TEXS8Z7K+GsOOtL0QD1hrMxL0lVJjKDl3qZq/mJHu2k=", + "owner": "nix-community", + "repo": "nixvim", + "rev": "e49b8deda7b1732f5a2ea2a90446e45adb2a121d", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixvim", + "type": "github" + } + }, + "root": { + "inputs": { + "home-manager": "home-manager", + "nixpkgs": "nixpkgs", + "nixvim": "nixvim" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..8a36585 --- /dev/null +++ b/flake.nix @@ -0,0 +1,125 @@ +{ + description = "NixOS Configuration for x86_64 Servers"; + + # Binary Cache configuration + nixConfig = { + extra-substituters = [ "https://nix-community.cachix.org" ]; + extra-trusted-public-keys = [ + "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" + ]; + + http-connections = 4; + download-buffer-size = 268435456; # 256MB + }; + + # External Dependencies + inputs = { + nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; + home-manager.url = "github:nix-community/home-manager/master"; + home-manager.inputs.nixpkgs.follows = "nixpkgs"; + nixvim.url = "github:nix-community/nixvim"; + }; + + outputs = + { + self, + nixpkgs, + home-manager, + nixvim, + ... + }@inputs: + let + primaryUser = "phil"; + system = "x86_64-linux"; + + # Configure Home Manager + homeManagerModule = { + home-manager = { + useGlobalPkgs = true; + useUserPackages = true; + users.${primaryUser} = import ./home/default.nix; + extraSpecialArgs = { inherit inputs primaryUser; }; + backupFileExtension = "backup"; + }; + }; + + # Modules needed regardless of config + commonModules = hostName: [ + home-manager.nixosModules.home-manager + homeManagerModule + ./hosts/${hostName}/configuration.nix + ]; + + # Wrapper around nixpkgs.lib.nixosSystem; pins system and specialArgs + mkSystem = + modules: + nixpkgs.lib.nixosSystem { + inherit system; + modules = modules; + specialArgs = { inherit inputs self primaryUser; }; + }; + + # Builds a full installed NixOS system for given Host + mkNixosConfig = + hostName: + mkSystem ( + [ + ./nixos/default.nix + ./nixos/hardware.nix + ] + ++ commonModules hostName + ); + + # Build a bootable installer ISO for given Host + mkISOConfig = + hostName: + (mkSystem ( + [ + "${nixpkgs}/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix" + ./nixos/settings.nix + ./nixos/packages.nix + # Re-declare the user for the ISO context — default.nix is excluded + # because it imports hardware.nix which conflicts with the ISO profile, + # but Home Manager still needs a valid user to activate against. + { + nixpkgs.config.allowUnfree = true; + programs.fish.enable = true; + users.users.${primaryUser} = { + isNormalUser = true; + group = primaryUser; + hashedPassword = "$6$TqAclAMz/DFP90Ve$HEN4t1pqK36rACeWctJOmLArkTWb/rIBYamu4sY8bPuDnqkVVyfOLqXKkgX8zBf9LKz02.mo4EKFRnYWIzcAX1"; + extraGroups = [ "wheel" ]; + shell = nixpkgs.legacyPackages.${system}.fish; + openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEuYuGhqRC/QLoRBH91c3DG5JHlAdRLQsvde18k5ipY2 phil@cyperpunk.de" + ]; + }; + users.groups.${primaryUser} = { }; + } + ] + ++ commonModules hostName + )).config.system.build.isoImage; + in + { + # Installed system configurations + # nixos-rebuild switch --flake .# + nixosConfigurations = { + "cyper-controller" = mkNixosConfig "cyper-controller"; + "cyper-node1" = mkNixosConfig "cyper-node1"; + "cyper-node2" = mkNixosConfig "cyper-node2"; + "cyper-cluster" = mkNixosConfig "cyper-cluster"; + "cyper-cloud" = mkNixosConfig "cyper-cloud"; + }; + + # Create installer ISOs + # nix build .#isoImages. + isoImages = { + "cyper-controller" = mkISOConfig "cyper-controller"; + "cyper-node1" = mkISOConfig "cyper-node1"; + "cyper-node2" = mkISOConfig "cyper-node2"; + "cyper-cluster" = mkISOConfig "cyper-cluster"; + "cyper-cloud" = mkISOConfig "cyper-cloud"; + }; + }; + +} diff --git a/home/default.nix b/home/default.nix new file mode 100644 index 0000000..3bb8a86 --- /dev/null +++ b/home/default.nix @@ -0,0 +1,21 @@ +{ primaryUser, inputs, ... }: +{ + imports = [ + ./packages.nix + ./git.nix + ./shell.nix + + inputs.nixvim.homeModules.nixvim + ./neovim + # ./python.nix + + ]; + + home = { + username = primaryUser; + stateVersion = "25.11"; + sessionVariables = { + GROQ_API_KEY = "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"; + }; + }; +} diff --git a/home/fastfetch.jsonc b/home/fastfetch.jsonc new file mode 100644 index 0000000..fa90e1b --- /dev/null +++ b/home/fastfetch.jsonc @@ -0,0 +1,171 @@ +{ + "$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json", + "logo": { + "type": "kitty-icat", + "source": "nixos", + // "height": 15, + "width": 12, + "padding": { + "top": 0, + "left": 0 + } + }, + "modules": [ + "break", + { + "type": "custom", + "format": "\u001b[90m┌──────────────────────Hardware──────────────────────┐" + }, + { + "type": "host", + "key": " PC", + "keyColor": "green" + }, + { + "type": "cpu", + "key": "│ ├", + "keyColor": "green" + }, + { + "type": "gpu", + "key": "│ ├󰍛", + "keyColor": "green" + }, + { + "type": "disk", + "key": "│ ├", + "keyColor": "green" + }, + { + "type": "memory", + "key": "└ └󰍛", + "keyColor": "green" + }, + { + "type": "custom", + "format": "\u001b[90m└────────────────────────────────────────────────────┘" + }, + "break", + { + "type": "custom", + "format": "\u001b[90m┌──────────────────────Software──────────────────────┐" + }, + { + "type": "os", + "key": " OS", + "keyColor": "yellow" + }, + { + "type": "kernel", + "key": "│ ├", + "keyColor": "yellow" + }, + { + "type": "bios", + "key": "│ ├", + "keyColor": "yellow" + }, + { + "type": "packages", + "key": "│ ├󰏖", + "keyColor": "yellow" + }, + { + "type": "shell", + "key": "└ └", + "keyColor": "yellow" + }, + "break", + { + "type": "de", + "key": " DE", + "keyColor": "blue" + }, + { + "type": "lm", + "key": "│ ├", + "keyColor": "blue" + }, + { + "type": "wm", + "key": "│ ├", + "keyColor": "blue" + }, + { + "type": "wmtheme", + "key": "│ ├󰉼", + "keyColor": "blue" + }, + { + "type": "terminal", + "key": "└ └", + "keyColor": "blue" + }, + { + "type": "custom", + "format": "\u001b[90m└────────────────────────────────────────────────────┘" + }, + "break", + { + "type": "custom", + "format": "\u001b[90m┌─────────────────Uptime / Age / DT──────────────────┐" + }, + { + "type": "command", + "key": " OS Age ", + "keyColor": "magenta", + "text": "birth_install=$(stat -c %W /); current=$(date +%s); time_progression=$((current - birth_install)); days_difference=$((time_progression / 86400)); echo $days_difference days" + }, + { + "type": "uptime", + "key": " Uptime ", + "keyColor": "magenta" + }, + { + "type": "datetime", + "key": " DateTime ", + "keyColor": "magenta" + }, + { + "type": "custom", + "format": "\u001b[90m└────────────────────────────────────────────────────┘" + }, + "break", + { + "type": "custom", + "format": "\u001b[90m┌─────────────────────Networking─────────────────────┐" + }, + { + "type": "publicip", + "key": " Public ", + "keyColor": "magenta" + }, + { + "type": "localip", + "key": " Local ", + "keyColor": "magenta" + }, + { + "type": "dns", + "key": " DNS ", + "keyColor": "magenta" + }, + { + "type": "netio", + "key": " Net I/O ", + "keyColor": "magenta" + }, + { + "type": "custom", + "format": "\u001b[90m└────────────────────────────────────────────────────┘" + }, + { + "type": "colors", + "paddingLeft": 2, + "symbol": "circle" + }, + "break", + ] +} + + diff --git a/home/git.nix b/home/git.nix new file mode 100644 index 0000000..daf61f0 --- /dev/null +++ b/home/git.nix @@ -0,0 +1,26 @@ +{ pkgs, primaryUser, ... }: +{ + programs.git = { + enable = true; + settings = { + user = { + name = "DerGrumpf"; # TODO replace + email = "p.keier@beyerstedt-it.de"; # TODO replace + }; + github = { + user = primaryUser; + }; + init = { + defaultBranch = "main"; + }; + }; + lfs.enable = true; + ignores = [ "**/.DS_STORE" ]; + }; + + home.packages = with pkgs; [ + gh + gitui + ]; + +} diff --git a/home/neovim/alpha.nix b/home/neovim/alpha.nix new file mode 100644 index 0000000..52357f4 --- /dev/null +++ b/home/neovim/alpha.nix @@ -0,0 +1,147 @@ +{ pkgs, ... }: { + # Alpha: Start screen/dashboard for Neovim + # Shows a custom ASCII art header and quick action buttons on startup. + programs.nixvim.plugins.alpha = { + enable = true; + settings.layout = [ + { + type = "padding"; + val = 2; + } + { + type = "text"; + val = [ + "⣿⣿⣿⣿⣿⣿⣿⣿⣿⢿⣯⣿⠿⣟⣷⣯⣛⢿⣿⣿⣾⣟⣿⣿⣿⣿⣿⣿⣿⣿⣿" + "⣿⣿⣿⣿⣿⣿⣿⡿⣵⣿⡿⣴⣽⡟⣳⢿⢽⣽⣕⣽⢿⡿⣿⣟⣿⣿⣿⣿⣿⣿⣿" + "⣿⣿⣿⣷⣿⣿⢟⣫⣿⢟⢟⣾⣾⣿⣿⣞⢳⣻⢞⣎⠿⢞⣊⣿⣞⣿⣿⣿⣿⣿⢽" + "⣿⣿⣿⣿⣿⣏⢯⣿⣏⣏⠔⢇⣿⢢⢆⢀⢆⣧⣼⢻⢰⡧⢻⣝⣏⡸⣧⣾⣿⣿⣿" + "⣿⣿⣿⣿⡟⣻⣿⣿⡾⡿⡼⢸⡝⣝⡳⢢⣧⢳⣳⢷⡇⣗⢺⡺⣿⡧⣿⣿⣿⢿⢿" + "⣿⡿⣿⣼⡼⣿⣿⡗⡧⣧⠁⡝⣧⣳⠅⡾⠈⣎⢮⣧⣿⣿⣗⣷⣻⢷⣏⣼⢏⣺⣿" + "⣿⣿⣿⣻⣿⣿⣿⢧⣿⢹⠉⢷⢿⣧⣲⡏⡀⡈⢆⠳⣿⡿⢿⣿⣱⢿⢫⣷⣝⣿⣿" + "⣿⣿⣿⡯⡟⣿⣿⢽⣡⠟⢿⣮⠁⠙⠛⠈⡴⢿⣿⡷⣬⣽⢽⠧⣷⡏⣿⡇⣧⣽⣿" + "⣿⠟⢻⡧⡇⣿⡇⣇⣆⢄⡜⢃⡀⡀⡀⡀⡀⢎⣁⠁⣸⣗⣸⣿⣧⣼⡿⢹⢿⢾⣿" + "⣿⣷⣾⣿⢻⣿⢧⢻⣽⡀⡀⡀⡀⢄⡀⡀⡀⡀⡀⢀⣷⡸⡟⣿⣶⣻⣧⡛⡱⢝⣿" + "⣿⣿⣿⣿⢸⡿⢚⡜⣿⣇⡀⡀⡀⡀⡀⡀⡀⡀⠚⢁⢣⣜⡿⣿⡇⢼⣿⠨⣸⣿⣿" + "⣿⣄⣿⣗⢾⢻⣧⢿⣾⣿⣦⡀⡀⠑⠚⠉⡀⡀⣤⣿⢨⣿⠗⣻⢣⣿⢹⢈⣽⣿⣿" + "⣿⣿⣿⣿⢎⡄⢿⣞⡇⣿⠹⣿⣶⣀⡀⣀⡴⡩⢸⢏⣿⣿⣶⢻⣾⢏⡞⠡⢽⣇⣾" + "⣿⣿⣿⣮⣼⢬⣦⢿⣳⣌⠧⡉⠈⣇⣛⣁⣈⣼⣿⡸⠫⠛⠐⠛⠕⣙⣻⣬⣼⣿⣿" + "⢟⢿⣿⣿⣿⡢⣃⣪⣭⣡⣤⣶⠟⡿⠿⠿⠿⠛⢁⣿⣿⢩⠉⡀⠈⠓⡝⣿⣿⣿⣿" + "⣾⣿⣿⣿⣿⠞⢔⡣⡴⣾⣿⠓⣤⢧⡼⣉⠠⢤⣿⣿⠇⠃⡀⡀⡀⡀⡸⢿⣾⣿⣿" + "⣿⣿⣿⡿⣺⡸⢗⢠⣇⣿⣿⠊⠃⡀⠉⡀⢠⣿⣿⠟⡸⡀⡀⡀⡀⡀⣃⣬⠽⠿⣿" + "⣿⣿⣿⣿⡇⡏⢸⣿⠟⣽⡇⡀⡀⡀⡀⣴⣟⢭⣾⣿⡇⠎⣠⠒⠉⠈⢀⡀⢨⡋⣿" + "⠛⠛⠛⠋⠃⠓⠚⠛⠘⠛⠃⡀⠊⡀⠛⠛⠛⠂⠛⠛⠓⠁⠚⡀⠂⠒⠒⠐⠒⠋⠛" + ]; + opts = { + position = "center"; + hl = "Type"; + }; + } + { + type = "padding"; + val = 2; + } + { + type = "group"; + val = [ + { + type = "button"; + val = "[+] New file"; + on_press.__raw = + "function() vim.cmd[[ene]] vim.cmd[[startinsert]] end"; + opts = { + keymap = [ "n" "e" ":ene startinsert " { } ]; + shortcut = "e"; + position = "center"; + cursor = 3; + width = 50; + align_shortcut = "right"; + hl_shortcut = "Keyword"; + }; + } + { + type = "button"; + val = "[?] Find file"; + on_press.__raw = "function() vim.cmd[[Telescope find_files]] end"; + opts = { + keymap = [ "n" "f" ":Telescope find_files " { } ]; + shortcut = "f"; + position = "center"; + cursor = 3; + width = 50; + align_shortcut = "right"; + hl_shortcut = "Keyword"; + }; + } + { + type = "button"; + val = "[~] Recent files"; + on_press.__raw = "function() vim.cmd[[Telescope oldfiles]] end"; + opts = { + keymap = [ "n" "r" ":Telescope oldfiles " { } ]; + shortcut = "r"; + position = "center"; + cursor = 3; + width = 50; + align_shortcut = "right"; + hl_shortcut = "Keyword"; + }; + } + { + type = "button"; + val = "[Y] Yazi"; + on_press.__raw = "function() require('yazi').yazi() end"; + opts = { + keymap = [ "n" "y" ":Yazi" { } ]; + shortcut = "y"; + position = "center"; + cursor = 3; + width = 50; + align_shortcut = "right"; + hl_shortcut = "Keyword"; + }; + } + { + type = "button"; + val = "[A] Open Prompt"; + #on_press.__raw = "function() require('yazi').yazi() end"; + opts = { + keymap = [ "n" "a" ":AvanteChatNew" { } ]; + shortcut = "a"; + position = "center"; + cursor = 3; + width = 50; + align_shortcut = "right"; + hl_shortcut = "Keyword"; + }; + } + { + type = "button"; + val = "[X] Quit"; + on_press.__raw = "function() vim.cmd[[qa]] end"; + opts = { + keymap = [ "n" "q" ":qa" { } ]; + shortcut = "q"; + position = "center"; + cursor = 3; + width = 50; + align_shortcut = "right"; + hl_shortcut = "Keyword"; + }; + } + ]; + } + { + type = "padding"; + val = 2; + } + { + type = "text"; + val = "Circuits hum in anticipation of your will."; + opts = { + position = "center"; + hl = "Comment"; + }; + } + ]; + }; +} diff --git a/home/neovim/avante.nix b/home/neovim/avante.nix new file mode 100644 index 0000000..edbbf9e --- /dev/null +++ b/home/neovim/avante.nix @@ -0,0 +1,106 @@ +{ pkgs, ... }: { + # Avante: AI-powered coding assistant (Cursor-like experience in Neovim) + programs.nixvim = { + + plugins = { + markdown-preview.enable = true; + render-markdown.enable = true; + #extraConfigLuaPre = '' + # vim.env.GROQ_API_KEY = os.getenv("GROQ_API_KEY") + #''; + # TODO: Integrate CoPilot https://github.com/settings/copilot/features + avante = { + enable = true; + autoLoad = true; + settings = { + provider = "groq"; + + providers.groq = { + __inherited_from = "openai"; + api_key_name = "GROQ_API_KEY"; + endpoint = "https://api.groq.com/openai/v1/"; + model = "groq/compound-mini"; + disable_tools = true; + extra_request_body = { + temperature = 1; + max_tokens = 8192; + tools = null; + tool_choice = "none"; + }; + }; + + # auto_suggestions_provider = "copilot"; + + render = { markdown = true; }; + + behaviour = { + auto_suggestions = false; + auto_set_highlight_group = true; + auto_set_keymaps = true; + auto_apply_diff_after_generation = false; + support_paste_from_clipboard = false; + }; + + mappings = { + ask = "aa"; + edit = "ae"; + refresh = "ar"; + diff = { + ours = "co"; + theirs = "ct"; + all_theirs = "ca"; + both = "cb"; + cursor = "cc"; + next = "]x"; + prev = "[x"; + }; + suggestion = { + accept = ""; + next = ""; + prev = ""; + dismiss = ""; + }; + jump = { + next = "]]"; + prev = "[["; + }; + submit = { + normal = ""; + insert = ""; + }; + sidebar = { + switch_windows = ""; + reverse_switch_windows = ""; + }; + }; + + hints = { enabled = true; }; + + windows = { + position = "right"; + wrap = true; + width = 30; + sidebar_header = { + align = "center"; + rounded = true; + }; + }; + + highlights = { + diff = { + current = "DiffText"; + incoming = "DiffAdd"; + }; + }; + + diff = { + autojump = true; + list_opener = "copen"; + }; + }; + }; + + extraPackages = with pkgs; [ curl ]; + }; + }; +} diff --git a/home/neovim/catppuccin.nix b/home/neovim/catppuccin.nix new file mode 100644 index 0000000..98ba46c --- /dev/null +++ b/home/neovim/catppuccin.nix @@ -0,0 +1,34 @@ +{ pkgs, ... }: +{ + # Catppuccin: Soothing pastel theme for Neovim + # Provides consistent theming across plugins with transparency support. + programs.nixvim = { + colorschemes.catppuccin = { + enable = true; + settings = { + flavour = "mocha"; + transparent_background = true; + term_colors = true; + integrations = { + treesitter = true; + cmp = true; + gitsigns = true; + telescope = { + enabled = true; + }; + notify = true; + mini = { + enabled = true; + }; + }; + }; + }; + + # Custom highlight overrides + extraConfigLua = '' + local colors = require("catppuccin.palettes").get_palette("mocha") + vim.api.nvim_set_hl(0, "LineNr", { fg = colors.text, bg = "NONE" }) + vim.api.nvim_set_hl(0, "CursorLineNr", { fg = colors.pink, bg = "NONE", bold = true }) + ''; + }; +} diff --git a/home/neovim/conform.nix b/home/neovim/conform.nix new file mode 100644 index 0000000..271ab5d --- /dev/null +++ b/home/neovim/conform.nix @@ -0,0 +1,33 @@ +{ pkgs, ... }: { + # Conform: Code formatter that runs external formatting tools + # Automatically formats code on save for consistent style. + programs.nixvim = { + plugins.conform-nvim = { + enable = true; + + settings = { + formatters_by_ft = { + lua = [ "stylua" ]; + nix = [ "nixfmt" ]; + python = [ "black" ]; + rust = [ "rustfmt" ]; + rasi = [ "prettierd" ]; + }; + + format_on_save = { + timeout_ms = 2000; + lsp_fallback = true; + }; + }; + }; + + # Install formatters + extraPackages = with pkgs; [ + stylua + nixfmt + black + rustfmt + prettierd + ]; + }; +} diff --git a/home/neovim/default.nix b/home/neovim/default.nix new file mode 100644 index 0000000..df19ab4 --- /dev/null +++ b/home/neovim/default.nix @@ -0,0 +1,95 @@ +{ ... }: +{ + imports = [ + ./treesitter.nix + ./lint.nix + ./lsp.nix + ./conform.nix + ./lualine.nix + ./yazi.nix + ./toggleterm.nix + ./telescope.nix + ./catppuccin.nix + ./alpha.nix + ./avante.nix + ./openscad.nix + # ./molten.nix + ./which-key.nix + ]; + + programs.nixvim = { + enable = true; + defaultEditor = true; + + # Leader key + globals.mapleader = " "; + + plugins.web-devicons.enable = true; + + opts = { + number = true; # Show line numbers + cursorline = true; # Highlight current line + showmode = true; # already in statusline + hlsearch = true; # Highlight search result + incsearch = true; # Incremental Search + tabstop = 4; + termguicolors = true; # Enable 24-bit colormode + }; + + # Clipboard keymaps - yank to system clipboard + keymaps = [ + # Yank operations + { + mode = "n"; + key = "y"; + action = ''"+y''; + options.desc = "Yank to clipboard"; + } + { + mode = "v"; + key = "y"; + action = ''"+y''; + options.desc = "Yank to clipboard"; + } + { + mode = "n"; + key = "Y"; + action = ''"+Y''; + options.desc = "Yank line to clipboard"; + } + # Delete operations + { + mode = "n"; + key = "d"; + action = ''"+d''; + options.desc = "Delete to clipboard"; + } + { + mode = "v"; + key = "d"; + action = ''"+d''; + options.desc = "Delete to clipboard"; + } + { + mode = "n"; + key = "D"; + action = ''"+D''; + options.desc = "Delete line to clipboard"; + } + # Paste operations + { + mode = "n"; + key = "p"; + action = ''"+p''; + options.desc = "Paste from clipboard"; + } + { + mode = "v"; + key = "p"; + action = ''"+p''; + options.desc = "Paste from clipboard"; + } + ]; + }; + +} diff --git a/home/neovim/lint.nix b/home/neovim/lint.nix new file mode 100644 index 0000000..ac178c6 --- /dev/null +++ b/home/neovim/lint.nix @@ -0,0 +1,42 @@ +{ pkgs, ... }: +{ + # nvim-lint: Asynchronous linter that runs external linting tools + # to find errors and style issues without blocking the editor. + # Runs automatically after saving files. + programs.nixvim = { + plugins.lint = { + enable = true; + + # Configure linters for each filetype + lintersByFt = { + lua = [ "luacheck" ]; + nix = [ "statix" ]; # Nix static analyzer + python = [ "ruff" ]; + javascript = [ "eslint" ]; + rust = [ "clippy" ]; + # rasi has no common linter + }; + + # Trigger linting after saving a file + autoCmd = { + event = [ "BufWritePost" ]; + callback = { + __raw = '' + function() + require('lint').try_lint() + end + ''; + }; + }; + }; + + # Install linter binaries + extraPackages = with pkgs; [ + lua54Packages.luacheck + statix + ruff + nodePackages.eslint + clippy + ]; + }; +} diff --git a/home/neovim/live-server.nix b/home/neovim/live-server.nix new file mode 100644 index 0000000..70dea7e --- /dev/null +++ b/home/neovim/live-server.nix @@ -0,0 +1,20 @@ +{ pkgs, ... }: +{ + # Live Server: Auto-reload browser for web development + # Uses browser-sync for live reload functionality + programs.nixvim = { + keymaps = [ + { + mode = "n"; + key = "ls"; + action = "terminal browser-sync start --server --files '*.html, *.css, *.js' --no-notify"; + options.desc = "Start live server (browser-sync)"; + } + ]; + + extraPackages = with pkgs; [ + nodePackages.browser-sync + biome + ]; + }; +} diff --git a/home/neovim/lsp.nix b/home/neovim/lsp.nix new file mode 100644 index 0000000..8113fb3 --- /dev/null +++ b/home/neovim/lsp.nix @@ -0,0 +1,91 @@ +{ pkgs, ... }: +{ + # LSP configuration: Language Server Protocol provides IDE features + # like autocomplete, go-to-definition, diagnostics, and more. + programs.nixvim = { + plugins = { + # LSP configuration + lsp = { + enable = true; + + # Language servers for each language + servers = { + lua_ls = { + enable = true; + settings = { + Lua = { + runtime.version = "LuaJIT"; + diagnostics.globals = [ "vim" ]; + workspace.library = [ ]; # Populated by nixvim + telemetry.enable = false; + }; + }; + }; + + nil_ls.enable = true; # Nix language server + rust_analyzer = { + enable = true; # Rust language server + installCargo = true; + installRustc = true; + }; + pylsp.enable = true; # Python language server + }; + + # Keymaps for LSP actions + keymaps = { + diagnostic = { + "e" = "open_float"; + "[d" = "goto_prev"; + "]d" = "goto_next"; + }; + lspBuf = { + "gd" = "definition"; + "K" = "hover"; + "rn" = "rename"; + "ca" = "code_action"; + }; + }; + }; + + # Autocompletion + cmp = { + enable = true; + autoEnableSources = true; + + settings = { + snippet.expand = '' + function(args) + require('luasnip').lsp_expand(args.body) + end + ''; + + mapping = { + "" = "cmp.mapping.scroll_docs(-4)"; + "" = "cmp.mapping.scroll_docs(4)"; + "" = "cmp.mapping.complete()"; + "" = "cmp.mapping.abort()"; + "" = "cmp.mapping.confirm({ select = true })"; + }; + + sources = [ + { name = "nvim_lsp"; } + { name = "luasnip"; } + { name = "buffer"; } + { name = "path"; } + ]; + }; + }; + + # Snippet engine (required for completion) + luasnip.enable = true; + }; + + # Install LSP servers + extraPackages = with pkgs; [ + lua-language-server + nil + rust-analyzer + # python311Packages.python-lsp-server + ]; + }; +} diff --git a/home/neovim/lualine.nix b/home/neovim/lualine.nix new file mode 100644 index 0000000..4f85435 --- /dev/null +++ b/home/neovim/lualine.nix @@ -0,0 +1,22 @@ +{ pkgs, ... }: +{ + # Lualine: Fast and customizable statusline for Neovim + # Displays file info, git status, diagnostics, and mode at the bottom of the editor. + programs.nixvim.plugins.lualine = { + enable = true; + + settings = { + options = { + theme = "catppuccin"; + component_separators = { + left = "|"; + right = "|"; + }; + section_separators = { + left = ""; + right = ""; + }; + }; + }; + }; +} diff --git a/home/neovim/molten.nix b/home/neovim/molten.nix new file mode 100644 index 0000000..6b816ff --- /dev/null +++ b/home/neovim/molten.nix @@ -0,0 +1,43 @@ +{ pkgs, ... }: { + programs.nixvim = { + plugins.molten = { + enable = true; + python3Dependencies = p: + with p; [ + pynvim + jupyter-client + cairosvg + ipython + nbformat + ipykernel + pnglatex + plotly + kaleido + pyperclip + ]; + settings = { + kernel_name = "python3"; + auto_open_output = true; + output_win_max_width = 80; + output_win_max_height = 20; + }; + }; + + keymaps = [ + { + mode = "n"; + key = "ml"; + action = "MoltenEvaluateLine"; + options.desc = "Molten: Evaluate line"; + options.silent = true; + } + { + mode = "v"; + key = "mv"; + action = "MoltenEvaluateVisual"; + options.desc = "Molten: Evaluate selection"; + options.silent = true; + } + ]; + }; +} diff --git a/home/neovim/openscad.nix b/home/neovim/openscad.nix new file mode 100644 index 0000000..b4934ab --- /dev/null +++ b/home/neovim/openscad.nix @@ -0,0 +1,28 @@ +{ pkgs, ... }: { + # OpenSCAD: 3D modeling language support with syntax highlighting, + # cheatsheet, snippets, offline manual and fuzzy help + programs.nixvim = { + plugins.openscad = { + enable = true; + autoLoad = true; + settings = { + fuzzy_finder = "fzf"; + auto_open = true; + cheatsheet_toggle_key = "os"; + default_mappings = true; + exec_openscad_trig_key = "oo"; + help_manual_trig_key = "om"; + help_trig_key = "oh"; + top_toggle = "oc"; + + }; + }; + + # Install OpenSCAD binary for preview/compilation + extraPackages = with pkgs; [ + openscad + zathura # PDF viewer for manual + fzf + ]; + }; +} diff --git a/home/neovim/telescope.nix b/home/neovim/telescope.nix new file mode 100644 index 0000000..1d0e330 --- /dev/null +++ b/home/neovim/telescope.nix @@ -0,0 +1,27 @@ +{ pkgs, ... }: +{ + # Telescope: Fuzzy finder for files, buffers, grep, and more + # Provides fast search and navigation throughout your project. + programs.nixvim.plugins.telescope = { + enable = true; + + keymaps = { + "ff" = { + action = "find_files"; + options.desc = "Telescope find files"; + }; + "fg" = { + action = "live_grep"; + options.desc = "Telescope live grep"; + }; + "fb" = { + action = "buffers"; + options.desc = "Telescope buffers"; + }; + "fh" = { + action = "help_tags"; + options.desc = "Telescope help tags"; + }; + }; + }; +} diff --git a/home/neovim/toggleterm.nix b/home/neovim/toggleterm.nix new file mode 100644 index 0000000..3eca8a4 --- /dev/null +++ b/home/neovim/toggleterm.nix @@ -0,0 +1,64 @@ +{ pkgs, ... }: +{ + # ToggleTerm: Terminal emulator inside Neovim + # Provides floating, horizontal, and vertical terminal windows. + programs.nixvim.plugins.toggleterm = { + enable = true; + + settings = { + size = 20; + open_mapping = "[[]]"; + direction = "float"; + float_opts = { + border = "single"; + width = 200; + height = 40; + }; + }; + }; + + programs.nixvim.keymaps = [ + { + mode = "n"; + key = "h"; + action.__raw = '' + function() + require("toggleterm").toggle(1, 10, vim.loop.cwd(), "horizontal") + end + ''; + options.desc = "Toggle terminal (horizontal)"; + } + { + mode = "n"; + key = "v"; + action.__raw = '' + function() + require("toggleterm").toggle(2, 60, vim.loop.cwd(), "vertical") + end + ''; + options.desc = "Toggle terminal (vertical)"; + } + { + mode = "n"; + key = "ft"; + action.__raw = '' + function() + require("toggleterm").toggle(3, 20, vim.loop.cwd(), "float") + end + ''; + options.desc = "Toggle terminal (float)"; + } + { + mode = "t"; + key = ""; + action = "ToggleTerm"; + options.desc = "Toggle terminal"; + } + { + mode = "t"; + key = ""; + action = "v"; + options.desc = "Exit terminal and enter visual mode"; + } + ]; +} diff --git a/home/neovim/treesitter.nix b/home/neovim/treesitter.nix new file mode 100644 index 0000000..58e174a --- /dev/null +++ b/home/neovim/treesitter.nix @@ -0,0 +1,24 @@ +{ pkgs, ... }: +{ + + # Install language parsers declaratively + # Syntax Highlighting + programs.nixvim.plugins.treesitter = { + enable = true; + grammarPackages = with pkgs.vimPlugins.nvim-treesitter.builtGrammars; [ + lua + nix + python + javascript + rust + rasi + ]; + + settings = { + highlight = { + enable = true; + additional_vim_regex_highlighting = false; + }; + }; + }; +} diff --git a/home/neovim/which-key.nix b/home/neovim/which-key.nix new file mode 100644 index 0000000..ade48c6 --- /dev/null +++ b/home/neovim/which-key.nix @@ -0,0 +1,94 @@ +{ pkgs, ... }: { + # Which-key: Display available keybindings in popup + # Shows all possible key combinations after pressing leader or other prefix keys + programs.nixvim.plugins.which-key = { + enable = true; + + settings = { + delay = 500; # Time in ms before popup shows + + icons = { + breadcrumb = "»"; + separator = "➜"; + group = "+"; + }; + + # Organize keymaps into named groups + spec = [ + # Leader key groups + { + __unkeyed-1 = "a"; + group = "Avante AI"; + icon = "🤖"; + } + { + __unkeyed-1 = "f"; + group = "Find/Files/Terminal"; + icon = "🔍"; + } + { + __unkeyed-1 = "m"; + group = "Molten (Jupyter)"; + icon = "📓"; + } + { + __unkeyed-1 = "o"; + group = "OpenSCAD"; + icon = "🔧"; + } + + # Bracket navigation groups + { + __unkeyed-1 = "["; + group = "Previous"; + icon = "⬅️"; + } + { + __unkeyed-1 = "]"; + group = "Next"; + icon = "➡️"; + } + + # g prefix groups + { + __unkeyed-1 = "g"; + group = "Go/LSP"; + icon = "🎯"; + } + { + __unkeyed-1 = "gr"; + group = "LSP References/Rename"; + icon = "🔗"; + } + { + __unkeyed-1 = "gc"; + group = "Comments"; + icon = "💬"; + } + + # l prefix + { + __unkeyed-1 = "l"; + group = "Live Server"; + icon = "🌐"; + } + + # z prefix + { + __unkeyed-1 = "z"; + group = "Folds/Spell"; + icon = "📋"; + } + ]; + + # Hide specific mappings to reduce clutter + disable = { + builtin_keys = { + # Hide these default vim keys from which-key + i = [ "" "" ]; + n = [ "" ]; + }; + }; + }; + }; +} diff --git a/home/neovim/yazi.nix b/home/neovim/yazi.nix new file mode 100644 index 0000000..06d6e0a --- /dev/null +++ b/home/neovim/yazi.nix @@ -0,0 +1,41 @@ +{ pkgs, ... }: { + # Yazi: Terminal file manager integration for Neovim + # Provides a fast, visual way to browse and manage files. + programs.nixvim = { + # Use extraPlugins to manually load yazi.nvim + extraPlugins = with pkgs.vimPlugins; [ yazi-nvim ]; + + # Configure yazi after it's loaded + extraConfigLua = '' + require('yazi').setup({ + open_for_directories = true, + }) + ''; + + keymaps = [ + { + mode = "n"; + key = "fy"; + action.__raw = '' + function() + require('yazi').yazi(nil, vim.loop.cwd()) + end + ''; + options.desc = "Open Yazi file manager"; + } + { + mode = "n"; + key = "fd"; + action.__raw = '' + function() + require('yazi').yazi(nil, vim.fn.expand("%:p:h")) + end + ''; + options.desc = "Open Yazi in current file directory"; + } + ]; + + # Install yazi terminal program + extraPackages = with pkgs; [ yazi ]; + }; +} diff --git a/home/packages.nix b/home/packages.nix new file mode 100644 index 0000000..a734616 --- /dev/null +++ b/home/packages.nix @@ -0,0 +1,27 @@ +{ pkgs, ... }: +{ + home = { + packages = with pkgs; [ + # dev tools + curl + wget + vim + htop + tree + ripgrep + unrar + + # programming languages + #mise # node, deno, bun, rust, python, etc. + + # PDF Tools + #pandoc + #texlive.combined.scheme-full + #wkhtmltopdf + + # misc + yt-dlp + ffmpeg + ]; + }; +} diff --git a/home/python.nix b/home/python.nix new file mode 100644 index 0000000..be4b85d --- /dev/null +++ b/home/python.nix @@ -0,0 +1,26 @@ +{ pkgs, ... }: { + home.packages = with pkgs; [ + # Python 3.13 (newest stable) + python313 + python313Packages.pip + python313Packages.virtualenv + + # Additional useful tools + python313Packages.pipx # Install Python apps in isolated environments + uv # Fast Python package installer (alternative to pip) + ]; + + # Set up default Python version + home.sessionVariables = { PYTHON = "${pkgs.python313}/bin/python3"; }; + + # Shell aliases for convenience + programs.zsh.shellAliases = { + venv = "python3 -m venv"; + activate = "source venv/bin/activate"; + }; + + programs.fish.shellAliases = { + venv = "python3 -m venv"; + activate = "source venv/bin/activate.fish"; + }; +} diff --git a/home/shell.nix b/home/shell.nix new file mode 100644 index 0000000..8500d5c --- /dev/null +++ b/home/shell.nix @@ -0,0 +1,209 @@ +{ pkgs, ... }: +{ + home.packages = with pkgs; [ + eza # ls replacement + fzf # FuzzyFinder + tdf # terminal pdf viewer + jq # json parser + tree + fastfetch # system stats + tabiew # Table viewer + glow # MD Viewer + btop + zoxide # Move to fish + llm # LLM in the Terminal + + # Fun stuff + lolcat + cmatrix + ]; + + programs.kitty = { + enable = true; + themeFile = "Catppuccin-Mocha"; + + font = { + name = "Fira Code Nerd Font"; + size = 12; + }; + + settings = { + confirm_os_window_close = 0; + dynamic_background_opacity = true; # ctrl+shift+a>m/l + enable_audio_bell = false; + mouse_hide_wait = 3.0; + window_padding_width = 10; + + background_opacity = 0.8; + background_blur = 5; + + tab_bar_min_tabs = 1; + tab_bar_edge = "bottom"; + tab_bar_style = "custom"; # Should be changed to custom + tab_title_template = "{fmt.fg.red}{bell_symbol}{activity_symbol}{fmt.fg.tab}{title}"; + + symbol_map = + let + mappings = [ + "U+23FB-U+23FE" + "U+2B58" + "U+E200-U+E2A9" + "U+E0A0-U+E0A3" + "U+E0B0-U+E0BF" + "U+E0C0-U+E0C8" + "U+E0CC-U+E0CF" + "U+E0D0-U+E0D2" + "U+E0D4" + "U+E700-U+E7C5" + "U+F000-U+F2E0" + "U+2665" + "U+26A1" + "U+F400-U+F4A8" + "U+F67C" + "U+E000-U+E00A" + "U+F300-U+F313" + "U+E5FA-U+E62B" + ]; + in + (builtins.concatStringsSep "," mappings) + " Symbols Nerd Font Mono"; + }; + }; + + programs.yazi = { + enable = true; + enableBashIntegration = true; + enableZshIntegration = true; + enableFishIntegration = true; + + settings = { + ration = [ + 1 + 3 + 4 + ]; + }; + }; + + programs.zsh = { + enable = true; + enableCompletion = true; + autosuggestion.enable = true; + syntaxHighlighting.enable = true; + + shellAliases = { + ls = "eza"; + la = "eza -la"; + f = "fzf"; + i = "kitty +kitten icat"; + "nix-switch" = "sudo nixos-rebuild switch --flake .#rpi-4"; + }; + + initContent = '' + fastfetch + ai() { + llm -m groq/groq/compound "$@" | glow + } + ''; + }; + + programs.fish = { + enable = true; + + shellAliases = { + ls = "eza"; + la = "eza -la"; + f = "fzf"; + i = "kitty +kitten icat"; + "nix-switch" = "sudo nixos-rebuild switch --flake .#rpi-4"; + }; + + interactiveShellInit = '' + starship init fish | source + fzf --fish | source + function fish_greeting + fastfetch + end + ''; + + functions.ai = { + body = '' + llm -m groq/groq/compound $argv | glow + ''; + }; + }; + + programs.starship = { + enable = true; + settings = { + add_newline = true; + command_timeout = 500; + + format = '' + $username$hostname $directory $git_branch$git_status + $character ''; + right_format = "$cmd_duration"; + + username = { + style_user = "bold #cba6f7"; + style_root = "bold #f38ba8"; + format = "[┌](bold #a6e3a1)[$user]($style)"; + show_always = true; + }; + + hostname = { + style = "bold #74c7ec"; + format = "[@](bold #fab387)[$hostname]($style)"; + ssh_only = false; + }; + + directory = { + style = "bold #a6e3a1"; + truncation_length = 0; + truncation_symbol = ""; + format = "[⤇ ](bold #f38ba8)[《$path 》]($style)"; + }; + + git_branch = { + format = "[⟦$branch⟧]($style)"; + style = "bold #f9e2af"; + }; + + # Git status module settings + git_status = { + format = "[[(*$conflicted$untracked$modified$staged$renamed$deleted)](red) ($ahead_behind$stashed)]($style)"; + style = "bold #a6e3a1"; + conflicted = ""; + untracked = ""; + modified = ""; + staged = ""; + renamed = ""; + deleted = ""; + }; + + # Command duration module + cmd_duration = { + format = "[$duration]($style)"; + style = "bold #cdd6f4"; + min_time = 5000; # Only show if command takes longer than 5 seconds + }; + + # Character module (prompt symbol) + character = { + success_symbol = "[└──────⇴ ](bold #a6e3a1)"; + error_symbol = "[└──────⇴ ](bold #f38ba8)"; + }; + + nix_shell = { + format = "[$symbol$state( ($name))]($style)"; + symbol = "U+02744"; + style = "bold #89dceb"; + }; + }; + }; + + home.file = { + ".config/fastfetch/config.jsonc".source = ./fastfetch.jsonc; + ".config/tabiew/theme.toml".source = ./tabiew.toml; + ".config/kitty/tab_bar.py".source = ./tab_bar.py; + }; +} diff --git a/home/tab_bar.py b/home/tab_bar.py new file mode 100644 index 0000000..e1bad95 --- /dev/null +++ b/home/tab_bar.py @@ -0,0 +1,34 @@ +from datetime import datetime +from kitty.tab_bar import DrawData, ExtraData, TabBarData, as_rgb +from kitty.fast_data_types import Screen + + +def draw_tab( + draw_data: DrawData, + screen: Screen, + tab: TabBarData, + before: int, + max_title_length: int, + index: int, + is_last: bool, + extra_data: ExtraData, +) -> int: + + # Left side: Current directory or command + screen.cursor.fg = as_rgb(int("a6e3a1", 16)) + screen.cursor.bg = as_rgb(int("1e1e2e", 16)) + + # Get the foreground process (command) or use title + title = tab.active_fg or tab.title or "shell" + screen.draw(f" {title} ") + + # Middle: Nix icon + screen.cursor.fg = as_rgb(int("89dceb", 16)) + screen.draw(" ❄ ") + + # Right: Current time + screen.cursor.fg = as_rgb(int("cdd6f4", 16)) + current_time = datetime.now().strftime("%H:%M") + screen.draw(f"{current_time} ") + + return screen.cursor.x diff --git a/home/tabiew.toml b/home/tabiew.toml new file mode 100644 index 0000000..514af60 --- /dev/null +++ b/home/tabiew.toml @@ -0,0 +1,141 @@ +# Catppuccin Mocha Theme for Tabiew +# Base colors from Catppuccin Mocha palette + +[table_header] +fg = "#F5E0DC" # Rosewater +bg = "#181825" # Mantle +add_modifier = "BOLD" +sub_modifier = "" + +[[table_headers]] +fg = "#F5C2E7" # Pink +bg = "#181825" # Mantle +add_modifier = "BOLD" +sub_modifier = "" + +[[table_headers]] +fg = "#CBA6F7" # Mauve +bg = "#181825" # Mantle +add_modifier = "BOLD" +sub_modifier = "" + +[[table_headers]] +fg = "#89DCEB" # Sky +bg = "#181825" # Mantle +add_modifier = "BOLD" +sub_modifier = "" + +[[rows]] +fg = "#CDD6F4" # Text +bg = "#313244" # Surface0 +add_modifier = "" +sub_modifier = "" + +[[rows]] +fg = "#CDD6F4" # Text +bg = "#181825" # Mantle +add_modifier = "" +sub_modifier = "" + +[highlight] +fg = "#181825" # Mantle +bg = "#F9E2AF" # Yellow +add_modifier = "BOLD" +sub_modifier = "" + +[[table_tags]] +fg = "#181825" # Mantle +bg = "#F38BA8" # Red +add_modifier = "BOLD" +sub_modifier = "" + +[[table_tags]] +fg = "#181825" # Mantle +bg = "#A6E3A1" # Green +add_modifier = "BOLD" +sub_modifier = "" + +[block] +fg = "#FAB387" # Peach +bg = "#313244" # Surface0 +add_modifier = "" +sub_modifier = "" + +[block_tag] +fg = "#181825" # Mantle +bg = "#FAB387" # Peach +add_modifier = "BOLD" +sub_modifier = "" + +[text] +fg = "#CDD6F4" # Text +bg = "#313244" # Surface0 +add_modifier = "" +sub_modifier = "" + +[subtext] +fg = "#9399B2" # Overlay1 +bg = "#313244" # Surface0 +add_modifier = "" +sub_modifier = "" + +[error] +fg = "#CDD6F4" # Text +bg = "#F38BA8" # Red +add_modifier = "BOLD" +sub_modifier = "" + +[[chart]] +fg = "#F38BA8" # Red +bg = "#313244" # Surface0 +add_modifier = "" +sub_modifier = "" + +[[chart]] +fg = "#FAB387" # Peach (Orange) +bg = "#313244" # Surface0 +add_modifier = "" +sub_modifier = "" + +[[chart]] +fg = "#F9E2AF" # Yellow +bg = "#313244" # Surface0 +add_modifier = "" +sub_modifier = "" + +[[chart]] +fg = "#A6E3A1" # Green +bg = "#313244" # Surface0 +add_modifier = "" +sub_modifier = "" + +[[chart]] +fg = "#94E2D5" # Teal +bg = "#313244" # Surface0 +add_modifier = "" +sub_modifier = "" + +[[chart]] +fg = "#89DCEB" # Sky (Cyan) +bg = "#313244" # Surface0 +add_modifier = "" +sub_modifier = "" + +[[chart]] +fg = "#89B4FA" # Blue +bg = "#313244" # Surface0 +add_modifier = "" +sub_modifier = "" + +[[chart]] +fg = "#CBA6F7" # Mauve (Purple) +bg = "#313244" # Surface0 +add_modifier = "" +sub_modifier = "" + +[[chart]] +fg = "#F5C2E7" # Pink +bg = "#313244" # Surface0 +add_modifier = "" +sub_modifier = "" + diff --git a/hosts/cyper-cloud/configuration.nix b/hosts/cyper-cloud/configuration.nix new file mode 100644 index 0000000..fa3b38c --- /dev/null +++ b/hosts/cyper-cloud/configuration.nix @@ -0,0 +1,15 @@ +{ lib, pkgs, ... }: + +{ + networking = { + hostName = lib.mkForce "cyper-cloud"; + useDHCP = true; + nameservers = [ "1.1.1.1" "8.8.8.8" ]; + }; + + environment.systemPackages = with pkgs; [ + kubectl + terraform + awscli2 + ]; +} diff --git a/hosts/cyper-cluster/configuration.nix b/hosts/cyper-cluster/configuration.nix new file mode 100644 index 0000000..70949c3 --- /dev/null +++ b/hosts/cyper-cluster/configuration.nix @@ -0,0 +1,16 @@ +{ lib, pkgs, ... }: + +{ + imports = [ ../services/k3s-agent.nix ]; + + networking = { + hostName = lib.mkForce "cyper-cluster"; + useDHCP = true; + nameservers = [ "1.1.1.1" "8.8.8.8" ]; + }; + + environment.systemPackages = with pkgs; [ + kubectl + helm + ]; +} diff --git a/hosts/cyper-controller/configuration.nix b/hosts/cyper-controller/configuration.nix new file mode 100644 index 0000000..716dd6e --- /dev/null +++ b/hosts/cyper-controller/configuration.nix @@ -0,0 +1,30 @@ +{ lib, pkgs, ... }: + +{ + imports = [ + ../services/k3s-master.nix + ./postgres.nix + #./dns.nix + ]; + + networking = { + hostName = lib.mkForce "cyper-controller"; + useDHCP = false; + interfaces.eth0.ipv4.addresses = [ + { + address = "192.168.2.2"; + prefixLength = 24; + } + ]; + defaultGateway = "192.168.2.1"; + nameservers = [ + "127.0.0.1" + "1.1.1.1" + ]; + }; + + environment.systemPackages = with pkgs; [ + kubectl + dnsutils + ]; +} diff --git a/hosts/cyper-controller/dns.nix b/hosts/cyper-controller/dns.nix new file mode 100644 index 0000000..88a579a --- /dev/null +++ b/hosts/cyper-controller/dns.nix @@ -0,0 +1,36 @@ +{ ... }: + +{ + services.dnsmasq = { + enable = true; + settings = { + # DNS forwarding + domain-needed = true; + bogus-priv = true; + no-resolv = true; + server = [ "1.1.1.1" "8.8.8.8" ]; + + # Local domain + local = "/cyper.local/"; + domain = "cyper.local"; + expand-hosts = true; + + # Static host entries + address = [ + "/cyper-controller.cyper.local/192.168.2.2" + "/cyper-node1.cyper.local/192.168.2.30" + "/cyper-node2.cyper.local/192.168.2.31" + ]; + + # DHCP for dynamic hosts (cyper-cluster, cyper-cloud) + dhcp-range = "192.168.2.100,192.168.2.200,24h"; + dhcp-option = [ + "3,192.168.2.1" # default gateway + "6,192.168.2.2" # DNS server + ]; + }; + }; + + networking.firewall.allowedTCPPorts = [ 53 ]; + networking.firewall.allowedUDPPorts = [ 53 67 68 ]; +} diff --git a/hosts/cyper-controller/postgres.nix b/hosts/cyper-controller/postgres.nix new file mode 100644 index 0000000..1e862cf --- /dev/null +++ b/hosts/cyper-controller/postgres.nix @@ -0,0 +1,57 @@ +{ pkgs, ... }: + +{ + services.postgresql = { + enable = true; + package = pkgs.postgresql_15; + enableTCPIP = true; + + initialScript = pkgs.writeText "backend-init-script" '' + CREATE USER postgres WITH SUPERUSER PASSWORD 'postgres'; + ''; + + # x86_64 server optimized settings (8GB+ RAM assumed) + settings = { + port = 5432; + + # Memory settings + shared_buffers = "2GB"; + effective_cache_size = "6GB"; + maintenance_work_mem = "512MB"; + work_mem = "16MB"; + wal_buffers = "16MB"; + + # Connection settings + max_connections = 100; + + # Performance tuning for x86_64 SSD + random_page_cost = 1.1; + effective_io_concurrency = 200; + + # WAL settings + wal_level = "replica"; + checkpoint_timeout = "15min"; + checkpoint_completion_target = 0.9; + min_wal_size = "1GB"; + max_wal_size = "4GB"; + + # Query planning + default_statistics_target = 100; + + # Logging + log_min_duration_statement = 1000; + log_duration = false; + }; + + authentication = '' + local all all trust + host all all 127.0.0.1/32 md5 + host all all ::1/128 md5 + host all all 192.168.2.0/24 md5 + ''; + }; + + systemd.services.postgresql.wantedBy = [ "multi-user.target" ]; + + networking.firewall.allowedTCPPorts = [ 5432 ]; +} diff --git a/hosts/cyper-node1/configuration.nix b/hosts/cyper-node1/configuration.nix new file mode 100644 index 0000000..b5af2ee --- /dev/null +++ b/hosts/cyper-node1/configuration.nix @@ -0,0 +1,18 @@ +{ lib, ... }: + +{ + imports = [ ../services/k3s-agent.nix ]; + + networking = { + hostName = lib.mkForce "cyper-node1"; + useDHCP = false; + interfaces.eth0.ipv4.addresses = [ + { + address = "192.168.2.30"; + prefixLength = 24; + } + ]; + defaultGateway = "192.168.2.1"; + nameservers = [ "192.168.2.2" ]; + }; +} diff --git a/hosts/cyper-node2/configuration.nix b/hosts/cyper-node2/configuration.nix new file mode 100644 index 0000000..015c6ff --- /dev/null +++ b/hosts/cyper-node2/configuration.nix @@ -0,0 +1,18 @@ +{ lib, ... }: + +{ + imports = [ ../services/k3s-agent.nix ]; + + networking = { + hostName = lib.mkForce "cyper-node2"; + useDHCP = false; + interfaces.eth0.ipv4.addresses = [ + { + address = "192.168.2.31"; + prefixLength = 24; + } + ]; + defaultGateway = "192.168.2.1"; + nameservers = [ "192.168.2.2" ]; + }; +} diff --git a/hosts/services/k3s-agent.nix b/hosts/services/k3s-agent.nix new file mode 100644 index 0000000..1ca22e6 --- /dev/null +++ b/hosts/services/k3s-agent.nix @@ -0,0 +1,23 @@ +{ ... }: + +{ + boot.kernelParams = [ + "cgroup_memory=1" + "cgroup_enable=memory" + "cgroup_enable=cpuset" + ]; + + services.k3s = { + enable = true; + role = "agent"; + serverAddr = "https://192.168.2.2:6443"; + }; + + networking.firewall = { + allowedTCPPortRanges = [ + { from = 10250; to = 10250; } + { from = 30000; to = 32767; } + ]; + trustedInterfaces = [ "cni0" ]; + }; +} diff --git a/hosts/services/k3s-master.nix b/hosts/services/k3s-master.nix new file mode 100644 index 0000000..0e51551 --- /dev/null +++ b/hosts/services/k3s-master.nix @@ -0,0 +1,32 @@ +{ pkgs, ... }: + +{ + boot.kernelParams = [ + "cgroup_memory=1" + "cgroup_enable=memory" + "cgroup_enable=cpuset" + ]; + + services.k3s = { + enable = true; + role = "server"; + clusterInit = true; + extraFlags = '' + --disable=traefik + --flannel-backend=host-gw + ''; + }; + + networking.firewall = { + allowedTCPPorts = [ 6443 ]; + allowedTCPPortRanges = [ + { from = 10250; to = 10250; } + { from = 30000; to = 32767; } + ]; + trustedInterfaces = [ "cni0" ]; + }; + + environment.systemPackages = with pkgs; [ + kubectl + ]; +} diff --git a/nixos/default.nix b/nixos/default.nix new file mode 100644 index 0000000..a19ae44 --- /dev/null +++ b/nixos/default.nix @@ -0,0 +1,113 @@ +{ + pkgs, + primaryUser, + ... +}: + +{ + imports = [ + ./hardware.nix + ./settings.nix + ./packages.nix + ]; + + nixpkgs.config.allowUnfree = true; + + # Speeding up builds + documentation = { + enable = false; + man = { + enable = false; + generateCaches = false; + }; + doc.enable = false; + info.enable = false; + nixos.enable = false; + }; + + # Override python-lsp-server to skip tests (flaky tests cause timeout) + nixpkgs.config.packageOverrides = pkgs: { + python3 = pkgs.python3.override { + packageOverrides = self: super: { + python-lsp-server = super.python-lsp-server.overridePythonAttrs (old: { + doCheck = false; + }); + }; + }; + }; + + networking = { + hostName = "cyper-server"; # overridden per host + useDHCP = false; # overridden per host + networkmanager.enable = false; + enableIPv6 = false; + + firewall = { + enable = true; + allowPing = true; + }; + }; + + # SSH configuration + services.openssh = { + enable = true; + settings.PermitRootLogin = "no"; + settings.PasswordAuthentication = true; + }; + + # User configuration + users.users.${primaryUser} = { + isNormalUser = true; + home = "/home/${primaryUser}"; + description = "Phil"; + hashedPassword = "$6$TqAclAMz/DFP90Ve$HEN4t1pqK36rACeWctJOmLArkTWb/rIBYamu4sY8bPuDnqkVVyfOLqXKkgX8zBf9LKz02.mo4EKFRnYWIzcAX1"; + extraGroups = [ + "wheel" + ]; + shell = pkgs.fish; + openssh.authorizedKeys.keys = [ + "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCaLHfxVylghDMYR8t4QMUpeRRqXasNABQKBEy9MmhbUXCcWiPbPMSZH8FMHON34rm2OrXP1kY/8jQxqBJDA+SqpFR2AZ4Khk9iVMaq5GHxxpn2amZUjoBa+fB29WaiE1npV5JVJV3O0ylw6GtiCnpneE6fGx2MO1vOY/7zKrUX/OK7WfwkDpeEzZgV/j/md917HrzUVeZwdeTq3WCRO8Gew6R8Xs6FRjSiGuH0dq14D4Ow5Zf1cI1jx+JfD/5vGasw8HXPu1NdxsOE+6D7/22IKqGr+S74/lAoyyD5qqk0s05lw8UY/PXBLJaNLZu9Fwx0BqTHpJEvftpmvd9wUxgR3msx9VXtKNSrqivIbDgeU+3oGzzkrGZODl7FCp4XKGmbrX85Z6lKwEGgv5jez4MLZcmT86bxB7m1wIbqSbVtfhS+GI7yPTA/kLzzFa14Im/+LTj95pb8qs2ALMwTMP1j2f9A6D3RriOFihL+68qn+YbK58KuV1R0f+CQRmlfVbk= phil@web.cyperpunk.de" + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEuYuGhqRC/QLoRBH91c3DG5JHlAdRLQsvde18k5ipY2 phil@cyperpunk.de" + ]; + }; + + # Shell + programs.zsh.enable = true; + programs.fish.enable = true; + + # Nix settings + nix = { + settings = { + experimental-features = [ + "nix-command" + "flakes" + ]; + auto-optimise-store = true; + builders-use-substitutes = true; + trusted-substituters = [ "ssh://phil@192.168.2.2" ]; + }; + gc = { + automatic = true; + dates = "weekly"; + options = "--delete-older-than 30d"; + }; + buildMachines = [ + { + hostName = "192.168.2.2"; + system = "x86_64-linux"; + sshUser = "phil"; + maxJobs = 8; + speedFactor = 2; + supportedFeatures = [ + "nixos-test" + "benchmark" + "big-parallel" + "kvm" + ]; + mandatoryFeatures = [ ]; + } + ]; + }; + + system.stateVersion = "25.11"; +} diff --git a/nixos/hardware.nix b/nixos/hardware.nix new file mode 100644 index 0000000..ecd3a63 --- /dev/null +++ b/nixos/hardware.nix @@ -0,0 +1,58 @@ +{ + config, + lib, + pkgs, + modulesPath, + ... +}: + +{ + imports = [ + (modulesPath + "/profiles/qemu-guest.nix") + ]; + + # Bootloader + boot = { + kernelPackages = pkgs.linuxPackages_latest; + initrd.availableKernelModules = [ + "ahci" + "xhci_pci" + "virtio_pci" + "virtio_scsi" + "sd_mod" + "sr_mod" + ]; + initrd.kernelModules = [ ]; + kernelModules = [ "kvm-intel" ]; + extraModulePackages = [ ]; + + loader = { + systemd-boot.enable = true; + efi.canTouchEfiVariables = true; + }; + }; + + # File systems + fileSystems."/" = { + device = "/dev/disk/by-label/nixos"; + fsType = "ext4"; + options = [ "noatime" ]; + }; + + fileSystems."/boot" = { + device = "/dev/disk/by-label/boot"; + fsType = "vfat"; + }; + + # Swap + swapDevices = [ + { + device = "/swapfile"; + size = 4096; + } + ]; + + # x86_64 hardware + hardware.enableRedistributableFirmware = true; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/nixos/packages.nix b/nixos/packages.nix new file mode 100644 index 0000000..696ed08 --- /dev/null +++ b/nixos/packages.nix @@ -0,0 +1,19 @@ +{ config, pkgs, ... }: + +{ + environment.systemPackages = with pkgs; [ + git + curl + wget + htop + neovim + tmux + ripgrep + fd + bat + eza + fzf + tree + fish + ]; +} diff --git a/nixos/settings.nix b/nixos/settings.nix new file mode 100644 index 0000000..bab9c20 --- /dev/null +++ b/nixos/settings.nix @@ -0,0 +1,21 @@ +{ config, pkgs, ... }: + +{ + # Localization + time.timeZone = "Europe/Berlin"; + i18n.defaultLocale = "en_US.UTF-8"; + i18n.extraLocaleSettings = { + LC_ADDRESS = "de_DE.UTF-8"; + LC_IDENTIFICATION = "de_DE.UTF-8"; + LC_MEASUREMENT = "de_DE.UTF-8"; + LC_MONETARY = "de_DE.UTF-8"; + LC_NAME = "de_DE.UTF-8"; + LC_NUMERIC = "de_DE.UTF-8"; + LC_PAPER = "de_DE.UTF-8"; + LC_TELEPHONE = "de_DE.UTF-8"; + LC_TIME = "de_DE.UTF-8"; + }; + + # System settings + console.keyMap = "de"; +}