27f6d95bf6
Removals: openwebui and netclaw compose + Traefik routes (both decommissioned). Updates: litellm, n8n, vaultwarden, ai-agents, media, traefik routes, CLAUDE.md (nodes/ports/known-issues), agent definitions. Additions: Rongorongo tree, LinkedStorm plan, rename-bart spec, vllm brief, tls-options and security-headers Traefik config. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
323 lines
8.4 KiB
Markdown
323 lines
8.4 KiB
Markdown
# RONGORONGO_DEPLOY.md
|
||
# Rongorongo Decipherment Engine — Claude Code Deployment Guide
|
||
# Target: hobbs.farm Docker Swarm infrastructure
|
||
# Subdomain: rongorongo.hobbs.farm
|
||
|
||
---
|
||
|
||
## CONTEXT
|
||
|
||
This document instructs Claude Code to build, push, and deploy the Rongorongo
|
||
Decipherment Engine as a containerized static web app to the hobbs.farm Swarm.
|
||
|
||
The app is a single-file HTML/JS application served by nginx. It calls the
|
||
Anthropic API directly from the browser. No backend, no database. All session
|
||
state is stored in browser localStorage.
|
||
|
||
Infrastructure assumptions (from existing hobbs.farm stack):
|
||
- Docker Swarm: nodes hf-pdocker-01, hf-pdocker-02, bart
|
||
- Traefik reverse proxy with wildcard *.hobbs.farm TLS via Cloudflare DNS
|
||
- External overlay network: traefik-public
|
||
- Registry: registry.hobbs.farm (if local) OR use Docker Hub as fallback
|
||
- Portainer CE available for stack management
|
||
- DNS: AdGuard Home with hairpin NAT for *.hobbs.farm
|
||
|
||
---
|
||
|
||
## REPOSITORY STRUCTURE
|
||
|
||
After cloning or creating the project, verify this structure exists:
|
||
|
||
```
|
||
rongorongo/
|
||
├── Dockerfile
|
||
├── nginx.conf
|
||
├── stack.yml
|
||
├── frontend/
|
||
│ └── index.html
|
||
└── RONGORONGO_DEPLOY.md (this file)
|
||
```
|
||
|
||
---
|
||
|
||
## STEP 1 — VERIFY PREREQUISITES
|
||
|
||
Run these checks before proceeding. Stop and report any failures.
|
||
|
||
```bash
|
||
# Confirm Docker and Swarm context
|
||
docker info | grep -E "Swarm:|Manager:|Nodes:"
|
||
|
||
# Confirm traefik-public network exists
|
||
docker network ls | grep traefik-public
|
||
|
||
# Confirm Traefik is running
|
||
docker service ls | grep traefik
|
||
|
||
# Test registry connectivity (if using local registry)
|
||
curl -s https://registry.hobbs.farm/v2/_catalog || echo "Registry unreachable — will use build-and-load method"
|
||
|
||
# Confirm you are on a Swarm manager node
|
||
docker node ls
|
||
```
|
||
|
||
If registry.hobbs.farm is unreachable, use the ALTERNATIVE DEPLOYMENT method
|
||
at the bottom of this document.
|
||
|
||
---
|
||
|
||
## STEP 2 — BUILD THE IMAGE
|
||
|
||
```bash
|
||
cd rongorongo/
|
||
|
||
# Build image
|
||
docker build -t registry.hobbs.farm/rongorongo:latest .
|
||
|
||
# Verify image was created
|
||
docker images | grep rongorongo
|
||
```
|
||
|
||
Expected output: image tagged `registry.hobbs.farm/rongorongo:latest`, size
|
||
should be ~25–40MB (nginx:alpine base + small HTML file).
|
||
|
||
---
|
||
|
||
## STEP 3 — PUSH TO REGISTRY
|
||
|
||
```bash
|
||
# If registry requires auth:
|
||
docker login registry.hobbs.farm
|
||
|
||
# Push
|
||
docker push registry.hobbs.farm/rongorongo:latest
|
||
```
|
||
|
||
If the push fails due to registry issues, fall through to ALTERNATIVE DEPLOYMENT.
|
||
|
||
---
|
||
|
||
## STEP 4 — DEPLOY STACK
|
||
|
||
```bash
|
||
# Deploy or update the stack
|
||
docker stack deploy -c stack.yml rongorongo --with-registry-auth
|
||
|
||
# Watch rollout
|
||
docker service ps rongorongo_rongorongo --no-trunc
|
||
```
|
||
|
||
Wait for the service to show `Running` status. This typically takes 15–30 seconds.
|
||
|
||
```bash
|
||
# Confirm healthy
|
||
docker service ls | grep rongorongo
|
||
curl -s http://localhost/health # or via container exec
|
||
```
|
||
|
||
---
|
||
|
||
## STEP 5 — DNS VERIFICATION
|
||
|
||
The stack.yml assumes `rongorongo.hobbs.farm` resolves to the Traefik entrypoint.
|
||
|
||
```bash
|
||
# Check AdGuard Home has the record (or wildcard covers it)
|
||
nslookup rongorongo.hobbs.farm
|
||
|
||
# Test internal access
|
||
curl -sk https://rongorongo.hobbs.farm/health
|
||
```
|
||
|
||
If using AdGuard Home for internal DNS and the wildcard *.hobbs.farm is already
|
||
configured for hairpin NAT, no additional DNS entry is needed.
|
||
|
||
---
|
||
|
||
## STEP 6 — SMOKE TEST
|
||
|
||
Open https://rongorongo.hobbs.farm in a browser and verify:
|
||
1. App loads with "Rongorongo · Decipherment Engine" title
|
||
2. Sidebar navigation works (Image Corpus, Glyph Catalog, etc.)
|
||
3. Enter an Anthropic API key in the sidebar footer input
|
||
4. Upload a test image to the corpus
|
||
5. Navigate to Pattern Analyzer and run an analysis
|
||
6. Confirm AI response appears in the result box
|
||
|
||
---
|
||
|
||
## UPDATING THE APP
|
||
|
||
When index.html is modified:
|
||
|
||
```bash
|
||
cd rongorongo/
|
||
|
||
# Rebuild
|
||
docker build -t registry.hobbs.farm/rongorongo:latest .
|
||
|
||
# Push
|
||
docker push registry.hobbs.farm/rongorongo:latest
|
||
|
||
# Force service update (pull new image)
|
||
docker service update --image registry.hobbs.farm/rongorongo:latest --force rongorongo_rongorongo
|
||
|
||
# Watch update
|
||
docker service ps rongorongo_rongorongo
|
||
```
|
||
|
||
---
|
||
|
||
## ROLLBACK
|
||
|
||
If something breaks after an update:
|
||
|
||
```bash
|
||
docker service rollback rongorongo_rongorongo
|
||
docker service ps rongorongo_rongorongo
|
||
```
|
||
|
||
---
|
||
|
||
## TEARDOWN
|
||
|
||
To remove the service without destroying data (there is no persistent volume):
|
||
|
||
```bash
|
||
docker stack rm rongorongo
|
||
```
|
||
|
||
---
|
||
|
||
## ALTERNATIVE DEPLOYMENT (no registry)
|
||
|
||
Use this if registry.hobbs.farm is unavailable. This method builds the image
|
||
directly on the Swarm manager and uses `docker service create` instead of
|
||
`stack deploy`.
|
||
|
||
```bash
|
||
# On the Swarm manager node:
|
||
cd rongorongo/
|
||
|
||
# Build locally
|
||
docker build -t rongorongo:latest .
|
||
|
||
# Create service manually (adjust Traefik labels as needed)
|
||
docker service create \
|
||
--name rongorongo_rongorongo \
|
||
--network traefik-public \
|
||
--label "traefik.enable=true" \
|
||
--label "traefik.docker.network=traefik-public" \
|
||
--label "traefik.http.routers.rongorongo.rule=Host(\`rongorongo.hobbs.farm\`)" \
|
||
--label "traefik.http.routers.rongorongo.entrypoints=websecure" \
|
||
--label "traefik.http.routers.rongorongo.tls=true" \
|
||
--label "traefik.http.routers.rongorongo.tls.certresolver=cloudflare" \
|
||
--label "traefik.http.services.rongorongo.loadbalancer.server.port=80" \
|
||
--replicas 1 \
|
||
--restart-condition on-failure \
|
||
rongorongo:latest
|
||
|
||
# Monitor
|
||
docker service ps rongorongo_rongorongo
|
||
```
|
||
|
||
NOTE: With this method, to update you must rebuild locally and run:
|
||
```bash
|
||
docker service update --image rongorongo:latest --force rongorongo_rongorongo
|
||
```
|
||
|
||
This only works if your current node is the one running the replica. If you
|
||
have a multi-node swarm, you should set up the registry to avoid placement issues.
|
||
|
||
---
|
||
|
||
## PORTAINER DEPLOYMENT (optional GUI method)
|
||
|
||
If you prefer Portainer CE:
|
||
|
||
1. Navigate to https://portainer.hobbs.farm (or your Portainer URL)
|
||
2. Select the Swarm endpoint
|
||
3. Go to Stacks → Add Stack
|
||
4. Name: `rongorongo`
|
||
5. Paste the contents of stack.yml into the web editor
|
||
6. Set `registry.hobbs.farm/rongorongo:latest` as the image
|
||
(you still need to build and push first)
|
||
7. Click Deploy the stack
|
||
|
||
---
|
||
|
||
## ENVIRONMENT NOTES
|
||
|
||
The app does NOT use environment variables or Docker secrets. The Anthropic API
|
||
key is entered by the user at runtime and stored in their browser's localStorage.
|
||
This is intentional — the app is designed to be used by a single user (Jeremy)
|
||
and no server-side key storage is needed or appropriate.
|
||
|
||
If you want to pre-populate the API key for convenience (only if the deployment
|
||
is strictly private/internal), you can inject it at build time by modifying
|
||
frontend/index.html before building:
|
||
|
||
Find this line:
|
||
```javascript
|
||
function getApiKey() {
|
||
return document.getElementById('apiKeyInput').value.trim()
|
||
```
|
||
|
||
And prepend a hardcoded fallback (NOT recommended for any externally accessible URL).
|
||
|
||
---
|
||
|
||
## TRAEFIK ENTRYPOINT NAMES
|
||
|
||
The stack.yml assumes:
|
||
- HTTP entrypoint name: `web`
|
||
- HTTPS entrypoint name: `websecure`
|
||
- Cert resolver name: `cloudflare`
|
||
|
||
These match the standard hobbs.farm Traefik configuration. If your Traefik uses
|
||
different names, edit the labels in stack.yml before deploying.
|
||
|
||
---
|
||
|
||
## TROUBLESHOOTING
|
||
|
||
**Service won't start:**
|
||
```bash
|
||
docker service ps rongorongo_rongorongo --no-trunc
|
||
docker inspect $(docker ps -q --filter name=rongorongo) 2>/dev/null | grep -A5 '"State"'
|
||
```
|
||
|
||
**Traefik not routing:**
|
||
```bash
|
||
# Check Traefik logs for rongorongo
|
||
docker service logs traefik_traefik 2>&1 | grep -i rongorongo | tail -20
|
||
# Confirm labels are applied
|
||
docker service inspect rongorongo_rongorongo | grep -A2 Labels
|
||
```
|
||
|
||
**TLS cert not issuing:**
|
||
```bash
|
||
# Wildcard cert should already cover rongorongo.hobbs.farm
|
||
# If not, check Cloudflare DNS API token has Zone:Read and DNS:Edit
|
||
docker service logs traefik_traefik 2>&1 | grep -i "acme\|certificate\|cloudflare" | tail -20
|
||
```
|
||
|
||
**API calls blocked (CORS/CSP):**
|
||
The nginx.conf includes a Content-Security-Policy header that allows
|
||
`connect-src https://api.anthropic.com`. If you see CORS errors in the browser
|
||
console, verify the CSP header is present:
|
||
```bash
|
||
curl -I https://rongorongo.hobbs.farm/ | grep -i content-security
|
||
```
|
||
|
||
**App loads but AI calls fail:**
|
||
- Check API key is entered correctly in the sidebar
|
||
- Anthropic API key must start with `sk-ant-`
|
||
- Confirm outbound HTTPS to api.anthropic.com is not blocked by firewall rules
|
||
- The app sends `anthropic-dangerous-direct-browser-access: true` header which
|
||
is required for direct browser API access
|
||
|
||
---
|
||
|
||
## END OF DEPLOYMENT GUIDE
|