Research-Stack/cupfox-config.nix
Brandon Schneider ac4e23dc9b Expand devcontainer with full Python stack, add MCP servers (Notion/AWS), strengthen Lean theorems
- .devcontainer/Dockerfile: add PostgreSQL client libs, OpenSSL/libffi headers, gfortran/BLAS for scipy, rclone; install full Python dependency set (boto3, psycopg2-binary, fastapi, uvicorn, notion-client, httpx, pytest, numpy, scipy, etc.) in uv-managed venv; add rclone S3 gateway init script as ENTRYPOINT
- .devcontainer/devcontainer.json: switch from build to pre-built image (localhost/research
2026-05-19 01:52:14 -05:00

225 lines
5.6 KiB
Nix

{ config, pkgs, lib, ... }:
let
caddyWithPorkbun = pkgs.caddy.withPlugins {
plugins = [ "github.com/caddy-dns/porkbun@v0.3.1" ];
hash = "sha256-X11vSQRbBg25I1eSKF2O5QBRS7zGOtdGhLISiwrHclw=";
};
in
{
imports = [ ./hardware-configuration.nix ];
boot.loader.grub.enable = false;
boot.loader.generic-extlinux-compatible.enable = true;
networking.hostName = "cupfox";
networking.networkmanager.enable = true;
networking.nameservers = [ "1.1.1.1" "8.8.8.8" ];
networking.networkmanager.dns = "none";
networking.networkmanager.settings.main."rc-manager" = "unmanaged";
nix.settings = {
experimental-features = [ "nix-command" "flakes" ];
auto-optimise-store = true;
};
systemd.services.nix-daemon.serviceConfig.BindReadOnlyPaths = [ "/etc/resolv.conf" ];
time.timeZone = "America/Chicago";
users.users.root.openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICqbOp63zWXWcHcFXxuGw9h/WNDLWRVVFTXDd4ZtPaj3 allaun@QFox"
];
services.openssh = {
enable = true;
settings = {
PermitRootLogin = "prohibit-password";
PasswordAuthentication = false;
};
};
services.tailscale.enable = true;
systemd.services.caddy.serviceConfig.EnvironmentFile = [ "/etc/caddy/porkbun.env" ];
# Stateful storage initialization for Open WebUI
systemd.tmpfiles.rules = [
"d /var/lib/open-webui 0700 root root -"
];
services.caddy = {
enable = true;
logFormat = "level INFO";
package = caddyWithPorkbun;
extraConfig = ''
researchstack.info, cupfox.researchstack.info, git.researchstack.info, http://100.126.151.57 {
tls {
dns porkbun {
api_key {$PORKBUN_API_KEY}
api_secret_key {$PORKBUN_SECRET_KEY}
}
}
handle_path /api/credentials/* {
reverse_proxy http://100.69.1.43:8444
}
handle_path /git/* {
reverse_proxy http://127.0.0.1:3000
}
root * /var/www/researchstack
file_server
}
ollama.researchstack.info {
tls {
dns porkbun {
api_key {$PORKBUN_API_KEY}
api_secret_key {$PORKBUN_SECRET_KEY}
}
}
reverse_proxy http://100.101.198.87:11434
}
chat.researchstack.info {
tls {
dns porkbun {
api_key {$PORKBUN_API_KEY}
api_secret_key {$PORKBUN_SECRET_KEY}
}
}
reverse_proxy http://127.0.0.1:8080
}
cupfox.tail4e7094.ts.net {
tls internal
handle_path /ollama/* {
reverse_proxy http://100.101.198.87:11434
}
handle {
respond "cupfox orchestration node"
}
}
'';
};
virtualisation.podman = {
enable = true;
defaultNetwork.settings.dns_enabled = true;
};
virtualisation.containers.enable = true;
virtualisation.oci-containers = {
backend = "podman";
containers = {
research-stack = {
image = "localhost/research-stack:latest";
autoStart = true;
cmd = [ "sleep" "infinity" ];
extraOptions = [
"--dns" "100.101.247.127"
"--dns" "1.1.1.1"
"--dns" "8.8.8.8"
];
};
open-webui = {
image = "ghcr.io/open-webui/open-webui:main";
autoStart = true;
ports = [ "127.0.0.1:8080:8080" ];
environment = {
OLLAMA_BASE_URL = "http://100.101.198.87:11434";
WEBUI_AUTH = "true";
};
extraOptions = [
"--dns" "100.101.247.127"
"--dns" "1.1.1.1"
"--dns" "8.8.8.8"
];
volumes = [
"/var/lib/open-webui:/app/backend/data"
];
};
};
};
systemd.services.laptop-1-health = {
description = "Poll laptop-1 health via Ollama API";
after = [ "network-online.target" ];
wants = [ "network-online.target" ];
serviceConfig = {
Type = "oneshot";
ExecStart = "${pkgs.curl}/bin/curl -sf --max-time 5 http://100.101.198.87:11434/api/tags";
};
};
systemd.timers.laptop-1-health = {
description = "Poll laptop-1 health every 5 minutes";
wantedBy = [ "timers.target" ];
timerConfig = {
OnCalendar = "*:0/5";
Persistent = true;
RandomizedDelaySec = 30;
};
};
systemd.services.microvm-health = {
description = "Poll MicroVM-Racknerd health endpoint";
after = [ "network-online.target" ];
wants = [ "network-online.target" ];
serviceConfig = {
Type = "oneshot";
ExecStart = "${pkgs.curl}/bin/curl -sf --max-time 5 http://100.101.247.127:8443/index.sh";
};
};
systemd.timers.microvm-health = {
description = "Poll MicroVM health every 5 minutes";
wantedBy = [ "timers.target" ];
timerConfig = {
OnCalendar = "*:0/5";
Persistent = true;
RandomizedDelaySec = 30;
};
};
systemd.services.gather-metrics = {
description = "Gather system metrics across all nodes";
after = [ "network-online.target" ];
wants = [ "network-online.target" ];
path = with pkgs; [ curl jq procps openssh iputils gawk gnused ];
serviceConfig = {
Type = "oneshot";
ExecStart = "/usr/local/bin/gather-metrics.sh";
};
};
systemd.timers.gather-metrics = {
description = "Gather metrics every minute";
wantedBy = [ "timers.target" ];
timerConfig = {
OnCalendar = "*:0/1";
Persistent = true;
};
};
environment.systemPackages = with pkgs; [
curl
dig
dnsutils
git
htop
jq
podman-compose
podman-tui
rclone
ripgrep
vim
wget
];
system.stateVersion = "25.05";
}