docs: NixOS deployment guide from Camellia
This commit is contained in:
@@ -0,0 +1,194 @@
|
||||
# Deploying nanobot on NixOS
|
||||
|
||||
This documents what it took to get nanobot running on Camellia (NixOS 26.05).
|
||||
|
||||
See `/etc/nixos/configuration.nix` for the full config — every block below has a matching section there.
|
||||
|
||||
## 1. Base system
|
||||
|
||||
```nix
|
||||
# Hostname, timezone, SSH, fail2ban
|
||||
networking.hostName = "Camellia";
|
||||
time.timeZone = "Asia/Shanghai";
|
||||
services.openssh = { enable = true; ... };
|
||||
services.fail2ban = { enable = true; };
|
||||
```
|
||||
|
||||
## 2. Required packages
|
||||
|
||||
```nix
|
||||
environment.systemPackages = with pkgs; [
|
||||
git curl wget vim tmux htop jq fd ripgrep
|
||||
python313 uv # nanobot runtime
|
||||
nodejs_22 # for some skills/tools
|
||||
];
|
||||
```
|
||||
|
||||
## 3. Users
|
||||
|
||||
Create a dedicated user for nanobot with lingering enabled:
|
||||
|
||||
```nix
|
||||
users.users.claw = {
|
||||
extraGroups = ["sudo"];
|
||||
isNormalUser = true;
|
||||
linger = true; # user services survive logout
|
||||
};
|
||||
security.sudo.extraRules = [
|
||||
{ users = ["claw"]; commands = [{ command = "ALL"; options = ["NOPASSWD"]; }]; }
|
||||
];
|
||||
```
|
||||
|
||||
## 4. FHS symlinks
|
||||
|
||||
nanobot's `exec` tool (and many scripts) expect `/bin/bash`:
|
||||
|
||||
```nix
|
||||
systemd.tmpfiles.rules = [
|
||||
"L+ /bin/bash - - - - /run/current-system/sw/bin/bash"
|
||||
"L+ /usr/bin/env - - - - /run/current-system/sw/bin/env"
|
||||
];
|
||||
```
|
||||
|
||||
## 5. nanobot systemd user service
|
||||
|
||||
```nix
|
||||
systemd.user.services.nanobot = {
|
||||
description = "nanobot AI assistant gateway";
|
||||
wantedBy = ["default.target"];
|
||||
serviceConfig = {
|
||||
Type = "simple";
|
||||
ExecStart = "/home/claw/nanobot-src/.venv/bin/python -m nanobot gateway --foreground --port 18790";
|
||||
Restart = "always";
|
||||
RestartSec = 5;
|
||||
WorkingDirectory = "/home/claw/.nanobot/workspace";
|
||||
Environment = "HOME=/home/claw";
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
Use a git checkout (`/home/claw/nanobot-src`) so you can `git checkout known-good` to rollback.
|
||||
|
||||
## 6. Watchdog timer
|
||||
|
||||
Covers the case where systemd misses a crash:
|
||||
|
||||
```nix
|
||||
systemd.user.services.nanobot-watchdog = {
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
ExecStart = "${pkgs.systemd}/bin/systemctl --user start nanobot";
|
||||
};
|
||||
};
|
||||
systemd.user.timers.nanobot-watchdog = {
|
||||
timerConfig = { OnUnitActiveSec = "60s"; };
|
||||
};
|
||||
```
|
||||
|
||||
## 7. Reverse proxy (Caddy)
|
||||
|
||||
nanobot's gateway binds to `127.0.0.1` by default and rejects non-local connections. For a dedicated VM this is over-cautious, so we use Caddy to reverse-proxy the WebSocket UI externally:
|
||||
|
||||
```nix
|
||||
services.caddy = {
|
||||
enable = true;
|
||||
virtualHosts."http://192.168.122.194".extraConfig = ''
|
||||
reverse_proxy 127.0.0.1:8765
|
||||
'';
|
||||
};
|
||||
```
|
||||
|
||||
## 8. Proxy for outbound traffic (v2rayA)
|
||||
|
||||
If the LLM API and Telegram are blocked:
|
||||
|
||||
```nix
|
||||
services.v2raya = { enable = true; };
|
||||
```
|
||||
|
||||
Then configure proxy env vars in `~/.bashrc`:
|
||||
|
||||
```bash
|
||||
export http_proxy=http://127.0.0.1:20171
|
||||
export https_proxy=http://127.0.0.1:20171
|
||||
export all_proxy=socks5://127.0.0.1:20170
|
||||
```
|
||||
|
||||
## 9. OOM protection
|
||||
|
||||
nanobot can spike memory. Without this, the kernel OOM killer takes it down:
|
||||
|
||||
```nix
|
||||
services.earlyoom = {
|
||||
enable = true;
|
||||
freeMemThreshold = 5;
|
||||
freeSwapThreshold = 10;
|
||||
};
|
||||
swapDevices = [{ device = "/swapfile"; size = 2048; }]; # 2 GB
|
||||
```
|
||||
|
||||
## 10. Firewall
|
||||
|
||||
```nix
|
||||
networking.firewall.allowedTCPPorts = [
|
||||
22 # SSH
|
||||
80 # Caddy HTTP
|
||||
2017 # v2rayA web UI
|
||||
20170 # v2rayA SOCKS5
|
||||
20171 # v2rayA HTTP proxy
|
||||
];
|
||||
```
|
||||
|
||||
## 11. Kernel hardening
|
||||
|
||||
```nix
|
||||
boot.kernel.sysctl = {
|
||||
"net.ipv4.tcp_syncookies" = 1;
|
||||
"net.ipv4.conf.all.rp_filter" = 1;
|
||||
"net.ipv4.conf.all.accept_redirects" = 0;
|
||||
"net.ipv6.conf.all.accept_redirects" = 0;
|
||||
"kernel.kptr_restrict" = 1;
|
||||
"kernel.dmesg_restrict" = 1;
|
||||
};
|
||||
```
|
||||
|
||||
## 12. Nix GC
|
||||
|
||||
```nix
|
||||
nix.gc = { automatic = true; dates = "weekly"; options = "--delete-older-than 30d"; };
|
||||
```
|
||||
|
||||
## 13. Mirrors (for China)
|
||||
|
||||
```nix
|
||||
nix.settings.substituters = ["https://mirrors.tuna.tsinghua.edu.cn/nix-channels/store"];
|
||||
```
|
||||
|
||||
## 14. Install nanobot itself
|
||||
|
||||
```bash
|
||||
# As claw user
|
||||
git clone https://github.com/HKUDS/nanobot.git ~/nanobot-src
|
||||
cd ~/nanobot-src
|
||||
uv sync
|
||||
uv run nanobot onboard # interactive setup wizard
|
||||
# Populate workspace: SOUL.md, USER.md, memory/MEMORY.md
|
||||
```
|
||||
|
||||
## 15. Apply
|
||||
|
||||
Use the safe-switch wrapper to rebuild with health checks:
|
||||
|
||||
```bash
|
||||
sudo /home/claw/.nanobot/workspace/scripts/safe-switch.sh
|
||||
```
|
||||
|
||||
This runs `nixos-rebuild switch`, waits, then verifies the gateway is reachable.
|
||||
If the health check fails, it automatically rolls back.
|
||||
|
||||
## Known quirks
|
||||
|
||||
- **sudo path**: Use `/run/wrappers/bin/sudo` inside scripts, not the default PATH's `/run/current-system/sw/bin/sudo` (lacks setuid).
|
||||
- **systemctl from cron/timers**: Need `XDG_RUNTIME_DIR=/run/user/1000 DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus`.
|
||||
- **Gateway self-restart**: Never `systemctl --user restart nanobot` from within nanobot's own process — it kills the parent. Use `nohup bash -c 'sleep 2 && ...' &`.
|
||||
- **Rollback**: `cd ~/nanobot-src && git checkout known-good && systemctl --user restart nanobot`.
|
||||
Reference in New Issue
Block a user