summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-01-23 21:37:07 +0200
committerPaul Buetow <paul@buetow.org>2026-01-23 21:37:07 +0200
commit4d27f91ea6e61020902fbb2ed916225b69866275 (patch)
treed4f6e40ca2130f81d4f6411244c187e6ef705be3
parentc0e3fc7492de0e3691d49bf0a890a5d1225b46f6 (diff)
more on hypserstack
-rwxr-xr-xsnippets/hyperstack/install.sh142
-rw-r--r--snippets/hyperstack/opencode-setup.md256
-rwxr-xr-xsnippets/hyperstack/wg1-setup.sh288
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"