mirror of
https://github.com/allaunthefox/Research-Stack.git
synced 2026-07-31 03:05:21 +00:00
feat(infra): add netcup VPS flake (ARM64, NixOS 25.11)
Provision: lean-lsp-mcp (8765/8766), pylsp (8767), ollama (11434) Services: systemd units for Lean 4.19.0, 4.30.0-rc2, Python LSP, Ollama Packages: elan, uv, texliveFull, octave, typst, docker, nix-ld Hardware: Ampere ARM64, 64GB RAM, 18 cores, 2TB disk Build: nix build .#packages.aarch64-linux.lean-lsp-mcp
This commit is contained in:
parent
5e12f21fa1
commit
cd385afcdc
3 changed files with 521 additions and 0 deletions
278
4-Infrastructure/netcup-vps/configuration.nix
Normal file
278
4-Infrastructure/netcup-vps/configuration.nix
Normal file
|
|
@ -0,0 +1,278 @@
|
|||
{ config, pkgs, lib, ... }:
|
||||
|
||||
{
|
||||
imports = [
|
||||
# Hardware configuration (if needed)
|
||||
];
|
||||
|
||||
# ── System identity ───────────────────────────────────────────────────────
|
||||
networking.hostName = "rs-vps";
|
||||
time.timeZone = "Europe/Berlin";
|
||||
|
||||
# ── Boot ──────────────────────────────────────────────────────────────────
|
||||
boot.loader.grub.enable = lib.mkDefault true;
|
||||
boot.loader.grub.device = "/dev/vda";
|
||||
boot.loader.grub.efiSupport = true;
|
||||
boot.loader.grub.efiInstallAsRemovable = true;
|
||||
|
||||
# ── Filesystems ────────────────────────────────────────────────────────────
|
||||
fileSystems = {
|
||||
"/" = {
|
||||
device = "/dev/vda1";
|
||||
fsType = "ext4";
|
||||
autoMount = true;
|
||||
};
|
||||
"/boot/efi" = {
|
||||
device = "/dev/vda2";
|
||||
fsType = "vfat";
|
||||
autoMount = true;
|
||||
};
|
||||
};
|
||||
|
||||
swapDevices = [
|
||||
{ device = "/dev/vda3"; size = 65536; }
|
||||
];
|
||||
|
||||
# ── Users ─────────────────────────────────────────────────────────────────
|
||||
users.users.researcher = {
|
||||
isNormalUser = true;
|
||||
description = "Research Stack developer";
|
||||
extraGroups = [
|
||||
"wheel"
|
||||
"docker"
|
||||
"keys"
|
||||
];
|
||||
openssh.authorizedKeys.keys = [
|
||||
# Add SSH keys here
|
||||
];
|
||||
};
|
||||
|
||||
# ── OpenSSH ────────────────────────────────────────────────────────────────
|
||||
services.openssh = {
|
||||
enable = true;
|
||||
settings = {
|
||||
PermitRootLogin = "yes";
|
||||
PasswordAuthentication = false;
|
||||
};
|
||||
# listenAddresses = [{ port = 22; }];
|
||||
};
|
||||
|
||||
# ── nix-ld (run x86_64 binaries on ARM64) ────────────────────────────────
|
||||
programs.nix-ld.enable = true;
|
||||
|
||||
# ── uv is installed via environment.systemPackages ──────────────────────
|
||||
|
||||
# ── Lean LSP services ──────────────────────────────────────────────────────
|
||||
# Lean 4.19.0 LSP on port 8765 (streamable-http)
|
||||
systemd.services.lean-lsp-mcp = {
|
||||
description = "Lean LSP MCP server (v4.19.0)";
|
||||
after = [ "network.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
script = let
|
||||
lean-lsp = pkgs.writeShellScriptBin "lean-lsp-run" ''
|
||||
#!${pkgs.bash}/bin/bash
|
||||
set -euo pipefail
|
||||
export ELAN_TOOLCHAIN=4.19.0
|
||||
export SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt
|
||||
export PATH="${pkgs.uv}/bin:$HOME/.elan/bin:$PATH"
|
||||
exec uv tool run --from lean-lsp-mcp lean-lsp-mcp --port 8765 --stdio
|
||||
'';
|
||||
in ''
|
||||
exec ${lean-lsp}/bin/lean-lsp-run
|
||||
'';
|
||||
|
||||
serviceConfig = {
|
||||
Type = "simple";
|
||||
Restart = "always";
|
||||
RestartSec = "5s";
|
||||
User = "researcher";
|
||||
Group = "researcher";
|
||||
WorkingDirectory = "/home/researcher";
|
||||
Environment = [
|
||||
"ELAN_TOOLCHAIN=4.19.0"
|
||||
"HOME=/home/researcher"
|
||||
"SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
# Lean 4.30.0-rc2 LSP on port 8766 (for mathlib)
|
||||
systemd.services.lean-lsp-mathlib = {
|
||||
description = "Lean LSP MCP server (v4.30.0-rc2, mathlib)";
|
||||
after = [ "network.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
script = let
|
||||
lean-lsp-mathlib = pkgs.writeShellScriptBin "lean-lsp-mathlib-run" ''
|
||||
#!${pkgs.bash}/bin/bash
|
||||
set -euo pipefail
|
||||
export ELAN_TOOLCHAIN=4.30.0-rc2
|
||||
export SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt
|
||||
export PATH="${pkgs.uv}/bin:$HOME/.elan/bin:$PATH"
|
||||
exec uv tool run --from lean-lsp-mcp lean-lsp-mcp --port 8766 --stdio
|
||||
'';
|
||||
in ''
|
||||
exec ${lean-lsp-mathlib}/bin/lean-lsp-mathlib-run
|
||||
'';
|
||||
|
||||
serviceConfig = {
|
||||
Type = "simple";
|
||||
Restart = "always";
|
||||
RestartSec = "5s";
|
||||
User = "researcher";
|
||||
Group = "researcher";
|
||||
WorkingDirectory = "/home/researcher";
|
||||
Environment = [
|
||||
"ELAN_TOOLCHAIN=4.30.0-rc2"
|
||||
"HOME=/home/researcher"
|
||||
"SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
# ── Python LSP TCP on port 8767 ──────────────────────────────────────────
|
||||
systemd.services.pylsp = {
|
||||
description = "Python LSP server (TCP)";
|
||||
after = [ "network.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
script = let
|
||||
pythonEnv = pkgs.python311.withPackages (ps: with ps; [
|
||||
numpy scipy sympy pandas matplotlib seaborn
|
||||
uncertainties pint
|
||||
beautifulsoup4 lxml
|
||||
requests httpx
|
||||
fastapi uvicorn pydantic
|
||||
python-dateutil
|
||||
]);
|
||||
pylsp-script = pkgs.writeShellScriptBin "pylsp-run" ''
|
||||
#!${pkgs.bash}/bin/bash
|
||||
set -euo pipefail
|
||||
exec ${pythonEnv}/bin/python -m pylsp --host 0.0.0.0 --port 8767
|
||||
'';
|
||||
in ''
|
||||
exec ${pylsp-script}/bin/pylsp-run
|
||||
'';
|
||||
|
||||
serviceConfig = {
|
||||
Type = "simple";
|
||||
Restart = "always";
|
||||
RestartSec = "5s";
|
||||
User = "researcher";
|
||||
Group = "researcher";
|
||||
WorkingDirectory = "/home/researcher";
|
||||
Environment = [
|
||||
"HOME=/home/researcher"
|
||||
"SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
# ── Ollama inference server on port 11434 ─────────────────────────────────
|
||||
systemd.services.ollama = {
|
||||
description = "Ollama LLM inference server";
|
||||
after = [ "network.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
script = ''
|
||||
#!${pkgs.bash}/bin/bash
|
||||
set -euo pipefail
|
||||
export OLLAMA_HOST=0.0.0.0:11434
|
||||
export OLLAMA_MODELS=/home/researcher/.ollama/models
|
||||
mkdir -p $OLLAMA_MODELS
|
||||
exec ${pkgs.ollama}/bin/ollama serve
|
||||
'';
|
||||
|
||||
serviceConfig = {
|
||||
Type = "simple";
|
||||
Restart = "always";
|
||||
RestartSec = "5s";
|
||||
User = "researcher";
|
||||
Group = "researcher";
|
||||
WorkingDirectory = "/home/researcher";
|
||||
Environment = [
|
||||
"HOME=/home/researcher"
|
||||
"PATH=${pkgs.ollama}/bin:${pkgs.curl}/bin"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
# ── Ollama model puller helper ─────────────────────────────────────────────
|
||||
# Run with: sudo -u researcher /var/lib/ollama/model-pull.sh deepseek-r1:7b
|
||||
systemd.services.ollama-model-pull = {
|
||||
description = "Ollama model puller";
|
||||
after = [ "ollama.service" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
script = ''
|
||||
#!${pkgs.bash}/bin/bash
|
||||
MODEL="''${1:-deepseek-r1:7b}"
|
||||
exec ${pkgs.ollama}/bin/ollama pull "$MODEL"
|
||||
'';
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
User = "researcher";
|
||||
RemainAfterExit = true;
|
||||
};
|
||||
};
|
||||
|
||||
# ── Docker (for x86_64 images via nix-ld) ────────────────────────────────
|
||||
virtualisation.docker = {
|
||||
enable = true;
|
||||
autoPrune.enable = true;
|
||||
enableOnBoot = true;
|
||||
# Store images on a larger disk if available
|
||||
# dataRoot = "/var/lib/docker";
|
||||
};
|
||||
|
||||
# ── Networking ─────────────────────────────────────────────────────────────
|
||||
networking.firewall = {
|
||||
enable = true;
|
||||
allowedTCPPorts = [
|
||||
22 # SSH
|
||||
80 # HTTP
|
||||
443 # HTTPS
|
||||
8765 # Lean LSP (v4.19.0)
|
||||
8766 # Lean LSP (v4.30.0-rc2)
|
||||
8767 # Python LSP
|
||||
11434 # Ollama
|
||||
];
|
||||
allowedUDPPorts = [ ];
|
||||
};
|
||||
|
||||
# ── Packages ────────────────────────────────────────────────────────────────
|
||||
environment.systemPackages = with pkgs; [
|
||||
# Core utilities
|
||||
git git-lfs
|
||||
bash bashInteractive coreutils findutils gnugrep gnused gawk
|
||||
util-linux
|
||||
curl wget rsync zstd xz gnutar gzip
|
||||
ripgrep jq
|
||||
gnumake
|
||||
nodejs_22
|
||||
uv
|
||||
elan
|
||||
texliveFull
|
||||
gnuplot maxima octave
|
||||
typst
|
||||
openssh cacert
|
||||
less which file procps htop
|
||||
glibc binutils
|
||||
openssl pkg-config
|
||||
graphviz
|
||||
postgresql_16
|
||||
docker containerd
|
||||
];
|
||||
|
||||
# ── Performance tuning for 64GB RAM / 18 cores ─────────────────────────────
|
||||
# Aggressive transparent hugepage for memory-heavy workloads
|
||||
boot.kernel.sysctl = {
|
||||
"vm.nr_hugepages" = 1024;
|
||||
};
|
||||
|
||||
# ── Security ────────────────────────────────────────────────────────────────
|
||||
security.sudo.wheelNeedsPassword = false;
|
||||
|
||||
# ── System state ────────────────────────────────────────────────────────────
|
||||
system.stateVersion = "25.11";
|
||||
}
|
||||
44
4-Infrastructure/netcup-vps/flake.lock
generated
Normal file
44
4-Infrastructure/netcup-vps/flake.lock
generated
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
{
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1779796641,
|
||||
"narHash": "sha256-ZsIrKmhp4vbBXoXXmR/tBXA/UCsAQiJL9vsgZEduhVY=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "25f538306313eae3927264466c70d7001dcea1df",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-25.11",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-stable": {
|
||||
"locked": {
|
||||
"lastModified": 1751274312,
|
||||
"narHash": "sha256-/bVBlRpECLVzjV19t5KMdMFWSwKLtb5RyXdjz3LJT+g=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "50ab793786d9de88ee30ec4e4c24fb4236fc2674",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-24.11",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs",
|
||||
"nixpkgs-stable": "nixpkgs-stable"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
199
4-Infrastructure/netcup-vps/flake.nix
Normal file
199
4-Infrastructure/netcup-vps/flake.nix
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
{
|
||||
description = "Research Stack — netcup VPS (Ampere ARM64, 64GB RAM)";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11";
|
||||
nixpkgs-stable.url = "github:NixOS/nixpkgs/nixos-24.11";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, nixpkgs-stable }:
|
||||
let
|
||||
system = "aarch64-linux";
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
config.allowUnfree = false;
|
||||
};
|
||||
|
||||
# ── Lean 4 toolchains via elan ─────────────────────────────────────────
|
||||
# elan-lsp overlays lean4 onto PATH for a given toolchain.
|
||||
# Multiple toolchains can coexist; default is set via ELAN_TOOLCHAIN.
|
||||
elan-lsp = { toolchain ? "4.19.0", port ? 8765 }:
|
||||
let
|
||||
elan-init = pkgs.runCommand "elan-init-${toolchain}" {
|
||||
nativeBuildInputs = [ pkgs.curl ];
|
||||
SSL_CERT_FILE = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
|
||||
} ''
|
||||
mkdir -p $out/etc/profile.d
|
||||
cat > $out/etc/profile.d/elan-${toolchain}.sh << 'PROFILE'
|
||||
export ELAN_TOOLCHAIN=${toolchain}
|
||||
export PATH="$HOME/.elan/toolchains/lean4-${toolchain}/bin:$PATH"
|
||||
PROFILE
|
||||
'';
|
||||
in pkgs.writeShellScriptBin "lean-lsp-mcp" ''
|
||||
#! ${pkgs.bash}/bin/bash
|
||||
set -euo pipefail
|
||||
export ELAN_TOOLCHAIN=${toolchain}
|
||||
export PATH="$HOME/.elan/toolchains/lean4-${toolchain}/bin:$PATH"
|
||||
export SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt
|
||||
exec uvx lean-lsp-mcp --port=${toString port} --stdio
|
||||
'';
|
||||
|
||||
# ── Python LSP server ─────────────────────────────────────────────────
|
||||
pylsp-tcp = { port ? 8767, extras ? [ "all" ] }:
|
||||
let
|
||||
pythonEnv = pkgs.python311.withPackages (ps: with ps; [
|
||||
numpy scipy sympy pandas matplotlib seaborn
|
||||
uncertainties pint
|
||||
beautifulsoup4 lxml
|
||||
requests httpx
|
||||
fastapi uvicorn pydantic
|
||||
python-dateutil
|
||||
]);
|
||||
in pkgs.writeShellScriptBin "pylsp-tcp" ''
|
||||
#! ${pkgs.bash}/bin/bash
|
||||
set -euo pipefail
|
||||
exec ${pythonEnv}/bin/python -m pylsp --host 0.0.0.0 --port ${toString port}
|
||||
'';
|
||||
|
||||
# ── Ollama for inference ─────────────────────────────────────────────
|
||||
ollama-service = pkgs.writeShellScriptBin "ollama-service" ''
|
||||
#! ${pkgs.bash}/bin/bash
|
||||
set -euo pipefail
|
||||
export OLLAMA_HOST=0.0.0.0:11434
|
||||
exec ${pkgs.ollama}/bin/ollama serve
|
||||
'';
|
||||
|
||||
# ── Core packages ─────────────────────────────────────────────────────
|
||||
corePackages = with pkgs; [
|
||||
# Version control
|
||||
git git-lfs
|
||||
# Shells & core utils
|
||||
bash bashInteractive coreutils findutils gnugrep gnused gawk
|
||||
util-linux
|
||||
# File transfer & compression
|
||||
curl wget rsync zstd xz gnutar gzip
|
||||
# Search & text processing
|
||||
ripgrep jq
|
||||
# Build essentials
|
||||
gnumake
|
||||
# Node (for any JS tooling)
|
||||
nodejs_22
|
||||
# Python: uv for runtime package management
|
||||
uv
|
||||
# Elan for Lean 4 toolchains
|
||||
elan
|
||||
# LaTeX
|
||||
texliveFull
|
||||
# Math CLI tools
|
||||
gnuplot maxima wxmaxima octave
|
||||
# CAS
|
||||
# sage # too heavy for server; use lean + sympy
|
||||
# Typesetting
|
||||
typst
|
||||
# Network / TLS
|
||||
openssh cacert
|
||||
# Shell helpers
|
||||
less which file procps htop
|
||||
# glibc / binutils
|
||||
glibc binutils
|
||||
# SSL / crypto
|
||||
openssl pkg-config
|
||||
# Graphviz
|
||||
graphviz
|
||||
# PostgreSQL client
|
||||
postgresql_16
|
||||
# Docker (for running pre-built x86_64 images via nix-ld)
|
||||
docker
|
||||
# Containerd for docker
|
||||
containerd
|
||||
# nix-ld for running x86_64 binaries on ARM64
|
||||
# (built from nixpkgs-stable to ensure binary cache availability)
|
||||
(import nixpkgs-stable {
|
||||
system = "x86_64-linux";
|
||||
config.allowUnfree = false;
|
||||
}).nix-ld
|
||||
];
|
||||
|
||||
# ── Python packages (full science stack) ──────────────────────────────
|
||||
pythonPackages = with pkgs.python311Packages; [
|
||||
numpy scipy sympy pandas matplotlib seaborn
|
||||
uncertainties pint
|
||||
beautifulsoup4 lxml
|
||||
requests httpx
|
||||
fastapi uvicorn pydantic
|
||||
python-dotenv pyyaml rich
|
||||
python-dateutil urllib3
|
||||
boto3 botocore
|
||||
psycopg2
|
||||
biopython networkx
|
||||
pycryptodome
|
||||
zstandard
|
||||
z3
|
||||
pywavelets
|
||||
polars
|
||||
scikit-learn
|
||||
notion-client
|
||||
pytest
|
||||
];
|
||||
|
||||
# ── Custom etc for researcher user ───────────────────────────────────
|
||||
customEtc = pkgs.runCommand "custom-etc" {} ''
|
||||
mkdir -p $out/etc
|
||||
echo 'root:x:0:0:root user:/var/empty:/bin/sh' > $out/etc/passwd
|
||||
echo 'nobody:x:65534:65534:nobody:/var/empty:/bin/sh' >> $out/etc/passwd
|
||||
echo 'researcher:x:1000:1000:Research Stack developer:/home/researcher:/bin/bash' >> $out/etc/passwd
|
||||
echo 'root:x:0:' > $out/etc/group
|
||||
echo 'nobody:x:65534:' >> $out/etc/group
|
||||
echo 'researcher:x:1000:' >> $out/etc/group
|
||||
echo 'passwd: files' > $out/etc/nsswitch.conf
|
||||
echo 'group: files' >> $out/etc/nsswitch.conf
|
||||
echo 'hosts: files dns' >> $out/etc/nsswitch.conf
|
||||
'';
|
||||
|
||||
researcherSetup = pkgs.runCommand "researcher-home" {} ''
|
||||
mkdir -p $out/home/researcher/stack
|
||||
mkdir -p $out/home/researcher/.elan/toolchains
|
||||
mkdir -p $out/home/researcher/.cache
|
||||
mkdir -p -m 1777 $out/tmp
|
||||
chmod 755 $out/home/researcher
|
||||
chmod 700 $out/home/researcher/.elan
|
||||
'';
|
||||
|
||||
in rec {
|
||||
packages.${system} = {
|
||||
inherit corePackages pythonPackages;
|
||||
|
||||
# ── Lean LSP service (port 8765) ──────────────────────────────────
|
||||
lean-lsp-mcp = elan-lsp { toolchain = "4.19.0"; port = 8765; };
|
||||
|
||||
# ── Lean LSP with mathlib toolchain (port 8766) ───────────────────
|
||||
lean-lsp-mathlib = elan-lsp { toolchain = "4.30.0-rc2"; port = 8766; };
|
||||
|
||||
# ── Python LSP TCP (port 8767) ───────────────────────────────────
|
||||
pylsp = pylsp-tcp { port = 8767; };
|
||||
|
||||
# ── Ollama inference server ───────────────────────────────────────
|
||||
ollama = ollama-service;
|
||||
};
|
||||
|
||||
# ── NixOS configuration for the VPS ──────────────────────────────────
|
||||
nixosConfigurations.netcup-vps = nixpkgs.lib.nixosSystem {
|
||||
inherit system;
|
||||
modules = [
|
||||
./configuration.nix
|
||||
];
|
||||
};
|
||||
|
||||
# Convenience: nix build .#packages.aarch64-linux.lean-lsp-mcp
|
||||
defaultPackage.${system} = packages.${system}.lean-lsp-mcp;
|
||||
|
||||
# ── Dev shell ────────────────────────────────────────────────────────
|
||||
devShells.${system}.default = pkgs.mkShell {
|
||||
packages = corePackages ++ pythonPackages;
|
||||
shellHook = ''
|
||||
echo "Research Stack — netcup VPS dev shell (ARM64, NixOS 25.11)"
|
||||
export PS1='\[\033[1;34m\][rs-vps]\[\033[0m\] \w \$ '
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue