diff options
Diffstat (limited to 'snippets/hyperstack')
| -rwxr-xr-x | snippets/hyperstack/install.sh | 142 | ||||
| -rw-r--r-- | snippets/hyperstack/opencode-setup.md | 256 | ||||
| -rwxr-xr-x | snippets/hyperstack/wg1-setup.sh | 288 |
3 files changed, 686 insertions, 0 deletions
diff --git a/snippets/hyperstack/install.sh b/snippets/hyperstack/install.sh new file mode 100755 index 0000000..3995a62 --- /dev/null +++ b/snippets/hyperstack/install.sh @@ -0,0 +1,142 @@ +#!/bin/bash +set -e + +# OpenCode + Codex + Ollama Installation Script +# Usage: ./install.sh [user@host] [opencode_version] +# Example: ./install.sh ubuntu@38.128.233.181 v1.1.32 + +HOST="${1:-ubuntu@38.128.233.181}" +OPENCODE_VERSION="${2:-v1.1.32}" +CODEX_VERSION="${3:-latest}" + +echo "Installing OpenCode, Codex, and Ollama on $HOST" +echo "OpenCode version: $OPENCODE_VERSION" +echo "Codex version: $CODEX_VERSION" + +# Function to run remote commands +run_remote() { + ssh "$HOST" "$1" +} + +# 1. Install Ollama +echo "Step 1: Installing Ollama..." +run_remote "curl -fsSL https://ollama.ai/install.sh | sh" || echo "Ollama may already be installed" + +# 2. Start Ollama service +echo "Step 2: Starting Ollama service..." +run_remote "sudo systemctl start ollama && sudo systemctl status ollama" || echo "Starting Ollama..." + +# 2.5. Configure Ollama to use /ephemeral for models (if available) +echo "Step 2.5: Configuring Ollama models directory..." +run_remote "if [ -d /ephemeral ]; then + sudo mkdir -p /ephemeral/ollama/models + sudo chown ollama:ollama /ephemeral/ollama /ephemeral/ollama/models + sudo mkdir -p /etc/systemd/system/ollama.service.d + sudo tee /etc/systemd/system/ollama.service.d/override.conf > /dev/null << 'EOF' +[Service] +Environment=\"OLLAMA_MODELS=/ephemeral/ollama/models\" +Environment=\"OLLAMA_GPU_OVERHEAD=2000\" +Environment=\"OLLAMA_NUM_PARALLEL=4\" +EOF + sudo systemctl daemon-reload + sudo systemctl restart ollama + sleep 3 + echo 'Ollama configured to use /ephemeral' +else + echo 'No /ephemeral directory found, using default' +fi" + +# 3. Kill unattended upgrade lock if it exists +echo "Step 3: Clearing package manager lock..." +run_remote "sudo pkill -f unattended-upgrade || true" +sleep 2 + +# 4. Install Node.js 20 (required for Codex), npm, and Python +echo "Step 4: Installing Node.js 20, npm, and Python..." +run_remote "curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - && sudo apt install -y nodejs python3 python3-pip" + +# 5. Download and install OpenCode CLI +echo "Step 5: Installing OpenCode CLI ($OPENCODE_VERSION)..." +run_remote "cd /tmp && wget -q https://github.com/anomalyco/opencode/releases/download/$OPENCODE_VERSION/opencode-linux-x64.tar.gz && tar -xzf opencode-linux-x64.tar.gz && sudo mv opencode /usr/local/bin/ && opencode --version" + +# 6. Create OpenCode config directory +echo "Step 6: Creating OpenCode config directory..." +run_remote "mkdir -p ~/.config/opencode" + +# 7. Create OpenCode configuration (qwen3-coder models) +echo "Step 7: Creating OpenCode configuration..." +run_remote "cat > ~/.config/opencode/opencode.json << 'EOF' +{ + \"provider\": { + \"ollama\": { + \"npm\": \"@ai-sdk/openai-compatible\", + \"name\": \"Ollama\", + \"api\": \"http://localhost:11434/v1\", + \"models\": { + \"qwen3-coder:latest\": { + \"name\": \"Qwen3 Coder Latest (Higher Quality)\" + }, + \"qwen3-coder:30b-a3b-q4_K_M\": { + \"name\": \"Qwen3 Coder 30B A3B Q4_K_M (Quantized)\" + } + } + } + } +} +EOF" + +# 8. Pull qwen3-coder models +echo "Step 8: Pulling qwen3-coder models (this may take a while)..." +run_remote "ollama pull qwen3-coder:latest" +run_remote "ollama pull qwen3-coder:30b-a3b-q4_K_M" + +# 9. Install Codex CLI +echo "Step 9: Installing Codex CLI..." +run_remote "sudo npm install -g @openai/codex || npm install -g @openai/codex" + +# 10. Create Codex config to use Ollama +echo "Step 10: Configuring Codex to use Ollama..." +run_remote "mkdir -p ~/.codex && cat > ~/.codex/config.json << 'EOF' +{ + \"provider\": \"ollama\", + \"model\": \"qwen3-coder:30b-a3b-q4_K_M\", + \"endpoint\": \"http://localhost:11434/v1\" +} +EOF" + +# 11. Install Aider (LLM-powered code editing) +echo "Step 11: Installing Aider..." +run_remote "pip3 install --user aider-chat && echo 'export PATH=~/.local/bin:\$PATH' >> ~/.bashrc" + +# 12. Configure Aider to use Ollama +echo "Step 12: Configuring Aider for Ollama..." +run_remote "mkdir -p ~/.aider && cat > ~/.aider/.aider.conf.yml << 'EOF' +model: ollama/qwen2.5-coder:14b-instruct +openai-api-base: http://localhost:11434/v1 +EOF" + +# 13. Verify installation +echo "Step 13: Verifying installation..." +run_remote "opencode --version && ollama list && codex --version && ~/.local/bin/aider --version" + +echo "" +echo "✓ Installation complete!" +echo "" +echo "To use OpenCode:" +echo " ssh $HOST" +echo " cd ~/your/project" +echo " opencode" +echo "" +echo "To use Codex:" +echo " ssh $HOST" +echo " codex --oss --local-provider ollama" +echo "" +echo "To use Aider (LLM-powered code editing):" +echo " ssh $HOST" +echo " cd ~/your/project" +echo " aider" +echo " aider <filename>" +echo "" +echo "Available models for all tools:" +echo " - qwen2.5-coder:14b-instruct (fast, ~9GB) - default" +echo " - qwen3-coder:30b-a3b-q4_K_M (slower, ~18GB)" diff --git a/snippets/hyperstack/opencode-setup.md b/snippets/hyperstack/opencode-setup.md new file mode 100644 index 0000000..64942ca --- /dev/null +++ b/snippets/hyperstack/opencode-setup.md @@ -0,0 +1,256 @@ +# OpenCode Setup on Hyperstack with Ollama + +This document outlines the steps to install and configure OpenCode to work with local Ollama models on a remote A100-80GB server. + +## Prerequisites + +- SSH access to the remote server (e.g., `ubuntu@IPHERE`) +- Ollama installed on the remote server + +## Installation Steps + +### 0. Install Ollama + +Install Ollama on the remote server: + +```bash +ssh ubuntu@IPHERE "curl -fsSL https://ollama.ai/install.sh | sh" +``` + +Start Ollama service: + +```bash +ssh ubuntu@IPHERE "sudo systemctl start ollama && sudo systemctl status ollama" +``` + +### 1. Kill Unattended Upgrade Lock + +If the package manager is locked by unattended-upgrades: + +```bash +ssh ubuntu@IPHERE "sudo kill -9 3523 && sleep 2" +``` + +### 2. Verify Node.js is Installed + +```bash +ssh ubuntu@IPHERE "npm --version && node --version" +``` + +If not installed, install Node.js: + +```bash +ssh ubuntu@IPHERE "sudo apt install -y nodejs npm" +``` + +### 3. Download and Install OpenCode CLI + +Get the latest release from GitHub releases and install to `/usr/local/bin`: + +```bash +ssh ubuntu@IPHERE "cd /tmp && wget -q https://github.com/anomalyco/opencode/releases/download/v1.1.32/opencode-linux-x64.tar.gz && tar -xzf opencode-linux-x64.tar.gz && sudo mv opencode /usr/local/bin/ && opencode --version" +``` + +This installs OpenCode v1.1.32. Check [GitHub releases](https://github.com/anomalyco/opencode/releases) for the latest version. + +### 4. Create OpenCode Configuration Directory + +```bash +ssh ubuntu@IPHERE "mkdir -p ~/.config/opencode" +``` + +### 5. Configure OpenCode to Use Ollama + +Create `~/.config/opencode/opencode.json` with Ollama as the provider: + +```bash +ssh ubuntu@IPHERE "cat > ~/.config/opencode/opencode.json << 'EOF' +{ + \"provider\": { + \"ollama\": { + \"npm\": \"@ai-sdk/openai-compatible\", + \"name\": \"Ollama\", + \"api\": \"http://localhost:11434/v1\", + \"models\": { + \"qwen3-coder:30b-a3b-q4_K_M\": { + \"name\": \"Qwen3 Coder 30B A3B Q4_K_M\" + }, + \"qwen2.5-coder:32b\": { + \"name\": \"Qwen2.5 Coder 32B\" + }, + \"mistral-large\": { + \"name\": \"Mistral Large 123B\" + }, + \"deepseek-coder\": { + \"name\": \"Deepseek Coder\" + } + } + } + } +} +EOF" +``` + +**Key configuration fields:** +- `npm`: AI SDK package for OpenAI-compatible APIs +- `api`: Ollama endpoint (defaults to localhost:11434) +- `models`: Map of model IDs to display names + +### 6. Clean Up Disk Space (if needed) + +Check disk usage: + +```bash +ssh ubuntu@IPHERE "df -h / && ollama list" +``` + +For A100-80GB, ensure sufficient space (~120GB free). Remove unused models if needed: + +```bash +ssh ubuntu@IPHERE "ollama rm model_name" +``` + +### 7. Pull Models into Ollama + +Pull Qwen3 Coder 30B (~20GB): + +```bash +ssh ubuntu@IPHERE "ollama pull qwen3-coder:30b-a3b-q4_K_M" +``` + +Pull Qwen2.5 Coder 32B (~19GB): + +```bash +ssh ubuntu@IPHERE "ollama pull qwen2.5-coder:32b" +``` + +Pull Mistral Large (~73GB): + +```bash +ssh ubuntu@IPHERE "ollama pull mistral-large" +``` + +Pull Deepseek Coder (776MB - lightweight option): + +```bash +ssh ubuntu@IPHERE "ollama pull deepseek-coder" +``` + +Verify models are available: + +```bash +ssh ubuntu@IPHERE "ollama list" +``` + +## Using OpenCode + +Navigate to your project and start OpenCode: + +```bash +ssh ubuntu@IPHERE +cd ~/git/aitest +opencode +``` + +Then: +1. Press Tab to enter Plan mode (recommended for new features) +2. Use `/models` command to select which Ollama model to use +3. Ask OpenCode to help with your code + +## Configuration Details + +### Provider Configuration Schema + +The `provider` object in `opencode.json` uses this structure: + +```json +{ + "provider": { + "provider_id": { + "npm": "@ai-sdk/openai-compatible", + "name": "Display Name", + "api": "http://localhost:11434/v1", + "models": { + "model_id": { + "name": "Model Display Name" + } + } + } + } +} +``` + +### Available Models + +#### Qwen3 Coder 30B A3B Q4_K_M +- **Size**: ~20GB (optimized quantization) +- **Strengths**: Advanced coding capabilities, good tool calling, specialized for programming +- **Tool Support**: Function calling support +- **Use Case**: Primary coding assistant for complex tasks + +#### Qwen2.5 Coder 32B +- **Size**: ~19GB +- **Strengths**: Optimized for function calling and coding, better than earlier versions +- **Tool Support**: Strong function calling support +- **Use Case**: Reliable coding assistant for general-purpose tasks + +#### Mistral Large 123B +- **Size**: 73GB +- **Strengths**: Excellent tool/function calling support, strong reasoning, balanced for coding +- **Tool Support**: Native function calling +- **Use Case**: Most capable model for complex reasoning and coding tasks + +#### Deepseek Coder +- **Size**: 776MB (very lightweight) +- **Strengths**: Specialized for coding tasks, fast inference +- **Tool Support**: Function calling support +- **Use Case**: Fast responses for code generation and analysis on limited resources + +### Ollama Endpoint + +OpenCode communicates with Ollama via the OpenAI-compatible API: +- Default: `http://localhost:11434/v1` +- Ollama models endpoint: `http://localhost:11434/api/tags` + +## Troubleshooting + +### Configuration Error: "Unrecognized key" + +Ensure the config uses correct structure: +- Top-level key should be `provider` (not `providers`) +- Provider ID (e.g., `ollama`) is a key under `provider` object +- Each provider has `npm`, `name`, `api`, and `models` fields + +### Out of Disk Space + +Check available space: +```bash +df -h / +``` + +Remove models: +```bash +ollama rm model_name +``` + +For A100-80GB, budget ~120GB for models + system (account for OS and dependencies). + +### Ollama Connection Issues + +Verify Ollama is running and accessible: + +```bash +curl -s http://localhost:11434/api/tags | jq '.models[].name' +``` + +If using remote SSH, ensure: +- Ollama is listening on 0.0.0.0 (not just localhost) +- Port 11434 is not firewalled +- Use SSH port forwarding: `ssh -L 11434:localhost:11434 ubuntu@server` + +## References + +- [OpenCode Documentation](https://opencode.ai/docs) +- [OpenCode Providers Configuration](https://opencode.ai/docs/providers) +- [OpenCode GitHub](https://github.com/anomalyco/opencode) +- [Ollama Documentation](https://ollama.ai) diff --git a/snippets/hyperstack/wg1-setup.sh b/snippets/hyperstack/wg1-setup.sh new file mode 100755 index 0000000..a0a898c --- /dev/null +++ b/snippets/hyperstack/wg1-setup.sh @@ -0,0 +1,288 @@ +#!/bin/bash +# +# wg1-setup.sh - Set up WireGuard wg1 tunnel between earth and hyperstack VM +# +# USAGE: +# ./wg1-setup.sh <VM_PUBLIC_IP> +# Example: ./wg1-setup.sh 185.216.20.163 +# +# NETWORK DESIGN: +# Subnet: 192.168.3.0/24 (separate from wg0's 192.168.2.0/24) +# Port: 56710/udp +# +# +----------------+ +------------------+ +# | earth (client) | | hyperstack (VM) | +# | 192.168.3.2 |<--- WireGuard ---> | 192.168.3.1 | +# +----------------+ tunnel +------------------+ +# | Ollama :11434 | +# +------------------+ +# +# WHAT THIS SCRIPT DOES: +# On hyperstack VM (via SSH): +# - Installs WireGuard if not present +# - Creates /etc/wireguard/wg1.conf +# - Opens UFW ports: 56710/udp (WireGuard), 11434/tcp from 192.168.3.0/24 (Ollama) +# - Configures Ollama to listen on 0.0.0.0:11434 +# - Starts wg-quick@wg1 +# +# On earth (locally): +# - Installs WireGuard if not present (dnf) +# - Creates /etc/wireguard/wg1.conf +# - Starts wg-quick@wg1 +# +# PREREQUISITES: +# - SSH access to ubuntu@<VM_IP> with key-based auth +# - UDP port 56710 open in cloud provider's firewall/security group +# +# RE-RUNNING: +# When the VM IP changes, simply re-run this script with the new IP. +# It will regenerate keys and update configs on both sides. +# +# USING OLLAMA REMOTELY: +# export OLLAMA_HOST=http://192.168.3.1:11434 +# ollama run qwen2.5-coder:14b-instruct +# # Or with aider: +# aider --model ollama/qwen2.5-coder:14b-instruct +# + +set -euo pipefail + +# Configuration constants +WG_INTERFACE="wg1" +WG_PORT="56710" +SERVER_WG_IP="192.168.3.1" +CLIENT_WG_IP="192.168.3.2" +SUBNET_MASK="24" +SSH_USER="ubuntu" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +print_warning() { + echo -e "${YELLOW}$1${NC}" +} + +print_success() { + echo -e "${GREEN}$1${NC}" +} + +print_error() { + echo -e "${RED}$1${NC}" +} + +# Validate arguments +if [[ $# -ne 1 ]]; then + echo "Usage: $0 <VM_PUBLIC_IP>" + echo "Example: $0 185.216.20.163" + exit 1 +fi + +VM_IP="$1" + +# Validate IP format (basic check) +if ! [[ "$VM_IP" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + print_error "Error: Invalid IP address format: $VM_IP" + exit 1 +fi + +echo "==============================================" +print_warning "IMPORTANT: Ensure UDP port ${WG_PORT} is open on the VM!" +print_warning "This must be configured in your cloud provider's" +print_warning "firewall/security group settings." +echo "==============================================" +echo "" +read -p "Press Enter to continue (or Ctrl+C to abort)..." +echo "" + +# Create temporary directory for key generation +TMPDIR=$(mktemp -d) +trap "rm -rf $TMPDIR" EXIT + +echo "=== Generating WireGuard keys locally ===" + +# Generate server (hyperstack) keys +wg genkey > "$TMPDIR/server-privatekey" +wg pubkey < "$TMPDIR/server-privatekey" > "$TMPDIR/server-publickey" +SERVER_PRIVATE_KEY=$(cat "$TMPDIR/server-privatekey") +SERVER_PUBLIC_KEY=$(cat "$TMPDIR/server-publickey") + +# Generate client (earth) keys +wg genkey > "$TMPDIR/client-privatekey" +wg pubkey < "$TMPDIR/client-privatekey" > "$TMPDIR/client-publickey" +CLIENT_PRIVATE_KEY=$(cat "$TMPDIR/client-privatekey") +CLIENT_PUBLIC_KEY=$(cat "$TMPDIR/client-publickey") + +print_success "Keys generated successfully" + +echo "" +echo "=== Creating server (hyperstack) configuration ===" + +# Create server wg1.conf +cat > "$TMPDIR/server-wg1.conf" << EOF +# WireGuard wg1 configuration for hyperstack VM +# Server side of earth <-> hyperstack tunnel +# Generated by wg1-setup.sh on $(date) + +[Interface] +Address = ${SERVER_WG_IP}/${SUBNET_MASK} +ListenPort = ${WG_PORT} +PrivateKey = ${SERVER_PRIVATE_KEY} + +[Peer] +# earth (client) +PublicKey = ${CLIENT_PUBLIC_KEY} +AllowedIPs = ${CLIENT_WG_IP}/32 +EOF + +print_success "Server config created" + +echo "" +echo "=== Creating client (earth) configuration ===" + +# Create client wg1.conf +cat > "$TMPDIR/client-wg1.conf" << EOF +# WireGuard wg1 configuration for earth +# Client side of earth <-> hyperstack tunnel +# Generated by wg1-setup.sh on $(date) + +[Interface] +Address = ${CLIENT_WG_IP}/${SUBNET_MASK} +PrivateKey = ${CLIENT_PRIVATE_KEY} + +[Peer] +# hyperstack VM (server) +PublicKey = ${SERVER_PUBLIC_KEY} +Endpoint = ${VM_IP}:${WG_PORT} +AllowedIPs = ${SERVER_WG_IP}/32 +PersistentKeepalive = 25 +EOF + +print_success "Client config created" + +echo "" +echo "=== Setting up hyperstack VM (${VM_IP}) ===" + +# Check SSH connectivity +echo "Testing SSH connection..." +if ! ssh -o ConnectTimeout=10 -o BatchMode=yes "${SSH_USER}@${VM_IP}" "echo 'SSH OK'" 2>/dev/null; then + print_error "Error: Cannot connect to ${SSH_USER}@${VM_IP}" + print_error "Please ensure SSH access is configured." + exit 1 +fi +print_success "SSH connection OK" + +# Install WireGuard on server if not present +echo "Installing WireGuard on hyperstack..." +ssh "${SSH_USER}@${VM_IP}" "which wg >/dev/null 2>&1 || (sudo apt update && sudo apt install -y wireguard)" +print_success "WireGuard installed" + +# Copy server config to hyperstack +echo "Copying wg1.conf to hyperstack..." +scp "$TMPDIR/server-wg1.conf" "${SSH_USER}@${VM_IP}:/tmp/wg1.conf" +ssh "${SSH_USER}@${VM_IP}" "sudo mv /tmp/wg1.conf /etc/wireguard/wg1.conf && sudo chmod 600 /etc/wireguard/wg1.conf" +print_success "Server config installed" + +# Configure firewall on hyperstack +echo "Configuring firewall (ufw) on hyperstack..." +ssh "${SSH_USER}@${VM_IP}" << 'REMOTE_SCRIPT' +# Ensure ufw is enabled +sudo ufw --force enable >/dev/null 2>&1 || true + +# Allow WireGuard port +sudo ufw allow 56710/udp comment 'WireGuard wg1' 2>/dev/null || true + +# Allow Ollama access from wg1 subnet +sudo ufw allow from 192.168.3.0/24 to any port 11434 proto tcp comment 'Ollama via wg1' 2>/dev/null || true + +echo "Firewall rules added" +REMOTE_SCRIPT +print_success "Firewall configured" + +# Configure Ollama to listen on all interfaces +echo "Configuring Ollama to listen on 0.0.0.0..." +ssh "${SSH_USER}@${VM_IP}" << 'REMOTE_SCRIPT' +# Create override directory if it doesn't exist +sudo mkdir -p /etc/systemd/system/ollama.service.d + +# Create or update override.conf to bind Ollama to all interfaces +cat << 'OVERRIDE' | sudo tee /etc/systemd/system/ollama.service.d/override.conf > /dev/null +[Service] +Environment="OLLAMA_HOST=0.0.0.0:11434" +OVERRIDE + +# Reload systemd and restart Ollama +sudo systemctl daemon-reload +sudo systemctl restart ollama 2>/dev/null || echo "Note: Ollama service not running or not installed" +REMOTE_SCRIPT +print_success "Ollama configured" + +# Start wg1 on hyperstack +echo "Starting wg1 on hyperstack..." +ssh "${SSH_USER}@${VM_IP}" "sudo systemctl start wg-quick@wg1 2>/dev/null || sudo wg-quick up wg1" +print_success "wg1 started on hyperstack" + +echo "" +echo "=== Setting up earth (local) ===" + +# Check if WireGuard is installed locally +if ! which wg >/dev/null 2>&1; then + echo "Installing WireGuard locally..." + sudo dnf install -y wireguard-tools +fi +print_success "WireGuard installed locally" + +# Install client config locally +echo "Installing wg1.conf locally..." +sudo cp "$TMPDIR/client-wg1.conf" /etc/wireguard/wg1.conf +sudo chmod 600 /etc/wireguard/wg1.conf +print_success "Client config installed" + +# Stop existing wg1 if running, then start fresh +echo "Starting wg1 locally..." +sudo systemctl stop wg-quick@wg1 2>/dev/null || true +sudo systemctl start wg-quick@wg1 +print_success "wg1 started locally" + +echo "" +echo "==============================================" +print_success "Setup complete!" +echo "==============================================" +echo "" +echo "WireGuard wg1 tunnel is now active." +echo "" +echo "Tunnel IPs:" +echo " hyperstack (server): ${SERVER_WG_IP}" +echo " earth (client): ${CLIENT_WG_IP}" +echo "" +echo "=== Verification commands ===" +echo "" +echo "# Check tunnel status:" +echo "sudo wg show wg1" +echo "" +echo "# Ping hyperstack via tunnel:" +echo "ping -c 3 ${SERVER_WG_IP}" +echo "" +echo "# Verify default route is UNCHANGED:" +echo "ip route | grep default" +echo "" +echo "# Test Ollama access:" +echo "curl http://${SERVER_WG_IP}:11434/api/tags" +echo "" +echo "=== Manual start/stop commands ===" +echo "" +echo "# Stop tunnel:" +echo "sudo systemctl stop wg-quick@wg1" +echo "" +echo "# Start tunnel:" +echo "sudo systemctl start wg-quick@wg1" +echo "" +echo "# Restart on hyperstack (if VM rebooted):" +echo "ssh ${SSH_USER}@${VM_IP} 'sudo systemctl start wg-quick@wg1'" +echo "" +echo "=== Use Ollama remotely ===" +echo "" +echo "export OLLAMA_HOST=http://${SERVER_WG_IP}:11434" +echo "curl http://${SERVER_WG_IP}:11434/v1/models" |
