From 5c2e25b98950aa8cfa026a5743714ba4c1e88d4c Mon Sep 17 00:00:00 2001 From: luochen570 <1160510664@qq.com> Date: Thu, 22 Oct 2026 10:20:30 +0800 Subject: [PATCH] feat(nixos): integrate agent VM into host configurations --- README.md | 6 + flake.lock | 582 ++++++++++++++++++++++++- flake.nix | 46 +- hosts/agent/README.md | 15 + hosts/agent/configuration.nix | 33 ++ hosts/agent/default.nix | 6 + hosts/agent/hardware-configuration.nix | 27 ++ hosts/agent/home.nix | 54 +++ lib/hosts.nix | 9 + lib/mkHost.nix | 23 +- modules/agent/default.nix | 6 + modules/agent/network.nix | 29 ++ modules/agent/nix.nix | 13 + profiles/agent.nix | 5 + 14 files changed, 826 insertions(+), 28 deletions(-) create mode 100644 hosts/agent/README.md create mode 100644 hosts/agent/configuration.nix create mode 100644 hosts/agent/default.nix create mode 100644 hosts/agent/hardware-configuration.nix create mode 100644 hosts/agent/home.nix create mode 100644 modules/agent/default.nix create mode 100644 modules/agent/network.nix create mode 100644 modules/agent/nix.nix create mode 100644 profiles/agent.nix diff --git a/README.md b/README.md index 37f474d..8ab781e 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ nixos/ │ ├── README.md │ ├── desktop.nix # 桌面机 │ ├── server.nix # 服务器 +│ ├── agent.nix # AI agent VM(不引入 Docker/免密 sudo) │ ├── wsl.nix # WSL (Debian/Windows) │ ├── virtualbox.nix # VirtualBox 虚拟机 │ └── lxc.nix # Proxmox LXC 容器 @@ -53,6 +54,7 @@ nixos/ │ └── nvchad.nix # Neovim (NvChad) ├── hosts/ # 主机专属配置 │ ├── README.md +│ ├── agent/ # AI agent VM + Home Manager + hardware │ ├── desktop/ # 桌面机(AMD + NVIDIA) │ ├── server/ # 服务器 │ ├── wsl/ # WSL (NixOS-WSL) @@ -66,6 +68,7 @@ nixos/ | 主机 | 角色 | 架构 | 说明 | |------|------|------|------| +| `agent` | agent | x86_64-linux | AI Agent VM,CERNET 镜像与 Mihomo TUN | | `desktop` | desktop | x86_64-linux | 桌面机,NVIDIA + AMD 双显卡 | | `server` | server | x86_64-linux | 服务器 | | `nixos-wsl` | wsl | x86_64-linux | WSL | @@ -81,6 +84,9 @@ sudo nixos-rebuild switch --flake .#desktop # 仅构建不切换 sudo nixos-rebuild build --flake .#server +# AI Agent VM:保留独立的 SSH、sudo 和 Mihomo 设置 +sudo nixos-rebuild switch --flake .#agent + # 更新 flake lock nix flake update diff --git a/flake.lock b/flake.lock index 5266c79..bd47604 100644 --- a/flake.lock +++ b/flake.lock @@ -1,5 +1,87 @@ { "nodes": { + "agent-nix4nvchad": { + "inputs": { + "nixpkgs": [ + "agent-nixpkgs" + ], + "nvchad-starter": "nvchad-starter" + }, + "locked": { + "lastModified": 1792593944, + "narHash": "sha256-CiqzeKQdtkkW56w/KZq6orzsPC6vHZqYYbJ3kqhEIy0=", + "owner": "nix-community", + "repo": "nix4nvchad", + "rev": "042bbb1be519d01c76d8c65b2e004212b5b706ad", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nix4nvchad", + "rev": "042bbb1be519d01c76d8c65b2e004212b5b706ad", + "type": "github" + } + }, + "agent-nixpkgs": { + "locked": { + "lastModified": 315532800, + "narHash": "sha256-OtQ9jaQ9aXZDm61TqykPLZdXJa2NMykYG3d0tbT683U=", + "type": "tarball", + "url": "https://mirrors.cernet.edu.cn/nix-channels/nixos-26.05/nixexprs.tar.xz" + }, + "original": { + "type": "tarball", + "url": "https://mirrors.cernet.edu.cn/nix-channels/nixos-26.05/nixexprs.tar.xz" + } + }, + "bun2nix": { + "inputs": { + "flake-parts": "flake-parts_2", + "nixpkgs": [ + "omp", + "nixpkgs" + ], + "systems": "systems_2", + "treefmt-nix": "treefmt-nix" + }, + "locked": { + "lastModified": 1784665499, + "narHash": "sha256-9BMxlTxCCDAeoNLtb1a/st7udtTIJep+wpUzquA29VU=", + "owner": "nix-community", + "repo": "bun2nix", + "rev": "0f2a1f0b6f42cebe3b149bf62d38754c5e0e9729", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "bun2nix", + "type": "github" + } + }, + "bun2nix-darwin-x64": { + "inputs": { + "flake-parts": "flake-parts_3", + "nixpkgs": [ + "omp", + "nixpkgs-darwin-x64" + ], + "systems": "systems_3", + "treefmt-nix": "treefmt-nix_2" + }, + "locked": { + "lastModified": 1784665499, + "narHash": "sha256-9BMxlTxCCDAeoNLtb1a/st7udtTIJep+wpUzquA29VU=", + "owner": "nix-community", + "repo": "bun2nix", + "rev": "0f2a1f0b6f42cebe3b149bf62d38754c5e0e9729", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "bun2nix", + "type": "github" + } + }, "flake-compat": { "flake": false, "locked": { @@ -17,6 +99,71 @@ } }, "flake-parts": { + "inputs": { + "nixpkgs-lib": [ + "hermes-agent", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1782949081, + "narHash": "sha256-vp6Y/Grm98ESt6ceOkWiHWyZRDV3J1RID4w+6NWK9yA=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "17c9d6cdfc60c64f4ee8d306f9bc0b4ccb51481e", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-parts_2": { + "inputs": { + "nixpkgs-lib": [ + "omp", + "bun2nix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1782949081, + "narHash": "sha256-vp6Y/Grm98ESt6ceOkWiHWyZRDV3J1RID4w+6NWK9yA=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "17c9d6cdfc60c64f4ee8d306f9bc0b4ccb51481e", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-parts_3": { + "inputs": { + "nixpkgs-lib": [ + "omp", + "bun2nix-darwin-x64", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1782949081, + "narHash": "sha256-vp6Y/Grm98ESt6ceOkWiHWyZRDV3J1RID4w+6NWK9yA=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "17c9d6cdfc60c64f4ee8d306f9bc0b4ccb51481e", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-parts_4": { "inputs": { "nixpkgs-lib": "nixpkgs-lib" }, @@ -34,7 +181,92 @@ "type": "github" } }, + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "herdr-nix": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1791994266, + "narHash": "sha256-o4QvYScvUHcOtYw3kFX5Tc+BG51kmyvHahIKZDERNG0=", + "owner": "herdrdev", + "repo": "herdr-nix", + "rev": "602c88543e53f33273ea913b774dfea0a812ac12", + "type": "github" + }, + "original": { + "owner": "herdrdev", + "repo": "herdr-nix", + "type": "github" + } + }, + "hermes-agent": { + "inputs": { + "flake-parts": "flake-parts", + "home-manager": "home-manager", + "nixpkgs": "nixpkgs", + "npm-lockfile-fix": "npm-lockfile-fix", + "pyproject-build-systems": "pyproject-build-systems", + "pyproject-nix": "pyproject-nix", + "uv2nix": "uv2nix" + }, + "locked": { + "lastModified": 1792592505, + "narHash": "sha256-qEYju2lK48R+aT+ry0aiT3JNAwOaXx49h/VMjZR7djE=", + "owner": "NousResearch", + "repo": "hermes-agent", + "rev": "3f2afed3eb813cb00bd381d29b084d0e01de048f", + "type": "github" + }, + "original": { + "owner": "NousResearch", + "repo": "hermes-agent", + "rev": "3f2afed3eb813cb00bd381d29b084d0e01de048f", + "type": "github" + } + }, "home-manager": { + "inputs": { + "nixpkgs": [ + "hermes-agent", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1786487128, + "narHash": "sha256-ad60hrRVhH/bo3Jl1YLzO+QcS3mUNZr9LNJdzhMO2P4=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "f404edbfa4117810c96b97048299242fc50e5362", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "home-manager", + "type": "github" + } + }, + "home-manager_2": { "inputs": { "nixpkgs": [ "nixpkgs" @@ -55,12 +287,33 @@ "type": "github" } }, + "nix-bun": { + "inputs": { + "nixpkgs": [ + "omp", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1789370898, + "narHash": "sha256-QBlvSGth1NfAWw7iePOzFlrz0/pX6CfkFCcPALdySNI=", + "owner": "ryoppippi", + "repo": "nix-bun", + "rev": "48e887d7955c1c05b8d4627ed39bafe4bf2455a7", + "type": "github" + }, + "original": { + "owner": "ryoppippi", + "repo": "nix-bun", + "type": "github" + } + }, "nix4nvchad": { "inputs": { "nixpkgs": [ "nixpkgs" ], - "nvchad-starter": "nvchad-starter" + "nvchad-starter": "nvchad-starter_2" }, "locked": { "lastModified": 1786241713, @@ -100,16 +353,32 @@ }, "nixpkgs": { "locked": { - "lastModified": 1786430034, - "narHash": "sha256-Vux08kA5PICwS2sViCMfwVLAHNoH8TkKAeBo25LjpMI=", + "lastModified": 1785318670, + "narHash": "sha256-dN6Ou5x/+23FZLEpYP3IffO+NyJFzUlGumt1uu3MMaY=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "70cc4559b10a6062b05ff1af17e0add065ccaed9", + "rev": "0954f7ee2f6bb3dc7d4e3d0d8bcb8fd4bde4cfc5", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixos-26.05", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-darwin-x64": { + "locked": { + "lastModified": 1786527240, + "narHash": "sha256-OLtJPnSXcRy79Rf7BhYaMeXAVF625FpLcd3+Svq641Y=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "e0c84f9d0ad137f076dc957494f5b39885597d4f", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-26.05-darwin", "repo": "nixpkgs", "type": "github" } @@ -129,6 +398,71 @@ "type": "github" } }, + "nixpkgs-unstable": { + "locked": { + "lastModified": 315532800, + "narHash": "sha256-ij8QUxzTOHovLrNOxVRx+RAhGQFOMsJbji0veiatH5k=", + "type": "tarball", + "url": "https://mirrors.cernet.edu.cn/nix-channels/nixos-unstable/nixexprs.tar.xz" + }, + "original": { + "type": "tarball", + "url": "https://mirrors.cernet.edu.cn/nix-channels/nixos-unstable/nixexprs.tar.xz" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1786430034, + "narHash": "sha256-Vux08kA5PICwS2sViCMfwVLAHNoH8TkKAeBo25LjpMI=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "70cc4559b10a6062b05ff1af17e0add065ccaed9", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-26.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_3": { + "locked": { + "lastModified": 1786384358, + "narHash": "sha256-RzPPiWeUtuvymnpuEWsdtzli5w4kjZs49FqEs3/1u+I=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "2fcb964de67fcf60b43471c55d5d99e61a9ccb5a", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "npm-lockfile-fix": { + "inputs": { + "nixpkgs": [ + "hermes-agent", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1775903712, + "narHash": "sha256-2GV79U6iVH4gKAPWYrxUReB0S41ty/Y3dBLquU8AlaA=", + "owner": "jeslie0", + "repo": "npm-lockfile-fix", + "rev": "c6093acb0c0548e0f9b8b3d82918823721930fe8", + "type": "github" + }, + "original": { + "owner": "jeslie0", + "repo": "npm-lockfile-fix", + "type": "github" + } + }, "nvchad-starter": { "flake": false, "locked": { @@ -146,16 +480,134 @@ "type": "github" } }, + "nvchad-starter_2": { + "flake": false, + "locked": { + "lastModified": 1753939018, + "narHash": "sha256-xdLr6tlU9uA+wu0pqha2br0fdVm+1MjgjbB5awz9ICU=", + "owner": "NvChad", + "repo": "starter", + "rev": "e3572e1f5e1c297212c3deeb17b7863139ce663e", + "type": "github" + }, + "original": { + "owner": "NvChad", + "ref": "main", + "repo": "starter", + "type": "github" + } + }, + "omp": { + "inputs": { + "bun2nix": "bun2nix", + "bun2nix-darwin-x64": "bun2nix-darwin-x64", + "nix-bun": "nix-bun", + "nixpkgs": "nixpkgs_3", + "nixpkgs-darwin-x64": "nixpkgs-darwin-x64", + "rust-overlay": "rust-overlay" + }, + "locked": { + "lastModified": 1792592597, + "narHash": "sha256-ZLfGaB6BKOeOgKs3EbMMcJWJGvu58woVqs8K6QE6Erw=", + "owner": "can1357", + "repo": "oh-my-pi", + "rev": "08542ed0df02ecaa78aaab28388aa6a563045f16", + "type": "github" + }, + "original": { + "owner": "can1357", + "repo": "oh-my-pi", + "rev": "08542ed0df02ecaa78aaab28388aa6a563045f16", + "type": "github" + } + }, + "pyproject-build-systems": { + "inputs": { + "nixpkgs": [ + "hermes-agent", + "nixpkgs" + ], + "pyproject-nix": [ + "hermes-agent", + "pyproject-nix" + ], + "uv2nix": [ + "hermes-agent", + "uv2nix" + ] + }, + "locked": { + "lastModified": 1785115949, + "narHash": "sha256-8AM37BfyGaL2v/SZyg4PupRxJ01Y4htvM+WrTjWrPpo=", + "owner": "pyproject-nix", + "repo": "build-system-pkgs", + "rev": "62c0d86027edb1c4f39a5facc09876348144f7c9", + "type": "github" + }, + "original": { + "owner": "pyproject-nix", + "repo": "build-system-pkgs", + "type": "github" + } + }, + "pyproject-nix": { + "inputs": { + "nixpkgs": [ + "hermes-agent", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1784591072, + "narHash": "sha256-zP/WaDxrRu8GANZM61+V2LT/7ycEEdoyLWn7M6WzU7M=", + "owner": "pyproject-nix", + "repo": "pyproject.nix", + "rev": "e3b599ca2e7fcf93d4edf65d7f19bbf6491724f3", + "type": "github" + }, + "original": { + "owner": "pyproject-nix", + "repo": "pyproject.nix", + "type": "github" + } + }, "root": { "inputs": { - "home-manager": "home-manager", + "agent-nix4nvchad": "agent-nix4nvchad", + "agent-nixpkgs": "agent-nixpkgs", + "herdr-nix": "herdr-nix", + "hermes-agent": "hermes-agent", + "home-manager": "home-manager_2", "nix4nvchad": "nix4nvchad", "nixos-wsl": "nixos-wsl", - "nixpkgs": "nixpkgs", + "nixpkgs": "nixpkgs_2", + "nixpkgs-unstable": "nixpkgs-unstable", + "omp": "omp", "sops-nix": "sops-nix", "vscode-server": "vscode-server" } }, + "rust-overlay": { + "inputs": { + "nixpkgs": [ + "omp", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1791276535, + "narHash": "sha256-iwqAmHTX1IgzTumJR3JayNAQAo5xEmmOuGzB6b2pT/Q=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "b962e5d0c8cd97196c6a882d659fe451b52ad989", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, "sops-nix": { "inputs": { "nixpkgs": [ @@ -176,9 +628,123 @@ "type": "github" } }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_2": { + "locked": { + "lastModified": 1776166891, + "narHash": "sha256-bI8yrEGjrohR5hkQox7UrxDH7XqrYMwI8SL/LrJ1+S8=", + "owner": "nix-systems", + "repo": "triplet", + "rev": "6de7bc09397911ce03636afbcf6118745ab2cda0", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "triplet", + "type": "github" + } + }, + "systems_3": { + "locked": { + "lastModified": 1680978224, + "narHash": "sha256-+xT9B1ZbhMg/zpJqd00S06UCZb/A2URW9bqqrZ/JTOg=", + "owner": "nix-systems", + "repo": "x86_64-darwin", + "rev": "db0463cce4cd60fb791f33a83d29a1ed53edab9b", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "x86_64-darwin", + "type": "github" + } + }, + "treefmt-nix": { + "inputs": { + "nixpkgs": [ + "omp", + "bun2nix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1784369104, + "narHash": "sha256-47cxbcZODibHv3rELFQ9vZly0vUNkND/atn/U7HLeb0=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "df3c0640565d04a0261253cdd89fce78ec50168a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } + }, + "treefmt-nix_2": { + "inputs": { + "nixpkgs": [ + "omp", + "bun2nix-darwin-x64", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1784369104, + "narHash": "sha256-47cxbcZODibHv3rELFQ9vZly0vUNkND/atn/U7HLeb0=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "df3c0640565d04a0261253cdd89fce78ec50168a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } + }, + "uv2nix": { + "inputs": { + "nixpkgs": [ + "hermes-agent", + "nixpkgs" + ], + "pyproject-nix": [ + "hermes-agent", + "pyproject-nix" + ] + }, + "locked": { + "lastModified": 1785277507, + "narHash": "sha256-9Tq3UDX2hD/aveW/HvkBlAmEwJTOlY5HQXJM+L5BGmE=", + "owner": "pyproject-nix", + "repo": "uv2nix", + "rev": "5a836d395cbf5fc22670eb98dd4aa4fc4d406977", + "type": "github" + }, + "original": { + "owner": "pyproject-nix", + "repo": "uv2nix", + "type": "github" + } + }, "vscode-server": { "inputs": { - "flake-parts": "flake-parts" + "flake-parts": "flake-parts_4" }, "locked": { "lastModified": 1784312229, diff --git a/flake.nix b/flake.nix index 3259367..593fc73 100644 --- a/flake.nix +++ b/flake.nix @@ -3,6 +3,15 @@ inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-26.05"; + agent-nixpkgs.url = "tarball+https://mirrors.cernet.edu.cn/nix-channels/nixos-26.05/nixexprs.tar.xz"; + nixpkgs-unstable.url = "tarball+https://mirrors.cernet.edu.cn/nix-channels/nixos-unstable/nixexprs.tar.xz"; + # Exact revisions of the source archives previously used on agent. + hermes-agent.url = "github:NousResearch/hermes-agent/3f2afed3eb813cb00bd381d29b084d0e01de048f"; + omp.url = "github:can1357/oh-my-pi/08542ed0df02ecaa78aaab28388aa6a563045f16"; + herdr-nix = { + url = "github:herdrdev/herdr-nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; home-manager = { url = "github:nix-community/home-manager/release-26.05"; @@ -14,6 +23,11 @@ url = "github:nix-community/nix4nvchad"; inputs.nixpkgs.follows = "nixpkgs"; }; + # Keep the agent VM on its currently installed NvChad module revision. + agent-nix4nvchad = { + url = "github:nix-community/nix4nvchad/042bbb1be519d01c76d8c65b2e004212b5b706ad"; + inputs.nixpkgs.follows = "agent-nixpkgs"; + }; # NixOS WSL nixos-wsl = { @@ -31,17 +45,25 @@ }; }; - outputs = inputs@{ nixpkgs, home-manager, ... }: - let - username = "luochen570"; - hosts = import ./lib/hosts.nix; - mkHost = import ./lib/mkHost.nix { - inherit nixpkgs home-manager inputs; + outputs = + inputs@{ nixpkgs, home-manager, ... }: + let + username = "luochen570"; + hosts = import ./lib/hosts.nix; + mkConfiguredHost = + hostname: cfg: + (import ./lib/mkHost.nix { + nixpkgs = if hostname == "agent" then inputs.agent-nixpkgs else nixpkgs; + inherit home-manager inputs; + }) + ( + { + inherit hostname username; + } + // cfg + ); + in + { + nixosConfigurations = nixpkgs.lib.mapAttrs mkConfiguredHost hosts; }; - mkConfiguredHost = hostname: cfg: mkHost ({ - inherit hostname username; - } // cfg); - in { - nixosConfigurations = nixpkgs.lib.mapAttrs mkConfiguredHost hosts; - }; } diff --git a/hosts/agent/README.md b/hosts/agent/README.md new file mode 100644 index 0000000..30f22a1 --- /dev/null +++ b/hosts/agent/README.md @@ -0,0 +1,15 @@ +# agent + +NixOS 26.05 VM at `s0.sermc.net` (SSH externally on port 6522), managed by `.#agent`. +This host intentionally does not import the shared `server` profile: that profile enables Docker and disables wheel sudo prompts, whereas the existing agent VM does neither. SSH replies bypass Mihomo TUN via `ssh-direct-route`. + +Apply on the VM from a checkout with its locked inputs: + +```sh +sudo nixos-rebuild build --flake .#agent +sudo nixos-rebuild switch --flake .#agent +``` + +`/etc/mihomo-config.yaml` is a root-owned mode-0600 subscription with credentials. It stays outside Git and must be provisioned separately before enabling Mihomo. Never place the subscription, API keys, or SSH secrets in the Nix store or this public repository. + +Hermes Agent and OMP are pinned to the exact upstream commits from which the previous local archives were extracted. Their `flake.nix` hashes matched the old local trees before cutover; the full packages must still build and pass the CLI smoke check after re-locking. The server needs the pinned sources and binary caches available at build time. diff --git a/hosts/agent/configuration.nix b/hosts/agent/configuration.nix new file mode 100644 index 0000000..fa05a2d --- /dev/null +++ b/hosts/agent/configuration.nix @@ -0,0 +1,33 @@ +{ + boot.loader.grub = { + enable = true; + device = "/dev/sda"; + useOSProber = true; + }; + + networking.networkmanager.enable = true; + + time.timeZone = "Asia/Shanghai"; + i18n.defaultLocale = "zh_CN.UTF-8"; + i18n.extraLocaleSettings = { + LC_ADDRESS = "zh_CN.UTF-8"; + LC_IDENTIFICATION = "zh_CN.UTF-8"; + LC_MEASUREMENT = "zh_CN.UTF-8"; + LC_MONETARY = "zh_CN.UTF-8"; + LC_NAME = "zh_CN.UTF-8"; + LC_NUMERIC = "zh_CN.UTF-8"; + LC_PAPER = "zh_CN.UTF-8"; + LC_TELEPHONE = "zh_CN.UTF-8"; + LC_TIME = "zh_CN.UTF-8"; + }; + services.xserver.xkb.layout = "cn"; + + users.users.luochen570 = { + isNormalUser = true; + description = "luochen570"; + extraGroups = [ + "networkmanager" + "wheel" + ]; + }; +} diff --git a/hosts/agent/default.nix b/hosts/agent/default.nix new file mode 100644 index 0000000..cd4010f --- /dev/null +++ b/hosts/agent/default.nix @@ -0,0 +1,6 @@ +{ + imports = [ + ./hardware-configuration.nix + ./configuration.nix + ]; +} diff --git a/hosts/agent/hardware-configuration.nix b/hosts/agent/hardware-configuration.nix new file mode 100644 index 0000000..4ecf78a --- /dev/null +++ b/hosts/agent/hardware-configuration.nix @@ -0,0 +1,27 @@ +# Generated by nixos-generate-config for this VM; keep device UUID intact. +{ + lib, + modulesPath, + ... +}: + +{ + imports = [ (modulesPath + "/profiles/qemu-guest.nix") ]; + + boot.initrd.availableKernelModules = [ + "ata_piix" + "uhci_hcd" + "virtio_pci" + "virtio_scsi" + "sd_mod" + "sr_mod" + ]; + boot.kernelModules = [ "kvm-amd" ]; + + fileSystems."/" = { + device = "/dev/disk/by-uuid/182efe7c-8bb0-4229-8815-1c58bf67dde4"; + fsType = "ext4"; + }; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; +} diff --git a/hosts/agent/home.nix b/hosts/agent/home.nix new file mode 100644 index 0000000..44b8c83 --- /dev/null +++ b/hosts/agent/home.nix @@ -0,0 +1,54 @@ +{ + pkgs, + inputs, + system, + ... +}: + +{ + imports = [ inputs.agent-nix4nvchad.homeManagerModules.default ]; + + home.username = "luochen570"; + home.homeDirectory = "/home/luochen570"; + programs.nvchad.enable = true; + + home.packages = with pkgs; [ + inputs.hermes-agent.packages.${system}.default + inputs.omp.packages.${system}.default + inputs.nixpkgs-unstable.legacyPackages.${system}.cc-switch-cli + inputs.herdr-nix.packages.${system}.default + codex + opencode + pi-coding-agent + zeroclaw + htop + fastfetch + hyfetch # Provides the maintained neofetch command. + zsh + eza + uv + bat + yazi + ncdu + duf + git + gh + podman + vim + tailscale + docker-client + curl + wget + fzf + unzip + zip + p7zip + unrar + gzip + bzip2 + xz + zstd + libarchive + gnutar + ]; +} diff --git a/lib/hosts.nix b/lib/hosts.nix index 21830e8..c01f698 100644 --- a/lib/hosts.nix +++ b/lib/hosts.nix @@ -1,4 +1,13 @@ { + agent = { + system = "x86_64-linux"; + profile = "agent"; + systemStateVersion = "26.05"; + homeStateVersion = "26.05"; + homeModules = [ ../hosts/agent/home.nix ]; + useSops = false; + }; + desktop = { system = "x86_64-linux"; profile = "desktop"; diff --git a/lib/mkHost.nix b/lib/mkHost.nix index 188927c..e826dd6 100644 --- a/lib/mkHost.nix +++ b/lib/mkHost.nix @@ -1,4 +1,8 @@ -{ nixpkgs, home-manager, inputs }: +{ + nixpkgs, + home-manager, + inputs, +}: { hostname, hostName ? hostname, @@ -8,15 +12,18 @@ username, extraModules ? [ ], extraSpecialArgs ? { }, + homeModules ? [ ../home ], + homeStateVersion ? "25.05", + useSops ? true, }: nixpkgs.lib.nixosSystem { inherit system; specialArgs = { inherit inputs system username; - } // extraSpecialArgs; + } + // extraSpecialArgs; modules = [ - inputs.sops-nix.nixosModules.sops ../hosts/${hostname} ../profiles/${profile}.nix { @@ -31,11 +38,11 @@ nixpkgs.lib.nixosSystem { inherit inputs system; }; home-manager.users.${username} = { - home.stateVersion = "25.05"; - imports = [ - ../home - ]; + home.stateVersion = homeStateVersion; + imports = homeModules; }; } - ] ++ extraModules; + ] + ++ nixpkgs.lib.optionals useSops [ inputs.sops-nix.nixosModules.sops ] + ++ extraModules; } diff --git a/modules/agent/default.nix b/modules/agent/default.nix new file mode 100644 index 0000000..ae0b3dc --- /dev/null +++ b/modules/agent/default.nix @@ -0,0 +1,6 @@ +{ + imports = [ + ./nix.nix + ./network.nix + ]; +} diff --git a/modules/agent/network.nix b/modules/agent/network.nix new file mode 100644 index 0000000..accb0ec --- /dev/null +++ b/modules/agent/network.nix @@ -0,0 +1,29 @@ +{ pkgs, ... }: + +{ + services.openssh.enable = true; + + services.mihomo = { + enable = true; + tunMode = true; + configFile = "/etc/mihomo-config.yaml"; + }; + + systemd.services.mihomo = { + after = [ "ssh-direct-route.service" ]; + requires = [ "ssh-direct-route.service" ]; + }; + + # Keep SSH replies outside the transparent proxy before Mihomo starts. + systemd.services.ssh-direct-route = { + description = "Keep SSH replies on the unmodified main routing table"; + wantedBy = [ "multi-user.target" ]; + before = [ "mihomo.service" ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + ExecStart = "${pkgs.iproute2}/bin/ip rule add pref 8000 ipproto tcp sport 22 lookup main"; + ExecStop = "${pkgs.iproute2}/bin/ip rule del pref 8000 ipproto tcp sport 22 lookup main"; + }; + }; +} diff --git a/modules/agent/nix.nix b/modules/agent/nix.nix new file mode 100644 index 0000000..c99adf5 --- /dev/null +++ b/modules/agent/nix.nix @@ -0,0 +1,13 @@ +{ + nix.settings = { + experimental-features = [ + "nix-command" + "flakes" + ]; + substituters = [ + "https://mirrors.cernet.edu.cn/nix-channels/store?priority=10" + ]; + }; + + nixpkgs.config.allowUnfree = true; +} diff --git a/profiles/agent.nix b/profiles/agent.nix new file mode 100644 index 0000000..39bda81 --- /dev/null +++ b/profiles/agent.nix @@ -0,0 +1,5 @@ +{ + # This VM keeps password-based SSH and password-protected sudo. The shared + # server profile enables Docker and the core profile disables sudo prompts. + imports = [ ../modules/agent ]; +}