Compare commits
1 Commits
feature/sy
...
feature/vp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
266d6ec008 |
22
configs/llama-server.service
Normal file
22
configs/llama-server.service
Normal file
@@ -0,0 +1,22 @@
|
||||
[Unit]
|
||||
Description=llama.cpp inference server for Timmy
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=root
|
||||
WorkingDirectory=/root/timmy
|
||||
ExecStart=/root/timmy/llama-server \
|
||||
-m /root/timmy/models/hermes-3-8b.Q4_K_M.gguf \
|
||||
--host 127.0.0.1 \
|
||||
--port 8081 \
|
||||
-c 8192 \
|
||||
-np 1 \
|
||||
--jinja \
|
||||
-ngl 0
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
Environment="HOME=/root"
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
17
configs/timmy-agent.service
Normal file
17
configs/timmy-agent.service
Normal file
@@ -0,0 +1,17 @@
|
||||
[Unit]
|
||||
Description=Timmy Agent Harness
|
||||
After=llama-server.service
|
||||
Requires=llama-server.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=root
|
||||
WorkingDirectory=/root/timmy
|
||||
ExecStart=/root/timmy/venv/bin/python /root/timmy/timmy-home/agent/agent_daemon.py
|
||||
Restart=always
|
||||
RestartSec=30
|
||||
Environment="HOME=/root"
|
||||
Environment="TIMMY_MODEL_URL=http://127.0.0.1:8081"
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -1,98 +0,0 @@
|
||||
# Syncthing Mesh Setup
|
||||
|
||||
Shared file synchronization across all Timmy VPS nodes.
|
||||
|
||||
## Overview
|
||||
|
||||
Syncthing provides peer-to-peer, encrypted file synchronization between all wizard VPS nodes. No central server required.
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
┌─────────────────┐ P2P Sync ┌─────────────────┐
|
||||
│ Allegro VPS │ ◄──────────────► │ Ezra VPS │
|
||||
│ 143.198.27.163 │ │ 167.99.126.228 │
|
||||
│ ~/shared/ │ │ ~/shared/ │
|
||||
└─────────────────┘ └─────────────────┘
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
### On Each VPS Node
|
||||
|
||||
```bash
|
||||
# Run the setup script
|
||||
curl -sL https://raw.githubusercontent.com/Timmy_Foundation/timmy-home/main/scripts/setup-syncthing.sh | bash
|
||||
```
|
||||
|
||||
Or manually:
|
||||
|
||||
```bash
|
||||
# Download and run setup script
|
||||
wget -O /tmp/setup-syncthing.sh https://raw.githubusercontent.com/Timmy_Foundation/timmy-home/main/scripts/setup-syncthing.sh
|
||||
chmod +x /tmp/setup-syncthing.sh
|
||||
/tmp/setup-syncthing.sh <node-name>
|
||||
```
|
||||
|
||||
## Node Status
|
||||
|
||||
| Node | IP | Device ID | Status |
|
||||
|------|-----|-----------|--------|
|
||||
| Allegro | 143.198.27.163 | MK6G5KV-VLTY7KS-FJ6ZN63-RV5ZIRG-7C2GSRS-OSJUDWA-IC6A7UP-NIGMQAE | ✅ Running |
|
||||
| Ezra | 167.99.126.228 | TBD | ⏳ Awaiting setup |
|
||||
| Future Timmy | TBD | TBD | ⏳ Future |
|
||||
|
||||
## Peering Nodes
|
||||
|
||||
After setup on each node:
|
||||
|
||||
1. Get device ID from each node:
|
||||
```bash
|
||||
syncthing --device-id
|
||||
```
|
||||
|
||||
2. On Allegro VPS, add Ezra's device:
|
||||
```bash
|
||||
syncthing cli config devices add --device-id=<EZRA_DEVICE_ID> --name=ezra
|
||||
```
|
||||
|
||||
3. On Ezra VPS, add Allegro's device:
|
||||
```bash
|
||||
syncthing cli config devices add --device-id=MK6G5KV-VLTY7KS-FJ6ZN63-RV5ZIRG-7C2GSRS-OSJUDWA-IC6A7UP-NIGMQAE --name=allegro
|
||||
```
|
||||
|
||||
4. Share the `shared` folder with the peer device via web UI or CLI.
|
||||
|
||||
## Testing Sync
|
||||
|
||||
```bash
|
||||
# On Allegro
|
||||
echo "Test from Allegro" > ~/shared/test-allegro.txt
|
||||
|
||||
# On Ezra (after 60 seconds)
|
||||
cat ~/shared/test-allegro.txt # Should show "Test from Allegro"
|
||||
```
|
||||
|
||||
## Web UI Access
|
||||
|
||||
```bash
|
||||
# SSH tunnel to access web UI locally
|
||||
ssh -L 8384:localhost:8384 root@<vps-ip>
|
||||
# Then open http://localhost:8384 in browser
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Issue | Solution |
|
||||
|-------|----------|
|
||||
| Nodes not connecting | Check firewall allows port 22000/tcp |
|
||||
| Web UI not accessible | Verify bound to 127.0.0.1:8384 |
|
||||
| Files not syncing | Check folder paths match on both nodes |
|
||||
| Service not starting | Check `systemctl status syncthing@root` |
|
||||
|
||||
## Security
|
||||
|
||||
- Web UI bound to localhost only (no external exposure)
|
||||
- All sync traffic is encrypted
|
||||
- Device IDs required for peering (no unauthorized access)
|
||||
- No central server - direct peer-to-peer only
|
||||
260
scripts/provision-timmy-vps.sh
Normal file
260
scripts/provision-timmy-vps.sh
Normal file
@@ -0,0 +1,260 @@
|
||||
#!/bin/bash
|
||||
# Timmy VPS Provisioning Script
|
||||
# Transforms fresh Ubuntu 22.04+ VPS into sovereign local-first wizard
|
||||
|
||||
set -e
|
||||
|
||||
TIMMY_USER="${TIMMY_USER:-root}"
|
||||
TIMMY_HOME="${TIMMY_HOME:-/root}"
|
||||
TIMMY_DIR="$TIMMY_HOME/timmy"
|
||||
REPO_URL="${REPO_URL:-http://143.198.27.163:3000/Timmy_Foundation/timmy-home.git}"
|
||||
MODEL_URL="${MODEL_URL:-https://huggingface.co/TheBloke/Hermes-3-Llama-3.1-8B-GGUF/resolve/main/hermes-3-llama-3.1-8b.Q4_K_M.gguf}"
|
||||
MODEL_NAME="${MODEL_NAME:-hermes-3-8b.Q4_K_M.gguf}"
|
||||
|
||||
echo "========================================"
|
||||
echo " Timmy VPS Provisioning"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
|
||||
# Colors
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
log() {
|
||||
echo -e "${GREEN}[TIMMY]${NC} $1"
|
||||
}
|
||||
|
||||
warn() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
# Check if running as root
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
error "Please run as root"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check Ubuntu version
|
||||
if ! grep -q "Ubuntu 22.04\|Ubuntu 24.04" /etc/os-release; then
|
||||
warn "Not Ubuntu 22.04/24.04 - may not work correctly"
|
||||
fi
|
||||
|
||||
log "Step 1/8: Installing system dependencies..."
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get update -qq
|
||||
apt-get install -y -qq \
|
||||
build-essential \
|
||||
cmake \
|
||||
git \
|
||||
curl \
|
||||
wget \
|
||||
python3 \
|
||||
python3-pip \
|
||||
python3-venv \
|
||||
libopenblas-dev \
|
||||
pkg-config \
|
||||
ufw \
|
||||
jq \
|
||||
sqlite3 \
|
||||
libsqlite3-dev \
|
||||
2>&1 | tail -5
|
||||
|
||||
log "Step 2/8: Setting up directory structure..."
|
||||
mkdir -p "$TIMMY_DIR"/{soul,scripts,logs,shared,models,configs}
|
||||
mkdir -p "$TIMMY_HOME/.config/systemd/user"
|
||||
|
||||
log "Step 3/8: Building llama.cpp from source..."
|
||||
if [ ! -f "$TIMMY_DIR/llama-server" ]; then
|
||||
cd /tmp
|
||||
git clone --depth 1 https://github.com/ggerganov/llama.cpp.git 2>/dev/null || true
|
||||
cd llama.cpp
|
||||
|
||||
# Build with OpenBLAS for CPU optimization
|
||||
cmake -B build \
|
||||
-DGGML_BLAS=ON \
|
||||
-DGGML_BLAS_VENDOR=OpenBLAS \
|
||||
-DLLAMA_BUILD_TESTS=OFF \
|
||||
-DLLAMA_BUILD_EXAMPLES=OFF \
|
||||
-DCMAKE_BUILD_TYPE=Release
|
||||
|
||||
cmake --build build --config Release -j$(nproc)
|
||||
|
||||
# Copy binaries
|
||||
cp build/bin/llama-server "$TIMMY_DIR/"
|
||||
cp build/bin/llama-cli "$TIMMY_DIR/"
|
||||
|
||||
log "llama.cpp built successfully"
|
||||
else
|
||||
log "llama.cpp already exists, skipping build"
|
||||
fi
|
||||
|
||||
log "Step 4/8: Downloading model weights..."
|
||||
if [ ! -f "$TIMMY_DIR/models/$MODEL_NAME" ]; then
|
||||
cd "$TIMMY_DIR/models"
|
||||
wget -q --show-progress "$MODEL_URL" -O "$MODEL_NAME" || {
|
||||
error "Failed to download model. Continuing anyway..."
|
||||
}
|
||||
log "Model downloaded"
|
||||
else
|
||||
log "Model already exists, skipping download"
|
||||
fi
|
||||
|
||||
log "Step 5/8: Setting up llama-server systemd service..."
|
||||
cat > /etc/systemd/system/llama-server.service << EOF
|
||||
[Unit]
|
||||
Description=llama.cpp inference server for Timmy
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=$TIMMY_USER
|
||||
WorkingDirectory=$TIMMY_DIR
|
||||
ExecStart=$TIMMY_DIR/llama-server \\
|
||||
-m $TIMMY_DIR/models/$MODEL_NAME \\
|
||||
--host 127.0.0.1 \\
|
||||
--port 8081 \\
|
||||
-c 8192 \\
|
||||
-np 1 \\
|
||||
--jinja \\
|
||||
-ngl 0
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
Environment="HOME=$TIMMY_HOME"
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable llama-server.service
|
||||
|
||||
log "Step 6/8: Cloning timmy-home repo and setting up agent..."
|
||||
if [ ! -d "$TIMMY_DIR/timmy-home" ]; then
|
||||
cd "$TIMMY_DIR"
|
||||
git clone "$REPO_URL" timmy-home 2>/dev/null || warn "Could not clone repo"
|
||||
fi
|
||||
|
||||
# Create minimal Python environment for agent
|
||||
if [ ! -d "$TIMMY_DIR/venv" ]; then
|
||||
python3 -m venv "$TIMMY_DIR/venv"
|
||||
"$TIMMY_DIR/venv/bin/pip" install -q requests pyyaml 2>&1 | tail -3
|
||||
fi
|
||||
|
||||
log "Step 7/8: Setting up Timmy agent systemd service..."
|
||||
cat > /etc/systemd/system/timmy-agent.service << EOF
|
||||
[Unit]
|
||||
Description=Timmy Agent Harness
|
||||
After=llama-server.service
|
||||
Requires=llama-server.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=$TIMMY_USER
|
||||
WorkingDirectory=$TIMMY_DIR
|
||||
ExecStart=$TIMMY_DIR/venv/bin/python $TIMMY_DIR/timmy-home/agent/agent_daemon.py
|
||||
Restart=always
|
||||
RestartSec=30
|
||||
Environment="HOME=$TIMMY_HOME"
|
||||
Environment="TIMMY_MODEL_URL=http://127.0.0.1:8081"
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable timmy-agent.service
|
||||
|
||||
log "Step 8/8: Configuring firewall..."
|
||||
# Reset UFW
|
||||
ufw --force reset 2>/dev/null || true
|
||||
ufw default deny incoming
|
||||
ufw default allow outgoing
|
||||
|
||||
# Allow SSH
|
||||
ufw allow 22/tcp
|
||||
|
||||
# Allow Syncthing (sync protocol)
|
||||
ufw allow 22000/tcp
|
||||
ufw allow 22000/udp
|
||||
|
||||
# Allow Syncthing (discovery)
|
||||
ufw allow 21027/udp
|
||||
|
||||
# Note: llama-server on 8081 is NOT exposed (localhost only)
|
||||
|
||||
ufw --force enable
|
||||
|
||||
log "Starting services..."
|
||||
systemctl start llama-server.service || warn "llama-server failed to start (may need model)"
|
||||
|
||||
# Wait for llama-server to be ready
|
||||
log "Waiting for llama-server to be ready..."
|
||||
for i in {1..30}; do
|
||||
if curl -s http://127.0.0.1:8081/health >/dev/null 2>&1; then
|
||||
log "llama-server is healthy!"
|
||||
break
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# Create status script
|
||||
cat > "$TIMMY_DIR/scripts/status.sh" << 'EOF'
|
||||
#!/bin/bash
|
||||
echo "=== Timmy VPS Status ==="
|
||||
echo ""
|
||||
echo "Services:"
|
||||
systemctl is-active llama-server.service && echo " llama-server: RUNNING" || echo " llama-server: STOPPED"
|
||||
systemctl is-active timmy-agent.service && echo " timmy-agent: RUNNING" || echo " timmy-agent: STOPPED"
|
||||
echo ""
|
||||
echo "Inference Health:"
|
||||
curl -s http://127.0.0.1:8081/health | jq . 2>/dev/null || echo " Not responding"
|
||||
echo ""
|
||||
echo "Disk Usage:"
|
||||
df -h $HOME | tail -1
|
||||
echo ""
|
||||
echo "Memory:"
|
||||
free -h | grep Mem
|
||||
EOF
|
||||
chmod +x "$TIMMY_DIR/scripts/status.sh"
|
||||
|
||||
# Create README
|
||||
cat > "$TIMMY_DIR/README.txt" << EOF
|
||||
Timmy Sovereign Wizard VPS
|
||||
==========================
|
||||
|
||||
Quick Commands:
|
||||
$TIMMY_DIR/scripts/status.sh - Check system status
|
||||
systemctl status llama-server - Check inference service
|
||||
systemctl status timmy-agent - Check agent service
|
||||
|
||||
Directories:
|
||||
$TIMMY_DIR/models/ - AI model weights
|
||||
$TIMMY_DIR/soul/ - SOUL.md and conscience files
|
||||
$TIMMY_DIR/logs/ - Agent logs
|
||||
$TIMMY_DIR/shared/ - Syncthing shared folder
|
||||
|
||||
Inference Endpoint:
|
||||
http://127.0.0.1:8081 (localhost only)
|
||||
|
||||
Provisioning complete!
|
||||
EOF
|
||||
|
||||
echo ""
|
||||
echo "========================================"
|
||||
log "Provisioning Complete!"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
echo "Status:"
|
||||
"$TIMMY_DIR/scripts/status.sh"
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo " 1. Run syncthing setup: curl -sL $REPO_URL/raw/branch/main/scripts/setup-syncthing.sh | bash"
|
||||
echo " 2. Check inference: curl http://127.0.0.1:8081/health"
|
||||
echo " 3. Review logs: journalctl -u llama-server -f"
|
||||
echo ""
|
||||
@@ -1,77 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Syncthing Setup Script for Timmy Fleet
|
||||
# Run this on each VPS node to join the sync mesh
|
||||
|
||||
set -e
|
||||
|
||||
NODE_NAME="${1:-$(hostname)}"
|
||||
HOME_DIR="${HOME:-/root}"
|
||||
CONFIG_DIR="$HOME_DIR/.config/syncthing"
|
||||
SHARED_DIR="$HOME_DIR/shared"
|
||||
|
||||
export HOME="$HOME_DIR"
|
||||
|
||||
echo "=== Syncthing Setup for $NODE_NAME ==="
|
||||
|
||||
# Install syncthing if not present
|
||||
if ! command -v syncthing &> /dev/null; then
|
||||
echo "Installing Syncthing..."
|
||||
curl -sL "https://github.com/syncthing/syncthing/releases/download/v1.27.0/syncthing-linux-amd64-v1.27.0.tar.gz" | tar -xzf - -C /tmp/
|
||||
cp /tmp/syncthing-linux-amd64-v1.27.0/syncthing /usr/local/bin/
|
||||
chmod +x /usr/local/bin/syncthing
|
||||
fi
|
||||
|
||||
# Create directories
|
||||
mkdir -p "$CONFIG_DIR"
|
||||
mkdir -p "$SHARED_DIR"
|
||||
|
||||
# Generate config if not exists
|
||||
if [ ! -f "$CONFIG_DIR/config.xml" ]; then
|
||||
echo "Generating Syncthing config..."
|
||||
syncthing generate --config="$CONFIG_DIR"
|
||||
fi
|
||||
|
||||
# Get device ID
|
||||
DEVICE_ID=$(syncthing --config="$CONFIG_DIR" --device-id 2>/dev/null || grep -oP '(?<=<device id=")[^"]+' "$CONFIG_DIR/config.xml" | head -1)
|
||||
echo "Device ID: $DEVICE_ID"
|
||||
|
||||
# Modify config: change folder path and bind GUI to localhost only
|
||||
echo "Configuring Syncthing..."
|
||||
sed -i 's|path="/root/Sync"|path="/root/shared"|g' "$CONFIG_DIR/config.xml"
|
||||
sed -i 's|<address>127.0.0.1:8384</address>|<address>127.0.0.1:8384</address>|g' "$CONFIG_DIR/config.xml"
|
||||
sed -i 's|<address>0.0.0.0:8384</address>|<address>127.0.0.1:8384</address>|g' "$CONFIG_DIR/config.xml"
|
||||
|
||||
# Create systemd service
|
||||
cat > /etc/systemd/system/syncthing@root.service << 'EOF'
|
||||
[Unit]
|
||||
Description=Syncthing - Open Source Continuous File Synchronization for %i
|
||||
Documentation=man:syncthing(1)
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
User=%i
|
||||
ExecStart=/usr/local/bin/syncthing -no-browser -no-restart -logflags=0
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
SuccessExitStatus=3 4
|
||||
RestartForceExitStatus=3 4
|
||||
Environment="HOME=/root"
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
# Enable and start service
|
||||
systemctl daemon-reload
|
||||
systemctl enable syncthing@root.service
|
||||
systemctl restart syncthing@root.service || systemctl start syncthing@root.service
|
||||
|
||||
echo ""
|
||||
echo "=== Setup Complete ==="
|
||||
echo "Node: $NODE_NAME"
|
||||
echo "Device ID: $DEVICE_ID"
|
||||
echo "Shared folder: $SHARED_DIR"
|
||||
echo "Web UI: http://127.0.0.1:8384 (localhost only)"
|
||||
echo ""
|
||||
echo "To peer with another node, add their device ID via the web UI"
|
||||
echo "or use: syncthing cli --config=$CONFIG_DIR config devices add --device-id=<ID>"
|
||||
Reference in New Issue
Block a user