security: remove all infrastructure and internal process material from the repo
Demo images / Build & push demo images (push) Failing after 2m13s
Demo images / Build & push demo images (push) Failing after 2m13s
The repo is source code and guidelines only. Nothing about how Archipelago's own fleet is run, or how the team works, stays in it. Untracked (kept on disk, gitignored) — 250 files: - .planning/ (199) and loop/ — internal development process - fleet operations tooling that targets specific nodes: deploy-to-target, deploy-tailscale, deploy-config-defaults, setup-target-dev, setup-aiui-server, setup-https-dev, debug-frontend, node-profile, fleet-fips-pair/unpair, image-recipe/sync-from-live.sh - image-recipe/INTEGRATION-GUIDE.md and docs/multinode-testing-plan.md, both of which are live-server workflow and fleet node inventories - the Phase 10 on-node verification and evidence records, which cite .planning/ as their evidence base KEY-05-ENTROPY-ENFORCEMENT.md was initially moved out with the other Phase 10 docs and then put back: it is cited as normative rationale from ten places in the codebase, including core/clippy.toml, which bans rand::thread_rng and points at it for the reason. That makes it a guideline, not an internal record. Node names removed from source (48 occurrences across comments, manifests and test fixtures): archi-dev-box, archy-x250*, shorty-s, framework-pt, zaza-optiplex, archi-thinkpad. Comments keep the engineering context and the date, which is what carried the meaning; the machine name did not. Three of those were live test values rather than comments and were replaced with valid stand-ins, not prose: two mDNS hostnames and a mesh peer name. An earlier pass substituted "a test node" into a hostname assertion, producing an invalid hostname; caught and fixed as test-node.local. Wipe mechanism: .local-only/manifest.txt inventories every local-only path and .local-only/wipe.sh deletes them on one confirmation, refusing to touch anything git still tracks. Both are themselves untracked, so the public repo does not carry a map of internal filenames. Verified: cargo check -p archipelago --all-features clean; archipelago-container 75/75 tests pass; appOrigin vitest 7/7; audit-secrets 5/5; every relative link in tracked markdown resolves (0 broken). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
cc00884b98
commit
6ba0599639
@@ -1,176 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Setup AIUI + Claude API proxy + FileBrowser on any Archipelago server
|
||||
#
|
||||
# Usage:
|
||||
# ./scripts/setup-aiui-server.sh <host>
|
||||
# ./scripts/setup-aiui-server.sh archipelago@192.168.1.198
|
||||
# ./scripts/setup-aiui-server.sh archipelago@192.168.1.228
|
||||
#
|
||||
# What it does:
|
||||
# 1. Deploys AIUI files (from local build)
|
||||
# 2. Configures nginx Claude API proxy (direct to Anthropic with API key)
|
||||
# 3. Fixes FileBrowser container (removes read-only root if needed)
|
||||
# 4. Reloads nginx
|
||||
#
|
||||
# Prerequisites:
|
||||
# - AIUI must be built locally first: cd AIUI/packages/app && VITE_BASE_PATH=/aiui/ npx vite build
|
||||
# - SSH key access to target server
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
SSH_KEY="${ARCHIPELAGO_SSH_KEY:-$HOME/.ssh/archipelago-deploy}"
|
||||
SSH_OPTS="-o StrictHostKeyChecking=no -i $SSH_KEY"
|
||||
|
||||
# Anthropic API key used by the AIUI Claude chat proxy. Keep this in the
|
||||
# caller's environment or scripts/deploy-config.sh; never commit live keys.
|
||||
ANTHROPIC_API_KEY="${ANTHROPIC_API_KEY:-}"
|
||||
|
||||
TARGET_HOST="$1"
|
||||
if [ -z "$TARGET_HOST" ]; then
|
||||
echo "Usage: $0 <user@host>"
|
||||
echo " e.g. $0 archipelago@192.168.1.198"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$ANTHROPIC_API_KEY" ]; then
|
||||
echo "ERROR: ANTHROPIC_API_KEY must be set in the environment."
|
||||
echo "Example: ANTHROPIC_API_KEY=<key> $0 $TARGET_HOST"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
AIUI_DIST="$PROJECT_DIR/../AIUI/packages/app/dist"
|
||||
if [ ! -f "$AIUI_DIST/index.html" ]; then
|
||||
echo "ERROR: AIUI build not found at $AIUI_DIST"
|
||||
echo "Build it first: cd ../AIUI/packages/app && VITE_BASE_PATH=/aiui/ npx vite build"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
timestamp() { echo "[$(date +%H:%M:%S)]"; }
|
||||
|
||||
echo "╔════════════════════════════════════════════════════════════╗"
|
||||
echo "║ Archipelago AIUI + Claude API Setup ║"
|
||||
echo "║ Target: $TARGET_HOST"
|
||||
echo "╚════════════════════════════════════════════════════════════╝"
|
||||
|
||||
# --- Step 1: Deploy AIUI files ---
|
||||
echo ""
|
||||
echo "$(timestamp) 📦 Deploying AIUI files..."
|
||||
|
||||
# Check if rsync is available on remote
|
||||
if ssh $SSH_OPTS "$TARGET_HOST" "which rsync" &>/dev/null; then
|
||||
rsync -avz --delete -e "ssh $SSH_OPTS" "$AIUI_DIST/" "$TARGET_HOST:/opt/archipelago/web-ui/aiui/" 2>&1 | tail -3
|
||||
else
|
||||
echo " rsync not available, using tar+scp..."
|
||||
TMPTAR=$(mktemp /tmp/aiui-dist-XXXXX.tar.gz)
|
||||
(cd "$AIUI_DIST" && tar czf "$TMPTAR" .)
|
||||
scp $SSH_OPTS "$TMPTAR" "$TARGET_HOST:/tmp/aiui-dist.tar.gz"
|
||||
ssh $SSH_OPTS "$TARGET_HOST" "sudo mkdir -p /opt/archipelago/web-ui/aiui && cd /opt/archipelago/web-ui/aiui && sudo tar xzf /tmp/aiui-dist.tar.gz --overwrite"
|
||||
rm -f "$TMPTAR"
|
||||
fi
|
||||
echo " AIUI deployed."
|
||||
|
||||
# --- Step 2: Configure nginx Claude API proxy ---
|
||||
echo ""
|
||||
echo "$(timestamp) 🔧 Configuring nginx Claude API proxy..."
|
||||
|
||||
# Create a Python script to patch nginx config
|
||||
cat << 'PYSCRIPT' > /tmp/patch-nginx-claude.py
|
||||
import sys
|
||||
import re
|
||||
|
||||
API_KEY = sys.argv[1]
|
||||
|
||||
with open("/etc/nginx/sites-available/archipelago") as f:
|
||||
content = f.read()
|
||||
|
||||
# The new Claude API proxy block
|
||||
new_block = '''location /aiui/api/claude/ {
|
||||
if ($cookie_session = "") {
|
||||
return 401 '{"error":"Unauthorized"}';
|
||||
}
|
||||
proxy_pass https://api.anthropic.com/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host api.anthropic.com;
|
||||
proxy_set_header x-api-key "''' + API_KEY + '''";
|
||||
proxy_set_header anthropic-version "2023-06-01";
|
||||
proxy_set_header anthropic-dangerous-direct-browser-access "true";
|
||||
proxy_ssl_server_name on;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_buffering off;
|
||||
proxy_cache off;
|
||||
proxy_connect_timeout 120s;
|
||||
proxy_read_timeout 300s;
|
||||
proxy_send_timeout 120s;
|
||||
}'''
|
||||
|
||||
# Replace existing Claude API proxy blocks (handles both old proxy and direct patterns)
|
||||
pattern = r'location /aiui/api/claude/ \{[^}]*(?:\{[^}]*\}[^}]*)*\}'
|
||||
content = re.sub(pattern, new_block, content)
|
||||
|
||||
with open("/etc/nginx/sites-available/archipelago", "w") as f:
|
||||
f.write(content)
|
||||
|
||||
# Verify
|
||||
count = content.count("api.anthropic.com")
|
||||
print(f" Patched {count // 2} Claude API proxy blocks (HTTP + HTTPS)")
|
||||
PYSCRIPT
|
||||
|
||||
scp $SSH_OPTS /tmp/patch-nginx-claude.py "$TARGET_HOST:/tmp/patch-nginx-claude.py"
|
||||
ssh $SSH_OPTS "$TARGET_HOST" "sudo python3 /tmp/patch-nginx-claude.py '$ANTHROPIC_API_KEY'"
|
||||
|
||||
# Test and reload nginx
|
||||
echo " Testing nginx config..."
|
||||
ssh $SSH_OPTS "$TARGET_HOST" "sudo nginx -t 2>&1 && sudo systemctl reload nginx && echo ' Nginx reloaded OK'" || {
|
||||
echo " ERROR: nginx config test failed!"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# --- Step 3: Fix FileBrowser container ---
|
||||
echo ""
|
||||
echo "$(timestamp) 📁 Checking FileBrowser..."
|
||||
|
||||
FB_STATUS=$(ssh $SSH_OPTS "$TARGET_HOST" "podman inspect filebrowser 2>/dev/null | grep -oP '\"ReadonlyRootfs\":\s*\K\w+'" 2>/dev/null || echo "not_found")
|
||||
|
||||
if [ "$FB_STATUS" = "true" ]; then
|
||||
echo " FileBrowser has read-only root — recreating..."
|
||||
ssh $SSH_OPTS "$TARGET_HOST" "
|
||||
podman stop filebrowser 2>/dev/null
|
||||
podman rm filebrowser 2>/dev/null
|
||||
sudo mkdir -p /var/lib/archipelago/filebrowser
|
||||
podman run -d --name filebrowser --restart=always \
|
||||
-p 8083:80 \
|
||||
-v /var/lib/archipelago/filebrowser:/srv \
|
||||
filebrowser/filebrowser:v2.27.0
|
||||
" 2>&1 | tail -2
|
||||
echo " FileBrowser recreated."
|
||||
elif [ "$FB_STATUS" = "not_found" ]; then
|
||||
echo " FileBrowser not found — creating..."
|
||||
ssh $SSH_OPTS "$TARGET_HOST" "
|
||||
sudo mkdir -p /var/lib/archipelago/filebrowser
|
||||
podman run -d --name filebrowser --restart=always \
|
||||
-p 8083:80 \
|
||||
-v /var/lib/archipelago/filebrowser:/srv \
|
||||
filebrowser/filebrowser:v2.27.0
|
||||
" 2>&1 | tail -2
|
||||
echo " FileBrowser created."
|
||||
else
|
||||
echo " FileBrowser OK (ReadonlyRootfs: $FB_STATUS)"
|
||||
fi
|
||||
|
||||
# --- Step 4: Verify ---
|
||||
echo ""
|
||||
echo "$(timestamp) ✅ Verification..."
|
||||
ssh $SSH_OPTS "$TARGET_HOST" "
|
||||
echo \" AIUI index: \$(ls -la /opt/archipelago/web-ui/aiui/index.html 2>/dev/null | awk '{print \$6,\$7,\$8}')\"
|
||||
echo \" FileBrowser: \$(podman ps --format '{{.Names}} {{.Status}}' | grep filebrowser)\"
|
||||
echo \" Nginx: \$(systemctl is-active nginx)\"
|
||||
echo \" Backend: \$(systemctl is-active archipelago)\"
|
||||
echo \" Claude API test: \$(curl -s -o /dev/null -w '%{http_code}' -X POST http://localhost/aiui/api/claude/v1/messages -H 'Content-Type: application/json' -H 'Cookie: session=test' -d '{\"model\":\"claude-sonnet-4-20250514\",\"max_tokens\":5,\"messages\":[{\"role\":\"user\",\"content\":\"hi\"}]}')\"
|
||||
"
|
||||
|
||||
echo ""
|
||||
echo "$(timestamp) Done! Server configured."
|
||||
echo " Access: http://$(echo $TARGET_HOST | cut -d@ -f2)"
|
||||
Reference in New Issue
Block a user