mirror of
https://github.com/myronblair/infra
synced 2026-06-30 17:50:10 -05:00
Compare commits
10 Commits
master
..
e9af102dbe
| Author | SHA1 | Date | |
|---|---|---|---|
| e9af102dbe | |||
| 27df1eb7c9 | |||
| 79db9f1a55 | |||
| a467a1de8f | |||
| 225259f1f4 | |||
| 2a92b958c1 | |||
| b71e58bbae | |||
| 3080273e0a | |||
| f8c406dbad | |||
| 52f6073593 |
@@ -1,345 +0,0 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Environment
|
||||
|
||||
This is a home-lab / managed-hosting environment. There is no local codebase to build or test — work consists of editing PHP/JS files on remote servers via SSH and managing infrastructure across several machines. All tool calls use `sshpass` with password auth.
|
||||
|
||||
## Tailscale Network
|
||||
|
||||
All key hosts are on Tailscale (myronblair@gmail.com). Use Tailscale IPs for SSH — no relay or port forwarding needed.
|
||||
|
||||
| Host | Tailscale IP | LAN IP | Password |
|
||||
|------|-------------|--------|----------|
|
||||
| Claude VM (this) | 100.69.120.58 | 10.48.200.29 | — |
|
||||
| PVE1 | 100.80.188.8 | 10.48.200.90 | `Joker1974!!!` |
|
||||
| PVE2 | 100.87.186.12 | 10.48.200.91 | `Joker1974!!!` |
|
||||
| DO server (orbis) | 100.121.13.34 | 165.22.1.228 | `Gonewalk1974!@#` |
|
||||
| FusionPBX | 100.74.46.120 | 134.209.72.226 | `Joker1974!@#` |
|
||||
| JARVIS VM | 100.77.178.42 | 10.48.200.211 | `Joker1974!!!` |
|
||||
| NPM VM | 100.110.239.71 | 10.48.200.201 | `Joker1974!!!` |
|
||||
| Ollama VM | 100.96.100.113 | 10.48.200.210 | `Joker1974!!!` |
|
||||
| NovaCPX (hostpanel-110) | 100.86.51.18 | 10.48.200.110 | `Joker1974!!!` |
|
||||
| HomeBridge | 100.124.182.18 | 10.48.200.18 | — |
|
||||
| WireGuard CT | 100.122.55.10 | 10.48.200.19 | — |
|
||||
| Synology NAS | 100.118.175.5 | 10.48.200.249 | — |
|
||||
| mini-it12 (Windows) | 100.98.151.120 | 10.48.200.87 | — |
|
||||
|
||||
**DNS note:** FortiGate blocks outbound port 53. All PVE1 VMs must use `10.48.200.90` (PVE1 dnsmasq → 100.100.100.100) as their DNS server, not 8.8.8.8 directly.
|
||||
|
||||
## Server Map
|
||||
|
||||
| Host | IP | SSH | Purpose |
|
||||
|------|-----|-----|---------|
|
||||
| DO (main) | 165.22.1.228 | `root / Gonewalk1974!@#` | CyberPanel/OLS — all websites (not JARVIS after migration) |
|
||||
| FusionPBX | 134.209.72.226 | `root / Joker1974!@#` (via Tailscale 100.74.46.120) | FreeSWITCH PBX |
|
||||
| PVE1 (Proxmox) | orbisne.fortiddns.com (10.48.200.90) | `root / Joker1974!!!` (via Tailscale 100.80.188.8) | Primary hypervisor |
|
||||
| PVE2 (Proxmox) | 10.48.200.91 | `root / Joker1974!!!` | Secondary hypervisor |
|
||||
| JARVIS VM | 10.48.200.211 | `root / Joker1974!!!` (via Tailscale 100.77.178.42) | JARVIS dashboard — PVE1 VM 211, 8c/16GB |
|
||||
| NPM VM | 10.48.200.201 | `root / Joker1974!!!` (via Tailscale 100.110.239.71) | Nginx Proxy Manager — PVE1 VM 105 (was VM200 pre-2026-06-22 restore; cloud-init says .200 but runs at .201) |
|
||||
| Ollama VM | 10.48.200.210 | `root / Joker1974!!!` (via Tailscale 100.96.100.113) | Local LLM — PVE1 VM 106 (was VM210 pre-2026-06-22 restore), 4c/8GB |
|
||||
| Home Assistant | 10.48.200.97 | `myron → sudo` | HA VM 101 |
|
||||
| NetworkBackup | 10.48.200.99 | `myron → sudo` | Backup VM (PVE2 VM 302) |
|
||||
| MediaStack | 10.48.200.35 | `root via PVE1 key` | Sonarr/Radarr/Prowlarr/qBittorrent (PVE1 VM 103, was VM113 pre-2026-06-22 restore) |
|
||||
| NovaCPX | 10.48.200.110 | `root / Joker1974!!!` (direct SSH — Tailscale 100.86.51.18 needs re-auth) | Custom hosting control panel (PVE1 VM 120) |
|
||||
| NPM | 10.48.200.201 | `root / Joker1974!!!` (via Tailscale 100.110.239.71) | Nginx Proxy Manager — PVE1 VM 200 · NPM API: `POST http://localhost:81/api/tokens` identity=myronblair@outlook.com |
|
||||
|
||||
**SSH password order** (try in sequence if first fails): `Joker1974!@#` → `Joker1974!!!` → `Joker1974!`
|
||||
|
||||
**SSH pattern for all remote work:**
|
||||
```bash
|
||||
sshpass -p 'Gonewalk1974!@#' ssh -o StrictHostKeyChecking=no root@165.22.1.228 'commands here'
|
||||
```
|
||||
|
||||
For PVE1 from anywhere (FortiGate DDNS, survives IP changes):
|
||||
```bash
|
||||
sshpass -p 'Joker1974!!!' ssh -o StrictHostKeyChecking=no root@orbisne.fortiddns.com 'commands here'
|
||||
```
|
||||
|
||||
For commands inside VMs on PVE1:
|
||||
```bash
|
||||
sshpass -p 'Joker1974!!!' ssh -o StrictHostKeyChecking=no root@orbisne.fortiddns.com \
|
||||
'qm guest exec <VMID> -- bash -c "commands here"'
|
||||
```
|
||||
|
||||
## Websites on DO (165.22.1.228)
|
||||
|
||||
All sites live at `/home/<domain>/public_html/` on DO. CyberPanel/OpenLiteSpeed serves them.
|
||||
|
||||
| Site | Path | GitHub |
|
||||
|------|------|--------|
|
||||
| ~~jarvis.orbishosting.com~~ | ~~removed from DO~~ | myronblair/jarvis (now on PVE1 VM 211) |
|
||||
| tomsjavajive.com | /home/tomsjavajive.com/public_html/ | myronblair/tomsjavajive |
|
||||
| epictravelexpeditions.com | /home/epictravelexpeditions.com/public_html/ | myronblair/epictravelexpeditions |
|
||||
| parkerslingshotrentals.com | /home/parkerslingshotrentals.com/public_html/ | myronblair/parkerslingshotrentals |
|
||||
| orbishosting.com | /home/orbishosting.com/public_html/ | myronblair/orbishosting |
|
||||
| orbis.orbishosting.com | /home/orbis.orbishosting.com/public_html/ | myronblair/orbis-hosting-portal |
|
||||
| tomtomgames.com | /home/tomtomgames.com/public_html/ | myronblair/tomtomgames |
|
||||
|
||||
**Parker Slingshot** is served from epictravelexpeditions.com, not its own domain:
|
||||
- URL: `https://parkerslingshot.epictravelexpeditions.com`
|
||||
- Path: `/home/epictravelexpeditions.com/parkerslingshot/`
|
||||
- GitHub: `myronblair/parkerslingshot` (own repo, auto-deploy active)
|
||||
- `db.php` and `config.php` are gitignored (credentials); `db.php.example` is the reference template
|
||||
|
||||
## Deployment Workflow
|
||||
|
||||
**Auto-deploy is active.** Push to `main` on any site repo → GitHub webhook → server pulls automatically within 1 minute. PHP syntax is validated before deploy; bad commits are auto-reverted.
|
||||
|
||||
**Two separate webhook handlers:**
|
||||
- **JARVIS repo** → `http://jarvis.orbishosting.com:1972/webhook.php` — deploys to JARVIS VM (`/var/www/jarvis/`). Deploy log: `/var/www/jarvis/logs/deploy.log`
|
||||
- **All 6 website repos → `https://tomtomgames.com/webhook.php` on DO — deploys to `/home/<site>/public_html/` on DO. Deploy log: `/home/tomtomgames.com/logs/deploy.log`. Deploy log: `/home/<site>/logs/deploy.log`
|
||||
|
||||
HMAC secret (both handlers): `4c8805f0285214ff0a0602b5880270b935f36a896946c7f1`
|
||||
Deploy queue: `/tmp/jarvis-deploy-queue.txt` | Runner: `/usr/local/bin/jarvis-deploy.sh` (cron every min, on both DO and JARVIS VM)
|
||||
|
||||
For hotfixes that can't wait 1 min, SCP directly:
|
||||
```bash
|
||||
# JARVIS VM
|
||||
scp -o StrictHostKeyChecking=no /tmp/changed.php root@100.77.178.42:/var/www/jarvis/public_html/changed.php
|
||||
# DO websites
|
||||
sshpass -p 'Gonewalk1974!@#' scp -o StrictHostKeyChecking=no /tmp/changed.php \
|
||||
root@165.22.1.228:/home/site.com/public_html/changed.php
|
||||
```
|
||||
|
||||
GitHub PAT (embedded in remote URLs): `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` — expires ~2026-08-20.
|
||||
Infra repo: `myronblair/infra` — cloned at `/opt/infra` on DO server.
|
||||
|
||||
**DO server backup:** `myronblair/do-server-config` — scripts, systemd units, WireGuard, OLS vhosts, cron, MySQL creds + 8-phase restore wizard. Weekly Sunday 4am. Launcher: `/usr/local/bin/do-server-backup`.
|
||||
|
||||
Gitignored credentials (never in GitHub): `api/config.php` (JARVIS, epictravelexpeditions), `config/database.php` (tomsjavajive).
|
||||
|
||||
## JARVIS System
|
||||
|
||||
Iron Man-style AI dashboard at `http://jarvis.orbishosting.com:1972`. **Migrated from DO to PVE1 VM 211 (2026-06-18).** All files on JARVIS VM at `/var/www/jarvis/`.
|
||||
|
||||
**Access:**
|
||||
- Dashboard: `http://jarvis.orbishosting.com:1972`
|
||||
- Admin: `http://jarvis.orbishosting.com:1972/admin`
|
||||
- Internal (LAN): `http://10.48.200.211` or via Tailscale `http://100.77.178.42`
|
||||
- FortiGate VIP: external port `1972` → `10.48.200.211:80`
|
||||
- Cloudflare: DNS only (grey cloud) — no CF proxy, no SSL overhead on origin
|
||||
|
||||
**Stack on JARVIS VM:**
|
||||
- nginx + PHP 8.3-FPM (replaces OLS/lsphp on DO)
|
||||
- MariaDB (jarvis_db local, `jarvis_user / J4rv1s_Pr0t0c0l_2026!`)
|
||||
- Redis (`redis-server`)
|
||||
- Python 3 + Arc Reactor daemon
|
||||
|
||||
**Architecture:**
|
||||
- `public_html/api.php` — API router; `session_start()` skipped only for machine-agent sub-actions (heartbeat/metrics/ha_state/command_result/register); browser-facing agent routes (list/status/myip) need session. Has `session_write_close()` guard (must skip for `auth` endpoint to prevent LSAPI session deadlock).
|
||||
- `api/config.php` — all credentials/constants (gitignored)
|
||||
- `api/endpoints/chat.php` — 4-tier AI: KB intent → Groq (`compound-beta-mini`) → Claude API; includes Tier 0.7 planner intents (tasks/appointments/briefing). Ollama at `http://10.48.200.210:11434`.
|
||||
- `api/endpoints/agent.php` — push-based agent registration/heartbeat/metrics; browser actions (list/status/myip) auth via `$_SESSION`, machine actions auth via `X-Agent-Key` header
|
||||
- `api/endpoints/alerts.php` — auto-generates alerts (CPU >85%, RAM >85%, disk >88%, offline agents, site down); dispatches restart commands to agents when their services fail
|
||||
- `api/endpoints/facts_collector.php` — runs every 3 min via cron (php8.3); collects agent metrics, KB facts, Proxmox/HA status, and all 7 site HTTP health checks. Site checks use external URLs (JARVIS VM is NOT the web host). `$fresh()` queries `WHERE category=?` (not `fact_category`).
|
||||
- `api/endpoints/stats_cache.php` — runs every 5 min via cron; weather/news/Proxmox cache refresh. Proxmox API at `https://10.48.200.90:8006` (direct LAN).
|
||||
- `api/endpoints/do_server.php` — reads `/proc` for JARVIS VM stats; also includes DO server agent metrics (`do_server` key from jarvis-do agent via Tailscale).
|
||||
- `api/endpoints/planner.php` — tasks & appointments CRUD; routes: `planner/tasks`, `planner/appointments`, `planner/today`, `planner/done`
|
||||
- `api/endpoints/ha.php` — HA entity list reads from `ha_entities` table (real-time agent push); service calls go direct to HA_URL (`http://10.48.200.97:8123`)
|
||||
- `api/lib/kb_engine.php` — `storeFact()` ON DUPLICATE KEY UPDATE always sets `updated_at=NOW()` explicitly; without this, unchanged values don't bump the timestamp and freshness checks break.
|
||||
|
||||
**Voice system (index.html):**
|
||||
- Continuous SpeechRecognition; mic stays open always (mute toggle button)
|
||||
- **Phase 1 wake**: say "wake up JARVIS" or "daddy's home" → activates voice mode once
|
||||
- **Phase 2 command**: say "JARVIS [command]" → executes; opens 17-second free-listen window (no prefix needed for follow-ups)
|
||||
- After 30 min of no commands → voice sleeps; full wake phrase required again
|
||||
- Mic paused during ElevenLabs TTS playback (`isSpeaking` guard) to prevent feedback loop
|
||||
- Auto-reload after 5 min idle is silent (no greeting speech)
|
||||
|
||||
**Planner system (2026-05-31):**
|
||||
- DB tables: `tasks` (id, title, notes, category, priority, status, due_date, due_time, completed_at) and `appointments` (id, title, description, category, start_at, end_at, location, all_day, reminder_min, alerted)
|
||||
- Voice commands: "add task [title]", "my tasks", "mark [x] done", "schedule [title] on [date]", "my calendar", "daily briefing"
|
||||
- Home page: small top-bar badge "N TASKS · N APPTS" when items due today (no panel added)
|
||||
- Admin CRUD at `/admin` under PLANNER section → TASKS and APPOINTMENTS tabs
|
||||
|
||||
**Agent system:** Agents phone home every 10s (heartbeat) / 30s (metrics) to `http://10.48.200.211` (direct LAN — no Cloudflare). Config at `/etc/jarvis-agent/config.json` or `/opt/jarvis-agent/config.json` on each Linux agent.
|
||||
Agent installer (one-liner for any Linux host): `curl -sk http://10.48.200.211/install-agent.sh | bash -s <hostname> <linux|homeassistant|proxmox>`
|
||||
DO server agent (jarvis-do) uses Tailscale: `jarvis_url: http://100.77.178.42`
|
||||
|
||||
**Agent file paths by host** (for manual updates — push to correct path then restart service):
|
||||
- Most Linux hosts: `/opt/jarvis-agent/jarvis-agent.py` · service: `systemctl restart jarvis-agent`
|
||||
- WireGuard CT (10.48.200.19, Alpine): `/opt/jarvis-agent/agent.py` · service: `rc-service jarvis-agent restart`
|
||||
- `public_html/agent/jarvis-agent.py` is the self-update URL — must be kept in sync with `agent/jarvis-agent.py` (both are tracked in git; auto-deploy keeps them in sync after 2026-06-17)
|
||||
|
||||
**Self-healing:** `/usr/local/bin/jarvis-watchdog.sh` runs every 5 min (root cron on DO). Restarts lsws/mysql/redis on DO if down. Log: `/usr/local/lsws/logs/watchdog.log` on DO.
|
||||
|
||||
**JARVIS DB:** `jarvis_db` on JARVIS VM localhost (MariaDB). User: `jarvis_user / J4rv1s_Pr0t0c0l_2026!`. phpMyAdmin at `/phpmyadmin` on JARVIS VM (myron / Joker1974!!!).
|
||||
Core tables: agent_commands, agent_metrics, alerts, api_cache, appointments, conversations, ha_entities, kb_facts, kb_intents, kb_ollama_models, kb_preferences, known_commands, metrics_history, network_devices, registered_agents, tasks, users. Arc Reactor adds: arc_jobs, guardian_events, guardian_config, agent_screenshots.
|
||||
|
||||
`kb_facts` schema: `(id, category, fact_key, fact_value, host, expires_at, updated_at)` — column is `category` not `fact_category`.
|
||||
|
||||
**Arc Reactor daemon:** Python service at `/opt/jarvis-arc/reactor.py` on JARVIS VM, port 7474, managed by `systemctl restart jarvis-arc`. Deploy source: `deploy/reactor.py` in the jarvis repo. After pushing to GitHub, auto-deploy pulls to `/var/www/jarvis/deploy/reactor.py` — then manually `cp /var/www/jarvis/deploy/reactor.py /opt/jarvis-arc/reactor.py && systemctl restart jarvis-arc`. Log: `/var/www/jarvis/logs/arc_reactor.log`.
|
||||
|
||||
**Arc Reactor AI routing:**
|
||||
| Feature | Provider | Model |
|
||||
|---------|----------|-------|
|
||||
| Guardian anomaly alerts | Groq | `llama-3.3-70b-versatile` |
|
||||
| SITREP | Groq | `llama-3.3-70b-versatile` |
|
||||
| Vision: text-only sysinfo snapshot | Groq | `llama-3.3-70b-versatile` |
|
||||
| Vision: actual screenshot image | Claude | `claude-opus-4-8-20251101` |
|
||||
| Email drafting, research, tool_loop | Claude | `claude-sonnet-4-6` |
|
||||
|
||||
`llm_call(messages, provider)` cascades: groq → ollama on failure. Pass `"groq"` or `"claude"` as provider.
|
||||
|
||||
**Groq API note:** Use model name `compound-beta-mini` directly — NOT `groq/compound-beta-mini` (that's OpenAI router syntax and will 404 on api.groq.com).
|
||||
|
||||
## Tom's Java Jive
|
||||
|
||||
PHP e-commerce site. DB: `toms_tjj_db / toms_tjj_user / +60wlPc+55e@gFq4`. Key quirks:
|
||||
- No `slug` column on products — URLs use `?id=product_id`
|
||||
- All tables must be `utf8mb4_unicode_ci` — mixed collation causes MySQL error 1267 on JOINs
|
||||
- `wallet_transactions.type` and `loyalty_transactions.type` have strict enums (see memory for values)
|
||||
|
||||
## MediaStack
|
||||
|
||||
Automated media server on PVE1 VM 113. All traffic routes through WireGuard VPN → DO, bypassing home ISP.
|
||||
|
||||
**SSH:** From PVE1: `ssh -o StrictHostKeyChecking=no -i /root/.ssh/id_rsa root@10.48.200.35`
|
||||
|
||||
**Services:**
|
||||
| Service | Port | Login |
|
||||
|---------|------|-------|
|
||||
| qBittorrent | :8080 | admin / Joker1974!!! |
|
||||
| Sonarr | :8989 | API key: `b43e04350a594846b4ee95261c29e9e0` |
|
||||
| Radarr | :7878 | API key: `53c4268360444feeae5f98c0cc24e0e3` |
|
||||
| Prowlarr | :9696 | API key: `9d0ce6c5660743b5bf1c7951efc62252` |
|
||||
|
||||
**Media paths:** downloads → `/media/downloads/complete` | movies → `/media/movies` | tv → `/media/tv`
|
||||
**Jellyfin NFS mounts** (VM 112, 10.48.200.33): `/mnt/mediastack/movies` and `/mnt/mediastack/tv`
|
||||
**WireGuard:** `wg0` IP `10.200.0.4` → CT110 (10.48.200.19:51821) → DO. Kill-switch active; LAN always allowed.
|
||||
**DNS:** FortiGate blocks port 53 outbound. PVE1 runs dnsmasq on :53 → 100.100.100.100. MediaStack uses `DNS=10.48.200.90`.
|
||||
**Indexer:** IPTorrents via Prowlarr (cookie auth). Prowlarr syncs to Sonarr + Radarr automatically.
|
||||
**GitHub:** `myronblair/mediastack` (private) — config files, systemd units, README with full setup notes.
|
||||
**JARVIS agent quirks:** needs `jarvis_url`, `registration_key` (`f846a9aaf7ce9a61742c63c87c4186052a71d2a580c65518`), `ssl_verify: false` in config.
|
||||
|
||||
## NovaCPX Panel
|
||||
|
||||
Custom web hosting control panel (PVE1 VM 120, 10.48.200.110). Root SSH: `sshpass -p 'Joker1974!!!' ssh -o StrictHostKeyChecking=no root@10.48.200.110` (direct LAN — use this, Tailscale 100.86.51.18 requires re-auth periodically).
|
||||
|
||||
**Public URLs (via NPM → FortiGate VIP port 443 → 10.48.200.201):**
|
||||
- Admin: `https://admin.novacpx.orbishosting.com` (→ port 8882) · `admin / Admin2026!` or `myron / Joker1974!!!`
|
||||
- Reseller: `https://reseller.novacpx.orbishosting.com` (→ port 8881)
|
||||
- User: `https://panel.novacpx.orbishosting.com` or `https://novacpx.orbishosting.com` (→ port 8880)
|
||||
- Webmail: port 8883 (Roundcube) — no public NPM proxy yet
|
||||
- `https://web.orbishosting.com` → port 80 (placeholder for a new hosted website)
|
||||
|
||||
**Ports:** 8880 (user) · 8881 (reseller) · 8882 (admin) · 8883 (Roundcube webmail)
|
||||
|
||||
**Paths:** Panel web root `/srv/novacpx/public/` · Git repo `/opt/novacpx-src/` · DB `/var/lib/novacpx/panel.db` (SQLite) · Config `/etc/novacpx/config.ini`
|
||||
|
||||
**Config notes:** `/etc/novacpx/config.ini` must have `server = nginx` (not apache) — VhostManager checks this to write the correct vhost format.
|
||||
|
||||
**⚠ After any restore from PBS backup:** config.ini reverts to `server = apache`. Always run: `sed -i "s/^server = apache/server = nginx/" /etc/novacpx/config.ini` after a restore. Also: PHP-FPM will fail to start if orphaned pool configs exist from pre-restore accounts — run the cleanup: `for f in /etc/php/8.3/fpm/pool.d/*.conf; do [[ "$f" == *"www.conf"* ]] && continue; u=$(basename "$f" .conf); id "$u" &>/dev/null || rm -f "$f"; done && systemctl start php8.3-fpm`. The `webacct` hosting account and its nginx vhost must be recreated after restore (Linux user survives but DB record and vhost are lost).
|
||||
|
||||
**GitHub:** `myronblair/novacpx` (private). Auto-deploy active: push to `main` (stable) or `beta` → webhook → VM pulls. GitHub Actions auto-bumps VERSION: main→PATCH, beta→-beta.N suffix. Current version: 1.0.40.
|
||||
|
||||
**Update channels:** `stable` tracks `origin/main`, `beta` tracks `origin/beta`. Set in Admin → Settings → Update Channel.
|
||||
|
||||
**Local clone:** `/tmp/novacpx/` on this machine. All edits go here first, then `git push origin main`. The deploy runner syncs `panel/` → `/srv/novacpx/public/` and `panel/lib/` → `/srv/novacpx/public/lib/`. For immediate changes use SCP to `root@10.48.200.110:/srv/novacpx/public/`.
|
||||
|
||||
**PHP-FPM:** Per-account pools in `/etc/php/8.3/fpm/pool.d/`. If php8.3-fpm fails to start, check for orphaned pool configs referencing deleted Linux users — remove them and `systemctl start php8.3-fpm`.
|
||||
|
||||
**JARVIS agent:** Installed, online. Agent ID: `novacpx_e3b07264`.
|
||||
|
||||
**SQLite quirk:** Never use MySQL syntax (ON DUPLICATE KEY, NOW(), DATE_ADD, etc.). DB.php has translate() layer but endpoints must also use SQLite syntax directly.
|
||||
|
||||
## Parker Slingshot Rentals
|
||||
|
||||
Admin portal at `/admin/index.php` uses HMAC-signed cookie auth (not PHP sessions — sessions were unreliable under LiteSpeed caching). Admin: `admin / Parker2026!`. DB: `epic_parkersling / epic_parkersling / Joker1974!!!`.
|
||||
|
||||
## FusionPBX / FreeSWITCH
|
||||
|
||||
Production at 134.209.72.226. Web: `https://fusion.orbishosting.com` (admin / fY7XP5swgtpbzrYLhkeVYkA4744). SIP profiles served via Lua XML handler — config changes require deleting `/var/cache/fusionpbx/FusionPBX.configuration.sofia.conf` to force reload. Extension 1000 (Yealink T48S at 10.48.200.43) registered on production server via port 5080 with `aggressive-nat-detection=true` to bypass FortiGate SIP ALG.
|
||||
|
||||
**SSH access:** Direct via Tailscale (preferred):
|
||||
```bash
|
||||
sshpass -p 'Joker1974!@#' ssh -o StrictHostKeyChecking=no root@100.74.46.120
|
||||
```
|
||||
Fallback if Tailscale down — relay through DO:
|
||||
```bash
|
||||
sshpass -p 'Gonewalk1974!@#' ssh -o StrictHostKeyChecking=no root@165.22.1.228 \
|
||||
'sshpass -p "Joker1974!@#" ssh -o StrictHostKeyChecking=no root@134.209.72.226 "command"'
|
||||
```
|
||||
|
||||
**Backup:** `myronblair/fusionpbx-config` — PostgreSQL dump (gzip, ~29MB) + FreeSWITCH configs + restore wizard. Weekly Sunday 5am. Launcher: `/usr/local/bin/fusionpbx-backup`.
|
||||
|
||||
## Proxmox
|
||||
|
||||
PVE1 at 10.48.200.90, PVE2 at 10.48.200.91. Root login direct. Run commands inside VMs via:
|
||||
```bash
|
||||
qm guest exec <VMID> -- bash -c 'command'
|
||||
```
|
||||
Proxmox `--nameserver` must be space-separated: `"8.8.8.8 1.1.1.1"` (comma causes netplan bug).
|
||||
|
||||
**Backup:** `myronblair/proxmox-config` — shared cluster configs (VM .conf, storage, HA, SDN) + per-node (network, cron, systemd, scripts). Weekly Sunday 3am. Launcher: `/usr/local/bin/proxmox-backup` on both nodes.
|
||||
|
||||
## PHP / OLS Runtime
|
||||
|
||||
CyberPanel uses `lsphp85`. Run PHP scripts directly with:
|
||||
```bash
|
||||
/usr/local/lsws/lsphp85/bin/lsphp /path/to/script.php
|
||||
```
|
||||
For PHP syntax checking use `php8.3 -l file.php` — lsphp segfaults on `-l` flag.
|
||||
When a PHP endpoint uses `ob_start()` + `header.php` pattern, add `ob_end_clean()` before any CSV/JSON response output.
|
||||
|
||||
**Cloudflare Rocket Loader:** JARVIS uses `data-cfasync="false"` on every `<script>` tag in `index.html` (including CDN scripts like face-api.js). One untagged script is enough to trigger Rocket Loader's bootstrap, which injects `mainScript.js` and causes `SyntaxError: Identifier 'mainScriptFlag' has already been declared`. `Cache-Control: no-store, no-cache, must-revalidate, no-transform` is set in `index.php` but tag every new script with `data-cfasync="false"` anyway.
|
||||
|
||||
**Cloudflare auto-deploy cache problem:** After pushing JS fixes, Cloudflare CDN serves stale cached files even on hard refresh. Bump the `?v=YYYYMMDD` query param on script tags in `index.html` to force a cache miss. Current version param: `?v=20260617b`.
|
||||
|
||||
**JS file structure (as of 2026-06-17):**
|
||||
- `assets/js/jarvis-effects.js` — canvas particle effects, sparklines
|
||||
- `assets/js/jarvis-overlays.js` — sleep overlay, network map canvas
|
||||
- `assets/js/jarvis-app.js` — globals, init, chat, voice, system/network/HA/alerts/weather panels
|
||||
- `assets/js/panels/jarvis-arc.js` — Arc Reactor, Intel Protocol, Comms Protocol, Guardian Mode
|
||||
- `assets/js/panels/jarvis-agents.js` — Missions, Directives, Memory, Clearance, Agents tab, Sites, Vision Protocol
|
||||
- `assets/js/panels/jarvis-assistant.js` — Chat History, Command Palette, Suggestions, Mobile switcher, Topology map
|
||||
|
||||
A SyntaxError in any panels/ file breaks only that group — other panels stay functional. `escHtml()` is defined in jarvis-arc.js (loads first) and is global to all subsequent files.
|
||||
|
||||
## GitHub Repos
|
||||
|
||||
| Repo | Site | DB Schema |
|
||||
|------|------|-----------|
|
||||
| myronblair/jarvis | jarvis.orbishosting.com | db/schema.sql (15 tables) |
|
||||
| myronblair/tomsjavajive | tomsjavajive.com | db/schema.sql (45 tables) |
|
||||
| myronblair/epictravelexpeditions | epictravelexpeditions.com | db/schema.sql (7 tables) |
|
||||
| myronblair/parkerslingshot | parkerslingshot.epictravelexpeditions.com | (no schema file — DB managed directly) |
|
||||
| myronblair/parkerslingshotrentals | parkerslingshotrentals.com | db/schema.sql (10 tables) |
|
||||
| myronblair/orbishosting | orbishosting.com | — |
|
||||
| myronblair/orbis-hosting-portal | orbis.orbishosting.com | — |
|
||||
| myronblair/tomtomgames | tomtomgames.com | db/schema.sql (22 tables) |
|
||||
| myronblair/infra | server configs | cron, systemd, agent configs |
|
||||
| myronblair/mediastack | MediaStack VM 113 | config/, systemd units, wg0.conf, README |
|
||||
| myronblair/do-server-config | DO server backup | scripts, systemd, WG, OLS vhosts, restore.sh |
|
||||
| myronblair/proxmox-config | PVE1+PVE2 backup | shared cluster configs + per-node, restore.sh |
|
||||
| myronblair/novacpx | admin.novacpx.orbishosting.com | db/schema.sql (SQLite, 19+ tables) |
|
||||
| myronblair/web-dashboard | web.orbishosting.com | — |
|
||||
| myronblair/fusionpbx-config | FusionPBX backup | PostgreSQL dump (gzip) + FS configs, restore.sh |
|
||||
|
||||
All repos are private. Each has `config/vhost/` with OLS vhost config. The jarvis repo also has `deploy/` (watchdog, deploy runner, systemd units) and `agent/jarvis-agent.py`.
|
||||
|
||||
## Split DNS (added 2026-06-21)
|
||||
|
||||
PVE1 dnsmasq (`/etc/dnsmasq.d/forwarder.conf`) has split DNS entries so all NPM-proxied domains resolve to `10.48.200.201` (NPM internal IP) for LAN clients — bypasses FortiGate hairpin NAT for HTTPS:
|
||||
|
||||
```
|
||||
address=/jarvis.orbishosting.com/10.48.200.201
|
||||
address=/hoa.orbishosting.com/10.48.200.201
|
||||
address=/novacpx.orbishosting.com/10.48.200.201
|
||||
address=/admin.novacpx.orbishosting.com/10.48.200.201
|
||||
address=/reseller.novacpx.orbishosting.com/10.48.200.201
|
||||
address=/panel.novacpx.orbishosting.com/10.48.200.201
|
||||
address=/web.orbishosting.com/10.48.200.201
|
||||
```
|
||||
|
||||
For any LAN device to use this: set DNS to `10.48.200.90` in Wi-Fi settings (or update FortiGate DHCP to push 10.48.200.90 as DNS for all clients).
|
||||
|
||||
## NovaCPX Panel (updated 2026-06-22)
|
||||
|
||||
Post-restore notes added — see `deploy/novacpx-post-restore.sh` which fixes config.ini, cleans pools, rebuilds webacct account. VM IDs changed after restore: MediaStack VM103, NPM VM105, Ollama VM106. Run script after any PBS restore.
|
||||
|
||||
**NovaCPX v1.0.54** — security fixes (CORS, open redirect, CSS injection, exception leakage), subdomains (#36), parked domains (#37), account settings page (#38), better default index (#39), post-restore script (#50), collapsible nav (#48).
|
||||
|
||||
**web.orbishosting.com** — Blair HQ dashboard with server-backed notes (notes.php → /home/webacct/notes.json). Password: myronblair@outlook.com / Joker1974!!!
|
||||
@@ -1,738 +0,0 @@
|
||||
# INFRASTRUCTURE REFERENCE — COMPLETE SYSTEM MAP
|
||||
**Last Updated:** 2026-06-14
|
||||
**Owner:** Myron Blair — myronblair@outlook.com
|
||||
|
||||
---
|
||||
|
||||
## TABLE OF CONTENTS
|
||||
1. [Network Overview](#1-network-overview)
|
||||
2. [Cloud Servers](#2-cloud-servers)
|
||||
3. [On-Premise — Proxmox Hypervisors](#3-on-premise--proxmox-hypervisors)
|
||||
4. [On-Premise — Virtual Machines](#4-on-premise--virtual-machines)
|
||||
5. [NAS Storage](#5-nas-storage)
|
||||
6. [Websites (all on DO)](#6-websites--all-on-do)
|
||||
7. [JARVIS AI System](#7-jarvis-ai-system)
|
||||
8. [Phone System (FusionPBX)](#8-phone-system-fusionpbx)
|
||||
9. [Networking & VPN](#9-networking--vpn)
|
||||
10. [Backup Systems](#10-backup-systems)
|
||||
11. [SSH Quick Reference](#11-ssh-quick-reference)
|
||||
12. [Critical Credentials Master List](#12-critical-credentials-master-list)
|
||||
|
||||
---
|
||||
|
||||
## 1. NETWORK OVERVIEW
|
||||
|
||||
```
|
||||
INTERNET
|
||||
│
|
||||
▼
|
||||
[Cloudflare CDN] ──────────────────────────────────────────────────────────────
|
||||
│ (proxied DNS for public sites)
|
||||
│
|
||||
├─► [DigitalOcean 165.22.1.228] — CyberPanel/OLS — All websites + JARVIS
|
||||
│
|
||||
└─► [FusionPBX 134.209.72.226] — FreeSWITCH PBX (SSH via DO relay)
|
||||
|
||||
HOME NETWORK (FortiGate router at 10.48.200.1)
|
||||
WAN: 97.154.109.245 (dynamic, DDNS: orbisne.fortiddns.com)
|
||||
│
|
||||
├─► PVE1 Proxmox 10.48.200.90 (primary hypervisor)
|
||||
│ ├── VM 101 10.48.200.97 Home Assistant
|
||||
│ ├── VM 112 10.48.200.33 Jellyfin
|
||||
│ ├── VM 113 10.48.200.35 MediaStack (Sonarr/Radarr/qBT/Prowlarr)
|
||||
│ ├── VM 118 10.48.200.18 Homebridge
|
||||
│ ├── VM 120 10.48.200.110 NovaCPX hosting panel
|
||||
│ ├── VM 210 10.48.200.95 Ollama (local LLM)
|
||||
│ └── CT110 10.48.200.19 WireGuard exit container
|
||||
│
|
||||
├─► PVE2 Proxmox 10.48.200.91 (secondary hypervisor)
|
||||
│ └── VM 302 10.48.200.99 NetworkBackup
|
||||
│
|
||||
├─► Synology NAS 10.48.200.249 — Media & backup storage
|
||||
├─► Yealink T48S 10.48.200.2 — Ext 1000 (Myron Blair, Desk)
|
||||
├─► Yealink T48S 10.48.200.43 — Ext 1001 (Tommy Ivy, Desk)
|
||||
├─► Yealink AX86R 10.48.200.65 — Ext 1002 (Myron Blair, WiFi Work)
|
||||
├─► Yealink T57W 10.48.200.3 — External SIP (United Mirror & Glass)
|
||||
├─► Yealink T57W 10.48.200.83 — Ext 1003 (Kitchen)
|
||||
└─► Yealink T57W 10.48.200.85 — Ext 1004 (Master Bedroom)
|
||||
|
||||
FortiGate Port Forwards:
|
||||
orbisne.fortiddns.com:8006 → PVE1:8006 (Proxmox web UI)
|
||||
orbisne.fortiddns.com:8123 → HA:8123 (Home Assistant)
|
||||
orbisne.fortiddns.com:22 → HA VM:22 (SSH — key only, unreliable)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. CLOUD SERVERS
|
||||
|
||||
### 2A. DigitalOcean — Main Server
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| **IP** | 165.22.1.228 |
|
||||
| **OS** | Ubuntu 22.04 LTS |
|
||||
| **Panel** | CyberPanel (OpenLiteSpeed) |
|
||||
| **SSH** | `ssh root@165.22.1.228` — password: `Gonewalk1974!@#` |
|
||||
| **Purpose** | All public websites + JARVIS AI + webhook deploy system |
|
||||
|
||||
**Key Paths:**
|
||||
- All sites: `/home/<domain>/public_html/`
|
||||
- JARVIS: `/home/jarvis.orbishosting.com/`
|
||||
- Deploy log: `/home/jarvis.orbishosting.com/logs/deploy.log`
|
||||
- Watchdog log: `/home/jarvis.orbishosting.com/logs/watchdog.log`
|
||||
- Infra repo: `/opt/infra`
|
||||
|
||||
**Services running:**
|
||||
- OpenLiteSpeed web server (`lsws`) — serves all 7 sites
|
||||
- MySQL 8 — all site databases on localhost
|
||||
- Redis — session/cache
|
||||
- PHP 8.5 (`lsphp85`) — runtime for all sites
|
||||
- Cron jobs: JARVIS deploy runner (every 1 min), facts collector (every 3 min), stats cache (every 5 min), watchdog (every 5 min)
|
||||
|
||||
**CyberPanel Web UI:** `https://165.22.1.228:8090`
|
||||
Login: `myron / Joker1974!!!`
|
||||
|
||||
**phpMyAdmin:** `https://165.22.1.228/phpmyadmin`
|
||||
Login: `myron / Joker1974!!!`
|
||||
|
||||
---
|
||||
|
||||
### 2B. FusionPBX / FreeSWITCH — PBX Server
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| **IP** | 134.209.72.226 |
|
||||
| **OS** | Debian (DigitalOcean droplet) |
|
||||
| **SSH** | Must relay via DO: `ssh root@165.22.1.228` → `ssh root@134.209.72.226` — password: `Joker1974!@#` |
|
||||
| **Direct SSH** | Only from: 107.178.2.130 / 97.154.109.245 |
|
||||
| **Purpose** | VoIP phone system — handles all inbound/outbound calls |
|
||||
|
||||
**Web UI:** `https://fusion.orbishosting.com`
|
||||
Login: `admin / fY7XP5swgtpbzrYLhkeVYkA4744`
|
||||
|
||||
**Database:** PostgreSQL
|
||||
User: `fusionpbx` / Password: `pSJaF9mUJqPr4Sj5mwJyRqvCCpc` / Host: 127.0.0.1
|
||||
|
||||
**SIP Trunk:** SignalWire
|
||||
DID: +1 (817) 764-5007
|
||||
Gateway: `signalwire` on external profile (port 5080, UDP)
|
||||
|
||||
**How calls flow:**
|
||||
```
|
||||
Caller → SignalWire SIP → FusionPBX:5080 → IVR (ext 900) → Ring extensions
|
||||
Outbound: Phone → FusionPBX:5080 → SignalWire → PSTN
|
||||
```
|
||||
|
||||
**SSH Relay Command:**
|
||||
```bash
|
||||
sshpass -p 'Gonewalk1974!@#' ssh -o StrictHostKeyChecking=no root@165.22.1.228 \
|
||||
'sshpass -p "Joker1974!@#" ssh -o StrictHostKeyChecking=no root@134.209.72.226 "COMMAND"'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. ON-PREMISE — PROXMOX HYPERVISORS
|
||||
|
||||
### PVE1 — Primary Hypervisor
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| **Local IP** | 10.48.200.90 |
|
||||
| **External** | orbisne.fortiddns.com (FortiGate DDNS — auto-updates on WAN IP change) |
|
||||
| **OS** | Proxmox VE 8.x |
|
||||
| **SSH** | `ssh root@orbisne.fortiddns.com` OR `ssh root@10.48.200.90` — password: `Joker1974!!!` |
|
||||
| **Web UI** | `https://orbisne.fortiddns.com:8006` — `root / Joker1974!!!` |
|
||||
| **Purpose** | Runs VMs 101, 112, 113, 118, 120, 210, CT110 |
|
||||
|
||||
**Useful commands:**
|
||||
```bash
|
||||
qm list # list all VMs
|
||||
qm start/stop/restart <VMID> # control VMs
|
||||
qm guest exec <VMID> -- bash -c "cmd" # run command inside VM (requires QEMU agent)
|
||||
```
|
||||
|
||||
**JARVIS API Token:** `root@pam!jarvis=c45b5feb-f9a9-445d-a626-14fbb959f78b`
|
||||
|
||||
---
|
||||
|
||||
### PVE2 — Secondary Hypervisor
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| **Local IP** | 10.48.200.91 |
|
||||
| **OS** | Proxmox VE 8.x |
|
||||
| **SSH** | `ssh root@10.48.200.91` — password: `Joker1974!!!` |
|
||||
| **Web UI** | `https://10.48.200.91:8006` — `root / Joker1974!!!` |
|
||||
| **Purpose** | Runs VM 302 (NetworkBackup); part of shared Proxmox cluster with PVE1 |
|
||||
|
||||
---
|
||||
|
||||
## 4. ON-PREMISE — VIRTUAL MACHINES
|
||||
|
||||
### VM 101 — Home Assistant (PVE1)
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| **IP** | 10.48.200.97 |
|
||||
| **OS** | Ubuntu + Home Assistant OS/Supervised |
|
||||
| **Web UI** | `http://orbisne.fortiddns.com:8123` — `myron / [HA password]` |
|
||||
| **SSH** | Via HA web terminal only (Settings → Add-ons → Advanced SSH & Web Terminal) |
|
||||
| **Purpose** | Smart home automation — 212 entities (lights, switches, scenes, sensors) |
|
||||
| **JARVIS Agent** | ID: `homeassistant_ha` — pushes entity states to JARVIS every 10s |
|
||||
|
||||
**JARVIS ↔ HA Integration:**
|
||||
- HA custom component at `/config/custom_components/jarvis_agent/`
|
||||
- Pushes all entity state changes to JARVIS `/api/agent/ha_state` (debounced 2s)
|
||||
- JARVIS admin toggles → queued in `agent_commands` table → HA executes natively
|
||||
- HA Long-lived Token (Jarvis2): `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiIzNmI0N2I1Njk5ZGQ0MTQ2ODMwZWFmYjZiYTQ1MjJkMSIsImlhdCI6MTc4MDIwMzU5NCwiZXhwIjoyMDk1NTYzNTk0fQ.sYRok-jRDlA4lFgWxLQELcEjkJNGQdprk6ZziLwLtXE`
|
||||
|
||||
---
|
||||
|
||||
### VM 112 — Jellyfin Media Server (PVE1)
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| **IP** | 10.48.200.33 |
|
||||
| **OS** | Ubuntu 22.04 LTS |
|
||||
| **SSH** | `ssh root@10.48.200.33` — password: `Joker1974!!!` (enabled 2026-06-14) |
|
||||
| **Web UI** | `http://10.48.200.33:8096` |
|
||||
| **Purpose** | Media streaming server — Movies and TV shows |
|
||||
| **JARVIS Agent** | Not yet installed |
|
||||
|
||||
**Media Libraries:**
|
||||
- Movies: `/mnt/mediastack/movies` — NFS from MediaStack (10.48.200.35:/media/movies)
|
||||
- TV: `/mnt/mediastack/tv` — NFS from MediaStack (10.48.200.35:/media/tv)
|
||||
|
||||
**NFS chain:** Jellyfin → MediaStack → Synology NAS (`/volume1/video/movies` and `/volume1/video/tv`)
|
||||
|
||||
**Admin token:** `7c0ccf78b91d4b5bafa607f585f24f2d`
|
||||
|
||||
**If library scan needed:**
|
||||
```bash
|
||||
curl -X POST "http://10.48.200.33:8096/Library/Refresh" \
|
||||
-H "X-Emby-Token: 7c0ccf78b91d4b5bafa607f585f24f2d"
|
||||
```
|
||||
|
||||
**If NFS stale after MediaStack changes:**
|
||||
```bash
|
||||
umount -l /mnt/mediastack/movies && umount -l /mnt/mediastack/tv
|
||||
mount /mnt/mediastack/movies && mount /mnt/mediastack/tv
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### VM 113 — MediaStack (PVE1)
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| **IP** | 10.48.200.35 |
|
||||
| **OS** | Ubuntu 24.04 LTS |
|
||||
| **SSH** | Via PVE1: `ssh -i /root/.ssh/id_rsa root@10.48.200.35` (no direct access from DO) |
|
||||
| **Purpose** | Automated media download pipeline + NFS server to Jellyfin |
|
||||
| **JARVIS Agent** | ID: `MediaStack_2c00b1b8` |
|
||||
|
||||
**Services:**
|
||||
| Service | Port | Login | API Key |
|
||||
|---------|------|-------|---------|
|
||||
| qBittorrent | :8080 | `admin / Joker1974!!!` | — |
|
||||
| Sonarr | :8989 | `admin / Joker1974!!!` | `b43e04350a594846b4ee95261c29e9e0` |
|
||||
| Radarr | :7878 | `admin / Joker1974!!!` | `53c4268360444feeae5f98c0cc24e0e3` |
|
||||
| Prowlarr | :9696 | `admin / Joker1974!!!` | `9d0ce6c5660743b5bf1c7951efc62252` |
|
||||
|
||||
**All services run as root** — required by Synology NFS ACL (only root can write).
|
||||
|
||||
**VPN:** NordVPN — `nordlynx` WireGuard interface — exit IP 181.214.226.188 (US Dallas)
|
||||
All download traffic exits via NordVPN. If downloads stall, check: `ip rule show` for rules 32764/32765.
|
||||
|
||||
**Media Flow:**
|
||||
```
|
||||
IPTorrents (Prowlarr) → Sonarr/Radarr search → qBittorrent download
|
||||
→ /mnt/nas/video/downloads (NAS)
|
||||
→ Sonarr/Radarr import → /mnt/nas/video/tv or /mnt/nas/video/movies (NAS)
|
||||
→ NFS → Jellyfin /mnt/mediastack/movies or /mnt/mediastack/tv
|
||||
```
|
||||
|
||||
**Indexer:** IPTorrents via Prowlarr cookie auth
|
||||
Cookie: `uid=2237410; pass=JzLP2niTWxBJAZIU3yvtLbJzD55kdLeB`
|
||||
(Expires — if search fails, log into iptorrents.com, copy uid+pass cookies)
|
||||
|
||||
**If Radarr/Sonarr shows "0 active indexers":**
|
||||
```bash
|
||||
systemctl stop radarr
|
||||
sqlite3 /var/lib/radarr/radarr.db "DELETE FROM IndexerStatus WHERE ProviderId=1;"
|
||||
systemctl start radarr
|
||||
```
|
||||
|
||||
**SSH from DO:**
|
||||
```bash
|
||||
sshpass -p 'Joker1974!!!' ssh -o StrictHostKeyChecking=no root@10.48.200.90 \
|
||||
'ssh -o StrictHostKeyChecking=no -i /root/.ssh/id_rsa root@10.48.200.35 "COMMAND"'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### VM 118 — Homebridge (PVE1)
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| **IP** | 10.48.200.18 |
|
||||
| **OS** | Linux |
|
||||
| **SSH** | `ssh myron@10.48.200.18` — password: `Joker1974!` |
|
||||
| **Purpose** | Apple HomeKit bridge — exposes non-HomeKit devices to Apple Home app |
|
||||
| **JARVIS Agent** | ID: `homebridge_b57cbaea` |
|
||||
|
||||
---
|
||||
|
||||
### VM 120 — NovaCPX Hosting Panel (PVE1)
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| **IP** | 10.48.200.110 |
|
||||
| **OS** | Ubuntu 24.04 LTS |
|
||||
| **SSH** | `ssh root@10.48.200.110` — password: `Joker1974!!!` (direct, no PVE hop) |
|
||||
| **Purpose** | Custom web hosting control panel (cPanel alternative), v1.0.27 |
|
||||
| **JARVIS Agent** | ID: `novacpx_e3b07264` |
|
||||
|
||||
**Ports:**
|
||||
| Port | Panel |
|
||||
|------|-------|
|
||||
| :8880 | User panel |
|
||||
| :8881 | Reseller panel |
|
||||
| :8882 | Admin panel |
|
||||
| :8883 | Roundcube webmail |
|
||||
|
||||
**Admin:** `https://10.48.200.110:8882` — `admin / Admin2026!`
|
||||
**phpMyAdmin:** `http://10.48.200.110/phpmyadmin`
|
||||
|
||||
**File Paths:**
|
||||
- Web root: `/srv/novacpx/public/`
|
||||
- DB (SQLite): `/var/lib/novacpx/panel.db`
|
||||
- Config: `/etc/novacpx/config.ini`
|
||||
- Git repo: `/opt/novacpx-src/`
|
||||
- GitHub: `myronblair/novacpx` (auto-deploy on push to `main`)
|
||||
|
||||
---
|
||||
|
||||
### VM 210 — Ollama Local LLM (PVE1)
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| **IP** | 10.48.200.95 |
|
||||
| **OS** | Ubuntu (cloud image) |
|
||||
| **SSH** | `ssh myron@10.48.200.95` — password: `Joker1974!` (then `sudo`) |
|
||||
| **Purpose** | Local AI inference — runs llama3.2 model for JARVIS Tier 1 chat |
|
||||
| **API** | `http://10.48.200.95:11434` (Ollama REST API) |
|
||||
| **JARVIS Agent** | ID: `ollama-ai_ubuntu` |
|
||||
|
||||
**JARVIS uses this as Tier 1 AI** — if Ollama is down, falls back to Groq (cloud).
|
||||
|
||||
---
|
||||
|
||||
### VM 302 — NetworkBackup (PVE2)
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| **IP** | 10.48.200.99 |
|
||||
| **OS** | Ubuntu/Linux |
|
||||
| **SSH** | `ssh myron@10.48.200.99` — password: `Joker1974!` (then `sudo`) |
|
||||
| **Purpose** | Network backup storage / backup operations |
|
||||
| **JARVIS Agent** | ID: `networkbackup_NetworkB` |
|
||||
|
||||
---
|
||||
|
||||
### CT110 — WireGuard Exit Container (PVE1)
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| **IP** | 10.48.200.19 / 10.48.200.67 |
|
||||
| **Purpose** | Legacy WireGuard exit tunnel to DO (10.200.0.4 via wg-exit) — currently NOT used by MediaStack/Jellyfin |
|
||||
| **Note** | MediaStack uses NordVPN directly; Jellyfin uses wg1 peer on MediaStack for NFS only |
|
||||
|
||||
---
|
||||
|
||||
## 5. NAS STORAGE
|
||||
|
||||
### Synology NAS
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| **IP** | 10.48.200.249 |
|
||||
| **Login** | `nas / Joker1974!!!` |
|
||||
| **DSM Web UI** | `http://10.48.200.249:5000` |
|
||||
| **Purpose** | Primary media and download storage |
|
||||
|
||||
**NFS Share:** `/volume1/video` (exported to MediaStack only)
|
||||
|
||||
**Directory structure:**
|
||||
```
|
||||
/volume1/video/
|
||||
movies/ ← Radarr imports here; NFS-exported to Jellyfin via MediaStack
|
||||
tv/ ← Sonarr imports here; NFS-exported to Jellyfin via MediaStack
|
||||
downloads/ ← qBittorrent downloads here (temp)
|
||||
incomplete/ ← in-progress torrents
|
||||
```
|
||||
|
||||
**Important:** Synology NFS ACL only allows root to write. All services on MediaStack run as root.
|
||||
|
||||
---
|
||||
|
||||
## 6. WEBSITES (ALL ON DO)
|
||||
|
||||
All sites are at `/home/<domain>/public_html/` on DO (165.22.1.228).
|
||||
**Auto-deploy:** Push to `main` on GitHub → webhook → server pulls in ~1 min.
|
||||
**GitHub PAT:** `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` (expires ~2026-08-20)
|
||||
|
||||
---
|
||||
|
||||
### jarvis.orbishosting.com — JARVIS AI Dashboard
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| **URL** | https://jarvis.orbishosting.com |
|
||||
| **Path** | `/home/jarvis.orbishosting.com/` |
|
||||
| **GitHub** | `myronblair/jarvis` |
|
||||
| **Login** | `myron / Joker1974!!!` |
|
||||
| **Purpose** | Iron Man-style AI home dashboard with voice control, smart home, media, planner |
|
||||
|
||||
See Section 7 for full JARVIS details.
|
||||
|
||||
---
|
||||
|
||||
### tomsjavajive.com — Tom's Java Jive
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| **URL** | https://tomsjavajive.com |
|
||||
| **Path** | `/home/tomsjavajive.com/public_html/` |
|
||||
| **GitHub** | `myronblair/tomsjavajive` |
|
||||
| **Purpose** | Coffee shop e-commerce — products, orders, loyalty, wallet, reviews |
|
||||
| **Admin URL** | `https://tomsjavajive.com/admin/` |
|
||||
| **Admin Login** | `admin@tomsjavajive.com / Joker1974!!!` OR `myronblair@outlook.com / Joker1974!!!` |
|
||||
| **DB** | `toms_tjj_db / toms_tjj_user / +60wlPc+55e@gFq4` |
|
||||
| **Email** | CyberMail API key: `sk_live_7f9b0f9a29f6de31a0d229d4af75d56b094ad724fc58a57d` |
|
||||
| **Email From** | `noreply@tomsjavajive.com` / `Toms Java Jive` (set in DB settings table) |
|
||||
|
||||
---
|
||||
|
||||
### epictravelexpeditions.com — Epic Travel Expeditions
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| **URL** | https://epictravelexpeditions.com |
|
||||
| **Path** | `/home/epictravelexpeditions.com/public_html/` |
|
||||
| **GitHub** | `myronblair/epictravelexpeditions` |
|
||||
| **Purpose** | Travel booking / expeditions website |
|
||||
| **DB** | `epic_travel_db` (see `api/config.php`) |
|
||||
|
||||
---
|
||||
|
||||
### parkerslingshot.epictravelexpeditions.com — Parker Slingshot (OLD)
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| **URL** | https://parkerslingshot.epictravelexpeditions.com |
|
||||
| **Path** | `/home/epictravelexpeditions.com/parkerslingshot/` |
|
||||
| **GitHub** | `myronblair/parkerslingshot` |
|
||||
| **Purpose** | Old slingshot rental site (superseded by parkerslingshotrentals.com) |
|
||||
|
||||
---
|
||||
|
||||
### parkerslingshotrentals.com — Parker Slingshot Rentals (LIVE)
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| **URL** | https://www.parkerslingshotrentals.com |
|
||||
| **Path** | `/home/parkerslingshotrentals.com/public_html/` |
|
||||
| **GitHub** | `myronblair/parkerslingshotrentals` |
|
||||
| **Purpose** | Polaris Slingshot rental — bookings, e-signature waiver, admin management |
|
||||
| **Admin** | `/admin/index.php` — `admin / Parker2026!` |
|
||||
| **DB** | `park_slingshot / park_slingshotuser / 4@rxg*8kovxCr7w6` |
|
||||
| **Square** | Production token: `EAAAl3FsAu_2ri8kZE_ENEyi2T_C8HXXm5XQFY6Lbnd8SX6FqYp8J_upUeXNYh7v` |
|
||||
|
||||
---
|
||||
|
||||
### orbishosting.com — Orbis Hosting (Landing Page)
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| **URL** | https://orbishosting.com |
|
||||
| **Path** | `/home/orbishosting.com/public_html/` |
|
||||
| **GitHub** | `myronblair/orbishosting` |
|
||||
| **Purpose** | Public landing page for Orbis Hosting brand |
|
||||
|
||||
---
|
||||
|
||||
### orbis.orbishosting.com — Orbis Hosting Portal
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| **URL** | https://orbis.orbishosting.com |
|
||||
| **Path** | `/home/orbis.orbishosting.com/public_html/` |
|
||||
| **GitHub** | `myronblair/orbis-hosting-portal` |
|
||||
| **Purpose** | Customer-facing hosting portal |
|
||||
|
||||
---
|
||||
|
||||
### tomtomgames.com — TomTom Games
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| **URL** | https://tomtomgames.com |
|
||||
| **Path** | `/home/tomtomgames.com/public_html/` |
|
||||
| **GitHub** | `myronblair/tomtomgames` |
|
||||
| **Purpose** | Gaming website |
|
||||
| **DB** | `tomtom_games_db` (see config) |
|
||||
| **Email** | CyberMail API key: `sk_live_7f9b...` |
|
||||
|
||||
---
|
||||
|
||||
## 7. JARVIS AI SYSTEM
|
||||
|
||||
**URL:** https://jarvis.orbishosting.com
|
||||
**Files:** `/home/jarvis.orbishosting.com/` on DO
|
||||
**DB:** `jarvis_db` — `jarvis_user / J4rv1s_Pr0t0c0l_2026!`
|
||||
**Login:** `myron / Joker1974!!!`
|
||||
**Admin portal:** https://jarvis.orbishosting.com/admin
|
||||
|
||||
### Architecture (end-to-end)
|
||||
|
||||
```
|
||||
Voice (browser mic)
|
||||
→ SpeechRecognition API
|
||||
→ Wake phrase: "wake up JARVIS" / "daddy's home"
|
||||
→ "JARVIS [command]" triggers action
|
||||
→ /api/chat.php (4-tier AI)
|
||||
Tier 0.7: KB intents / planner (tasks, appointments)
|
||||
Tier 1: Knowledge Base (MySQL)
|
||||
Tier 1.5: Ollama (10.48.200.95:11434, llama3.2) — local LLM
|
||||
Tier 2: Groq (cloud, model: compound-beta-mini)
|
||||
Tier 3: Claude API (Anthropic, fallback)
|
||||
→ ElevenLabs TTS → browser speaker
|
||||
```
|
||||
|
||||
### Deploy Pipeline
|
||||
```
|
||||
Code edit → git push → GitHub webhook → /webhook.php (HMAC verified)
|
||||
→ /tmp/jarvis-deploy-queue.txt → /usr/local/bin/jarvis-deploy.sh (cron 1min)
|
||||
→ git pull + PHP syntax check → deploy or auto-revert
|
||||
```
|
||||
Webhook secret: `4c8805f0285214ff0a0602b5880270b935f36a896946c7f1`
|
||||
|
||||
### Agent System
|
||||
Agents installed on all servers — phone home every 10s (heartbeat) / 30s (metrics).
|
||||
Registration key: `f846a9aaf7ce9a61742c63c87c4186052a71d2a580c65518`
|
||||
Install command: `curl -sk https://jarvis.orbishosting.com/install-agent.sh | bash -s <hostname> <linux|proxmox>`
|
||||
|
||||
### Self-Healing Watchdog
|
||||
`/usr/local/bin/jarvis-watchdog.sh` — runs every 5 min (root cron on DO)
|
||||
Restarts: lsws, mysql, redis if down
|
||||
Restarts offline Proxmox VM agents via `qm guest exec`
|
||||
|
||||
### Cron Jobs (DO server)
|
||||
| Schedule | Script | Purpose |
|
||||
|----------|--------|---------|
|
||||
| Every 1 min | `jarvis-deploy.sh` | Process GitHub deploy queue |
|
||||
| Every 3 min | `facts_collector.php` | Collect agent metrics, KB facts, site health |
|
||||
| Every 5 min | `stats_cache.php` | Weather, news, Proxmox stats refresh |
|
||||
| Every 5 min | `jarvis-watchdog.sh` | Self-healing: restart dead services |
|
||||
|
||||
---
|
||||
|
||||
## 8. PHONE SYSTEM (FUSIONPBX)
|
||||
|
||||
### Extensions
|
||||
| Ext | Name | Phone | IP | SIP Password |
|
||||
|-----|------|-------|----|-------------|
|
||||
| 1000 | Myron Blair — Desk | Yealink T48S | 10.48.200.2 | `Xk9mPw3nQv7rLs2t` |
|
||||
| 1001 | Tommy Ivy — Desk | Yealink T48S | 10.48.200.43 | `Tv8xNm4pWq6rZs3k` |
|
||||
| 1002 | Myron Blair — WiFi Work | Yealink AX86R | 10.48.200.65 | `yXHaJTwa8rj?$GkrVFQB` |
|
||||
| 1003 | Kitchen | Yealink T57W | 10.48.200.83 | — |
|
||||
| 1004 | Master Bedroom | Yealink T57W | 10.48.200.85 | — |
|
||||
| 1010 | Parker County Slingshot | Virtual (voicemail only) | — | — |
|
||||
| 1011 | Epic Travel Expeditions | Virtual (voicemail only) | — | — |
|
||||
| 1012 | Tom's Java Jive | Virtual (voicemail only) | — | — |
|
||||
| 900 | IVR | — | — | (auto-attendant) |
|
||||
|
||||
**Phone SIP Settings (all phones):**
|
||||
- Server: `134.209.72.226`
|
||||
- Port: `5080`
|
||||
- Transport: UDP
|
||||
|
||||
**Provisioning URL:** `https://fusion.orbishosting.com/app/provision/`
|
||||
(Username: `provision-master`, Password: `Joker1974!!!`)
|
||||
|
||||
### Call Flow
|
||||
```
|
||||
Inbound (+18177645007)
|
||||
→ SignalWire → FusionPBX:5080 (UDP)
|
||||
→ signalwire-inbound dialplan (catch-all ^.*$)
|
||||
→ IVR ext 900 (ivr_menu_16k.wav)
|
||||
→ Routes to extensions 1000/1001/1002/1003/1004
|
||||
|
||||
Outbound
|
||||
→ Phone → FusionPBX:5080
|
||||
→ signalwire gateway → SignalWire → PSTN
|
||||
```
|
||||
|
||||
### FreeSWITCH CLI Commands
|
||||
```bash
|
||||
fs_cli -x "sofia status profile external reg" # check registrations
|
||||
fs_cli -x "sofia xmlstatus gateway" # check SignalWire gateway
|
||||
fs_cli -x "reloadxml" # reload config (safe)
|
||||
fs_cli -x "reloadacl" # reload ACL (safe)
|
||||
# AVOID: sofia profile external restart (drops all phone registrations)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. NETWORKING & VPN
|
||||
|
||||
### FortiGate Firewall
|
||||
- WAN IP: 97.154.109.245 (dynamic)
|
||||
- DDNS: `orbisne.fortiddns.com` (FortiGate auto-updates on IP change)
|
||||
- Blocks: outbound port 53 (DNS) — MediaStack uses PVE1 dnsmasq (10.48.200.90) as resolver → 100.100.100.100
|
||||
|
||||
**Port Forwards:**
|
||||
| External Port | Internal Destination | Purpose |
|
||||
|--------------|---------------------|---------|
|
||||
| :8006 | PVE1:8006 | Proxmox web UI |
|
||||
| :8123 | HA VM:8123 | Home Assistant |
|
||||
| :22 | HA VM:22 | HA SSH (unreliable) |
|
||||
|
||||
### WireGuard — Jellyfin ↔ MediaStack
|
||||
- MediaStack runs WireGuard server on `wg1` (port 51820, subnet 10.200.0.1/24)
|
||||
- Jellyfin peer: 10.200.0.3 (active handshake)
|
||||
- Used for NFS media file access ONLY — not internet VPN
|
||||
|
||||
### NordVPN — MediaStack Internet Traffic
|
||||
- Interface: `nordlynx` on MediaStack
|
||||
- Exit IP: 181.214.226.188 (US Dallas)
|
||||
- Policy routing: table 205 (all traffic via nordlynx), managed by `nordvpn-routing.service`
|
||||
- Required for IPTorrents access (blocks non-VPN IPs)
|
||||
|
||||
---
|
||||
|
||||
## 10. BACKUP SYSTEMS
|
||||
|
||||
### DO Server Backup
|
||||
- **Repo:** `myronblair/do-server-config`
|
||||
- **Schedule:** Weekly, Sunday 4am
|
||||
- **Launcher:** `/usr/local/bin/do-server-backup` on DO
|
||||
- **Covers:** Scripts, systemd units, WireGuard, OLS vhosts, cron, MySQL credentials
|
||||
- **Restore:** 8-phase wizard in `restore.sh`
|
||||
- **DB backups:** `jarvis-backup.sh` runs daily (separate)
|
||||
|
||||
### Proxmox Config Backup
|
||||
- **Repo:** `myronblair/proxmox-config`
|
||||
- **Schedule:** Weekly, Sunday 3am (both PVE1 and PVE2)
|
||||
- **Launcher:** `/usr/local/bin/proxmox-backup` on each node
|
||||
- **Covers:** VM .conf files, network, cron, systemd, scripts
|
||||
- **VM disks:** Covered by Proxmox Backup Server (PBS)
|
||||
|
||||
### FusionPBX Backup
|
||||
- **Repo:** `myronblair/fusionpbx-config`
|
||||
- **Schedule:** Weekly, Sunday 5am
|
||||
- **Launcher:** `/usr/local/bin/fusionpbx-backup`
|
||||
- **Covers:** PostgreSQL dump (gzip, ~29MB) + FreeSWITCH configs
|
||||
- **Restore:** 10-phase wizard in `restore.sh`
|
||||
|
||||
---
|
||||
|
||||
## 11. SSH QUICK REFERENCE
|
||||
|
||||
```bash
|
||||
# DO (main web server)
|
||||
sshpass -p 'Gonewalk1974!@#' ssh -o StrictHostKeyChecking=no root@165.22.1.228
|
||||
|
||||
# FusionPBX (must relay via DO)
|
||||
sshpass -p 'Gonewalk1974!@#' ssh root@165.22.1.228 \
|
||||
'sshpass -p "Joker1974!@#" ssh root@134.209.72.226 "CMD"'
|
||||
|
||||
# PVE1 (direct or via DDNS)
|
||||
sshpass -p 'Joker1974!!!' ssh -o StrictHostKeyChecking=no root@orbisne.fortiddns.com
|
||||
sshpass -p 'Joker1974!!!' ssh -o StrictHostKeyChecking=no root@10.48.200.90
|
||||
|
||||
# PVE2
|
||||
sshpass -p 'Joker1974!!!' ssh -o StrictHostKeyChecking=no root@10.48.200.91
|
||||
|
||||
# MediaStack (via PVE1)
|
||||
sshpass -p 'Joker1974!!!' ssh root@10.48.200.90 \
|
||||
'ssh -i /root/.ssh/id_rsa root@10.48.200.35 "CMD"'
|
||||
|
||||
# Jellyfin (direct, password enabled 2026-06-14)
|
||||
sshpass -p 'Joker1974!!!' ssh -o StrictHostKeyChecking=no root@10.48.200.33
|
||||
|
||||
# NovaCPX (direct)
|
||||
sshpass -p 'Joker1974!!!' ssh -o StrictHostKeyChecking=no root@10.48.200.110
|
||||
|
||||
# Ollama / Homebridge / NetworkBackup (myron user, then sudo)
|
||||
sshpass -p 'Joker1974!' ssh myron@10.48.200.95 # Ollama
|
||||
sshpass -p 'Joker1974!' ssh myron@10.48.200.18 # Homebridge
|
||||
sshpass -p 'Joker1974!' ssh myron@10.48.200.99 # NetworkBackup
|
||||
|
||||
# Run command inside VM via Proxmox (requires QEMU agent installed)
|
||||
sshpass -p 'Joker1974!!!' ssh root@10.48.200.90 \
|
||||
'qm guest exec 210 -- bash -c "CMD"'
|
||||
```
|
||||
|
||||
**Password fallback order:** `Joker1974!@#` → `Joker1974!!!` → `Joker1974!`
|
||||
|
||||
---
|
||||
|
||||
## 12. CRITICAL CREDENTIALS MASTER LIST
|
||||
|
||||
### SSH / Root Access
|
||||
| System | User | Password | Notes |
|
||||
|--------|------|----------|-------|
|
||||
| DO (165.22.1.228) | root | `Gonewalk1974!@#` | Main web server |
|
||||
| FusionPBX (134.209.72.226) | root | `Joker1974!@#` | Via DO relay |
|
||||
| PVE1 (10.48.200.90) | root | `Joker1974!!!` | Also via DDNS |
|
||||
| PVE2 (10.48.200.91) | root | `Joker1974!!!` | |
|
||||
| MediaStack (10.48.200.35) | root | key only | Via PVE1 (`/root/.ssh/id_rsa`) |
|
||||
| Jellyfin (10.48.200.33) | root | `Joker1974!!!` | Enabled 2026-06-14 |
|
||||
| NovaCPX (10.48.200.110) | root | `Joker1974!!!` | Direct SSH works |
|
||||
| Ollama / Homebridge / Backup VMs | myron | `Joker1974!` | Then sudo |
|
||||
|
||||
### Web Panels & Admin
|
||||
| System | URL | User | Password |
|
||||
|--------|-----|------|----------|
|
||||
| CyberPanel | https://165.22.1.228:8090 | myron | `Joker1974!!!` |
|
||||
| phpMyAdmin (DO) | https://165.22.1.228/phpmyadmin | myron | `Joker1974!!!` |
|
||||
| Proxmox PVE1 | https://orbisne.fortiddns.com:8006 | root | `Joker1974!!!` |
|
||||
| Proxmox PVE2 | https://10.48.200.91:8006 | root | `Joker1974!!!` |
|
||||
| JARVIS | https://jarvis.orbishosting.com | myron | `Joker1974!!!` |
|
||||
| JARVIS Admin | https://jarvis.orbishosting.com/admin | myron | `Joker1974!!!` |
|
||||
| FusionPBX | https://fusion.orbishosting.com | admin | `fY7XP5swgtpbzrYLhkeVYkA4744` |
|
||||
| Home Assistant | http://orbisne.fortiddns.com:8123 | myron | (HA password) |
|
||||
| NovaCPX Admin | https://10.48.200.110:8882 | admin | `Admin2026!` |
|
||||
| Jellyfin | http://10.48.200.33:8096 | — | token: `7c0ccf78b91d4b5bafa607f585f24f2d` |
|
||||
| qBittorrent | http://10.48.200.35:8080 | admin | `Joker1974!!!` |
|
||||
| Sonarr | http://10.48.200.35:8989 | admin | `Joker1974!!!` |
|
||||
| Radarr | http://10.48.200.35:7878 | admin | `Joker1974!!!` |
|
||||
| Prowlarr | http://10.48.200.35:9696 | admin | `Joker1974!!!` |
|
||||
| Synology NAS | http://10.48.200.249:5000 | nas | `Joker1974!!!` |
|
||||
| Parker Slingshot Admin | https://parkerslingshotrentals.com/admin | admin | `Parker2026!` |
|
||||
| TJJ Admin | https://tomsjavajive.com/admin | `admin@tomsjavajive.com` OR `myronblair@outlook.com` | `Joker1974!!!` |
|
||||
|
||||
### Databases
|
||||
| Site | DB Name | DB User | DB Password |
|
||||
|------|---------|---------|-------------|
|
||||
| JARVIS | `jarvis_db` | `jarvis_user` | `J4rv1s_Pr0t0c0l_2026!` |
|
||||
| Tom's Java Jive | `toms_tjj_db` | `toms_tjj_user` | `+60wlPc+55e@gFq4` |
|
||||
| Parker Slingshot Rentals | `park_slingshot` | `park_slingshotuser` | `4@rxg*8kovxCr7w6` |
|
||||
| Epic Travel | `epic_travel_db` | (see config.php) | (see config.php) |
|
||||
| Epic/Parker Slingshot | `epic_parkersling` | `epic_parkersling` | `Joker1974!!!` |
|
||||
| NovaCPX | SQLite: `/var/lib/novacpx/panel.db` | — | — |
|
||||
| FusionPBX | PostgreSQL | `fusionpbx` | `pSJaF9mUJqPr4Sj5mwJyRqvCCpc` |
|
||||
| MySQL root (DO) | — | root | `b71e5c1a8c7457541b9c1db822de37adfa271926a38b6c20` |
|
||||
|
||||
### API Keys
|
||||
| Service | Key |
|
||||
|---------|-----|
|
||||
| GitHub PAT | `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` (exp ~2026-08-20) |
|
||||
| JARVIS Agent Registration | `f846a9aaf7ce9a61742c63c87c4186052a71d2a580c65518` |
|
||||
| Proxmox API Token | `root@pam!jarvis=c45b5feb-f9a9-445d-a626-14fbb959f78b` |
|
||||
| HA Long-lived Token | `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiIzNmI0N2I1Njk5ZGQ0MTQ2ODMwZWFmYjZiYTQ1MjJkMSIsImlhdCI6MTc4MDIwMzU5NCwiZXhwIjoyMDk1NTYzNTk0fQ.sYRok-jRDlA4lFgWxLQELcEjkJNGQdprk6ZziLwLtXE` |
|
||||
| Sonarr API | `b43e04350a594846b4ee95261c29e9e0` |
|
||||
| Radarr API | `53c4268360444feeae5f98c0cc24e0e3` |
|
||||
| Prowlarr API | `9d0ce6c5660743b5bf1c7951efc62252` |
|
||||
| Jellyfin Admin Token | `7c0ccf78b91d4b5bafa607f585f24f2d` |
|
||||
| Square (Parker) Production | `EAAAl3FsAu_2ri8kZE_ENEyi2T_C8HXXm5XQFY6Lbnd8SX6FqYp8J_upUeXNYh7v` |
|
||||
| Square App ID (Parker) | `sq0idp-YSM7BU9IVyOWSzpeP-0nzQ` |
|
||||
| Webhook HMAC Secret | `4c8805f0285214ff0a0602b5880270b935f36a896946c7f1` |
|
||||
|
||||
### SIP / Phone
|
||||
| Extension | Name | SIP Password |
|
||||
|-----------|------|-------------|
|
||||
| 1000 | Myron Blair — Desk (10.48.200.2) | `Xk9mPw3nQv7rLs2t` |
|
||||
| 1001 | Tommy Ivy — Desk (10.48.200.43) | `Tv8xNm4pWq6rZs3k` |
|
||||
| 1002 | Myron Blair — WiFi Work (10.48.200.65) | `yXHaJTwa8rj?$GkrVFQB` |
|
||||
| 1003 | Kitchen (10.48.200.83) | — |
|
||||
| 1004 | Master Bedroom (10.48.200.85) | — |
|
||||
| 1010 | Parker County Slingshot (voicemail only) | — |
|
||||
| 1011 | Epic Travel Expeditions (voicemail only) | — |
|
||||
| 1012 | Tom's Java Jive (voicemail only) | — |
|
||||
|
||||
---
|
||||
|
||||
*This document contains sensitive credentials. Store securely and do not share.*
|
||||
@@ -18,31 +18,3 @@ cp agent/config.json /opt/jarvis-agent/config.json
|
||||
systemctl enable jarvis-agent
|
||||
systemctl start jarvis-agent
|
||||
```
|
||||
|
||||
## Cloudflare Rocket Loader — IMPORTANT
|
||||
|
||||
JARVIS (and all sites) sit behind Cloudflare with **Rocket Loader enabled**.
|
||||
Rocket Loader does two things that break JavaScript login forms:
|
||||
|
||||
1. Changes `<script>` tag `type` to a fake value, deferring execution.
|
||||
2. Injects `if (!window.__cfRLUnblockHandlers) return false;` into **every**
|
||||
`onclick=`, `onkeydown=`, and other inline HTML event attributes,
|
||||
blocking them until Rocket Loader finishes loading.
|
||||
|
||||
### Rules for any page with JavaScript that must run immediately:
|
||||
|
||||
- Add `data-cfasync="false"` to ALL `<script>` tags.
|
||||
- **Never use inline event handler attributes** (`onclick=`, `onkeydown=`, etc.)
|
||||
on HTML elements — Rocket Loader will block them.
|
||||
- Attach all event listeners via `addEventListener()` in JavaScript.
|
||||
- Use `XMLHttpRequest` instead of `fetch()` for auth calls (more compatible).
|
||||
- Put scripts **after** their target DOM elements (end of body), not in `<head>`,
|
||||
so the elements exist when the script runs without needing DOMContentLoaded.
|
||||
|
||||
### Current login implementation (jarvis repo: public_html/login.html)
|
||||
|
||||
Standalone `/login.html` page handles all auth. `index.html` redirects to
|
||||
`/login.html` if no `jarvis_token` in sessionStorage.
|
||||
- Script is at end of body, after elements, with `data-cfasync="false"`
|
||||
- All handlers attached via `addEventListener` — no inline attributes
|
||||
- Uses XHR (not fetch) to POST to `/api/auth`
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
# Memory Index
|
||||
|
||||
- [FusionPBX Setup](project_fusionpbx.md) — DO 134.209.72.226; SignalWire SIP trunk (transport=udp required); ext 1000/1001/1002; IVR 900; signalwire-inbound catch-all dialplan; providers ACL includes FortiGate 97.154.109.245
|
||||
- [Yealink API](feedback_yealink_api.md) — PKCS1v15+AES-CBC login; token required for writes; account-register page; correct field names (server1, AccountRegisterName, etc.)
|
||||
- [Yealink Phone Status](project_yealink_phones.md) — Ext 1000 (Myron/.2) + ext 1001 (Tommy/.43) registered; provisioning URL set; BLF buttons in progress
|
||||
- [JARVIS System](project_jarvis.md) — Iron Man AI on DO 165.22.1.228; /admin portal; PVE1 nmap auto-scan; agents on all nodes; Proxmox cluster API via FortiGate DDNS:8006
|
||||
- [JARVIS HA Integration](project_jarvis_ha_integration.md) — Two-way HA↔JARVIS via custom component; 212 entities live; webhook fix; HA SSH via web terminal only
|
||||
- [Web Server](project_webserver.md) — CyberPanel/OpenLiteSpeed DO at 165.22.1.228 (root/Gonewalk1974!@#); tomsjavajive.com + 5 other sites; IP changed from 206.189.229.53
|
||||
- [GitHub Workflow](feedback_github_workflow.md) — All sites have private GitHub repos (myronblair/*); commit+push to GitHub THEN deploy to server for every change; repo map + gitignored creds inside
|
||||
- [Tom's Java Jive](project_tomsjavajive.md) — DB creds, admin portal map, schema quirks (no slug col, enum values, collation), bugs fixed 2026-05-22
|
||||
- [TJJ Email](project_tomsjavajive_email.md) — CyberMail (CyberPersons); API key in config.php as CYBERMAIL_API_KEY; mgmt at platform.cyberpersons.com
|
||||
- [TomTomGames Email](project_tomtomgames_email.md) — CyberMail API key sk_live_7f9b...; mailer.php uses cybermailSend(); sendgridSend() aliased; verified 2026-06-06
|
||||
- [SMTP Credentials (all sites)](project_smtp_credentials.md) — All 5 sites on CyberMail, same API key, all verified 2026-06-06; TJJ reads from settings DB table; TJJ email_cybermail bad key fixed
|
||||
- [PHP ob_start Export Fix](feedback_php_ob_export.md) — ob_end_clean() required before CSV/JSON responses when ob_start()+header.php pattern is used
|
||||
- [MySQL Collation](feedback_mysql_collation.md) — Always utf8mb4_unicode_ci; mixing with general_ci breaks JOINs (error 1267)
|
||||
- [Parker Slingshot Rentals](project_parkerslingshotrentals.md) — parkerslingshotrentals.com booking site; HMAC cookie admin auth (not sessions); Square creds stored; 6-step booking flow
|
||||
- [SSH Passwords](feedback_ssh_passwords.md) — Try Joker1974!@# → Joker1974!!! → Joker1974!; root direct on PVE; myron/Joker1974!!! + sudo on VMs
|
||||
- [Yealink Provisioning](feedback_yealink_provisioning.md) — overwrite_mode=1 required; BLF type=16 in FusionPBX; auto_linekeys=0; factory reset clears URL; git safe.directory for www-data
|
||||
- [Cloudflare Rocket Loader](feedback_cloudflare_rocket_loader.md) — breaks inline onclick= handlers and defers scripts; fix with Cache-Control: no-transform in PHP
|
||||
- [MediaStack VM](project_mediastack.md) — VM 113 on PVE1; all services admin/Joker1974!!!; NordVPN (not CT110); IPTorrents uid=2237410 cookie; download dirs must be qbittorrent-owned; NFS to Jellyfin
|
||||
- [NovaCPX Panel](project_novacpx.md) — VM 120 @ 10.48.200.110 (direct SSH works); v1.0.27; admin/Admin2026!; stable/beta channels; JARVIS agent online; 140-app Docker catalog
|
||||
- [NovaCPX Dev Tools](project_novacpx_tools.md) — Direct SSH/SCP to 10.48.200.110 (PVE1 hop broken); API session-cookie auth pattern; key VM paths
|
||||
- [Proxmox Config Backup](project_proxmox_backup.md) — myronblair/proxmox-config; weekly cron on PVE1+PVE2; restore.sh wizard; VM configs + network + scripts + systemd; PBS covers VM disks
|
||||
- [DO Server Backup](project_do_backup.md) — myronblair/do-server-config; weekly cron Sunday 4am; scripts/systemd/WG/OLS vhosts/mysql; restore.sh 8-phase wizard; DBs covered by jarvis-backup.sh daily
|
||||
- [FusionPBX Backup](project_fusionpbx_backup.md) — myronblair/fusionpbx-config; weekly cron Sunday 5am; PostgreSQL dump (gzip, 29MB) IS the config; restore.sh 10-phase wizard; SSH via DO relay only
|
||||
- [Context Management](feedback_context_management.md) — Warn before context limit; finish/commit current task cleanly; don't start large features if context is already long
|
||||
- [JARVIS TODO](project_jarvis_todo.md) — Master TODO: Workers page, Phase 2/3 modularization, agent fixes, install-agent.sh, Arc Reactor systemd, Jellyfin, Claude credits
|
||||
- [Cryptex Safe](user_cryptex.md) — Physical 3D-printed Cryptex key: NEBYMJ (Creality K2 Pro)
|
||||
- [Infrastructure TODO](project_infra_todo.md) — Open items: CT110 read-only fs, wg-clients auto-start, MediaStack guest agent, Tailscale PVE1 re-auth, stale ARP watch
|
||||
@@ -0,0 +1,27 @@
|
||||
---
|
||||
name: feedback-cloudflare-rocket-loader
|
||||
description: Cloudflare Rocket Loader breaks inline JS event handlers and defers scripts — how to avoid and fix
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: feedback
|
||||
originSessionId: dfc59a24-a903-4f91-8c76-331af763d3e6
|
||||
---
|
||||
|
||||
Cloudflare Rocket Loader is enabled on all orbishosting.com sites and causes two distinct problems:
|
||||
|
||||
1. **Script deferral** — changes `<script>` tag type to a fake value, preventing execution until Rocket Loader finishes loading. Breaks any JS that must run on page load.
|
||||
|
||||
2. **Inline handler blocking** — injects `if (!window.__cfRLUnblockHandlers) return false;` into every `onclick=`, `onkeydown=`, etc. HTML attribute. Even if the function is defined, the click is blocked.
|
||||
|
||||
**Why:** These are Cloudflare "performance optimizations" that can't be disabled without Cloudflare dashboard access (no API keys stored).
|
||||
|
||||
**How to apply:** For any page with JavaScript that must work:
|
||||
- Add `Cache-Control: no-transform, no-store` response header — this tells Cloudflare not to modify the response. Use `ini_set('session.cache_limiter', '')` before session_start() or the session headers will override it.
|
||||
- Never use inline event handler attributes (`onclick=`, `onkeydown=`). Always use `addEventListener()`.
|
||||
- The main JARVIS app (jarvis.orbishosting.com) is now served via `index.php` which adds this header automatically.
|
||||
|
||||
**Current solution (2026-06-01):**
|
||||
- Login: `login.php` (pure PHP form POST, no JS) with `Cache-Control: no-transform`
|
||||
- Entry point: `index.php` checks PHP session, redirects to `login.php` if not auth'd
|
||||
- App served with token injected as `var __jarvisToken` global + CSS forcing loginScreen hidden
|
||||
- See [[project-jarvis]] for full architecture
|
||||
@@ -0,0 +1,14 @@
|
||||
---
|
||||
name: feedback-context-management
|
||||
description: User wants to be warned before context limit and have tasks cleanly finished before running out
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: feedback
|
||||
originSessionId: c454fc50-f93d-4ddd-b9f3-f3f442e89fb9
|
||||
---
|
||||
|
||||
Warn the user proactively when the conversation is getting long and approaching the context limit — before a task is left in a broken/hanging state. Finish or save the current task cleanly, then let the user know the session needs to continue fresh.
|
||||
|
||||
**Why:** User wants nothing left hanging when a session ends.
|
||||
|
||||
**How to apply:** When making edits mid-feature, always commit and deploy what's done so far. Before starting something large when context is already long, warn the user and offer to continue in a new session rather than starting something that won't finish.
|
||||
@@ -0,0 +1,43 @@
|
||||
---
|
||||
name: feedback-github-workflow
|
||||
description: Standing rule — all website and Jarvis changes must be committed to GitHub then deployed to the server
|
||||
metadata:
|
||||
type: feedback
|
||||
originSessionId: 002fe81e-7e03-414d-b842-1f94f1390a22
|
||||
---
|
||||
|
||||
For every code change to any website or Jarvis: commit to GitHub first, then deploy to the live server. Never make changes directly without a git commit.
|
||||
|
||||
**Why:** User explicitly requested this as a standing workflow on 2026-05-22.
|
||||
|
||||
**How to apply:** After editing any file:
|
||||
1. `git add -A && git commit -m "description"` in the site root
|
||||
2. `git push origin main`
|
||||
3. Then SCP/SSH the changed files to the live server (or git pull if pull-based deploy is set up)
|
||||
|
||||
## Repo Map
|
||||
|
||||
| Site / Project | Server | Path | GitHub Repo |
|
||||
|---|---|---|---|
|
||||
| tomsjavajive.com | 165.22.1.228 | /home/tomsjavajive.com/public_html | myronblair/tomsjavajive |
|
||||
| epictravelexpeditions.com | 165.22.1.228 | /home/epictravelexpeditions.com/public_html | myronblair/epictravelexpeditions |
|
||||
| orbishosting.com | 165.22.1.228 | /home/orbishosting.com/public_html | myronblair/orbishosting |
|
||||
| orbis.orbishosting.com | 165.22.1.228 | /home/orbis.orbishosting.com/public_html | myronblair/orbis-hosting-portal |
|
||||
| parkerslingshotrentals.com | 165.22.1.228 | /home/parkerslingshotrentals.com/public_html | myronblair/parkerslingshotrentals |
|
||||
| tomtomgames.com | 165.22.1.228 | /home/tomtomgames.com/public_html | myronblair/tomtomgames |
|
||||
| JARVIS | 10.48.200.84 | /var/www/jarvis.orbishosting.com | myronblair/jarvis |
|
||||
|
||||
## Gitignored Credentials (never in GitHub)
|
||||
- tomsjavajive: `config/database.php`
|
||||
- epictravelexpeditions: `api/config.php`
|
||||
- jarvis: `api/config.php`
|
||||
|
||||
## Git on Servers
|
||||
- DO server (165.22.1.228): SSH as root, git runs as root, safe.directory set for all /home/*/public_html paths
|
||||
- Jarvis (10.48.200.84): SSH as myron, git requires `sudo` + explicit GIT_DIR/GIT_WORK_TREE env vars
|
||||
|
||||
## PAT
|
||||
- **Token:** `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`
|
||||
- Embedded in all remote URLs on both servers (DO + Jarvis)
|
||||
- Expires ~90 days from 2026-05-22 (around 2026-08-20)
|
||||
- Rotate via: `git remote set-url origin https://myronblair:NEW_TOKEN@github.com/myronblair/REPO.git`
|
||||
@@ -0,0 +1,17 @@
|
||||
---
|
||||
name: feedback-mysql-collation
|
||||
description: Always use utf8mb4_unicode_ci for new tables — mixing collations breaks JOINs with MySQL error 1267
|
||||
metadata:
|
||||
type: feedback
|
||||
originSessionId: 002fe81e-7e03-414d-b842-1f94f1390a22
|
||||
---
|
||||
|
||||
All new tables in these MySQL databases must use `utf8mb4_unicode_ci` collation. Never use `utf8mb4_general_ci` or leave it at the server default without checking.
|
||||
|
||||
**Why:** Mixing `utf8mb4_general_ci` and `utf8mb4_unicode_ci` in a JOIN causes MySQL error 1267: "Illegal mix of collations." This silently broke wishlist.php and reviews.php on tomsjavajive.com — pages returned 500 with no visible error until a diagnostic script revealed the PDO exception. Fixed by running `ALTER TABLE x CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci` on the mismatched tables.
|
||||
|
||||
**How to apply:**
|
||||
- When writing `CREATE TABLE`, always include `COLLATE utf8mb4_unicode_ci`
|
||||
- When checking an existing table: `SHOW CREATE TABLE tablename\G` — look at the COLLATE line
|
||||
- Fix a bad table: `ALTER TABLE tablename CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci`
|
||||
- Affected tables on tomsjavajive.com that were wrong (now fixed): wishlist, loyalty_transactions, loyalty_tiers, product_types, loyalty_settings
|
||||
@@ -0,0 +1,34 @@
|
||||
---
|
||||
name: feedback-php-ob-export
|
||||
description: PHP file export/AJAX handlers that run after ob_start()+header.php must call ob_end_clean() before sending headers
|
||||
metadata:
|
||||
type: feedback
|
||||
originSessionId: 002fe81e-7e03-414d-b842-1f94f1390a22
|
||||
---
|
||||
|
||||
When a PHP admin page uses the pattern `ob_start()` + `require_once header.php` at the top, any handler that sends a non-HTML response (CSV download, JSON AJAX, redirect) must call `ob_end_clean()` before setting Content-Type headers and outputting content.
|
||||
|
||||
**Why:** `ob_start()` buffers everything. `require_once header.php` fills the buffer with a full HTML page before any request-type checks run. Without `ob_end_clean()`, the browser receives the full HTML page *followed by* the CSV/JSON body — the export appears to download the entire rendered page instead of the file.
|
||||
|
||||
**How to apply:** Any time I add a file export or AJAX handler to an admin page that uses this pattern:
|
||||
|
||||
```php
|
||||
// ✅ correct
|
||||
if (isset($_GET['export'])) {
|
||||
ob_end_clean(); // discard buffered HTML from header.php
|
||||
header('Content-Type: text/csv; charset=UTF-8');
|
||||
header('Content-Disposition: attachment; filename="export.csv"');
|
||||
// ... output CSV ...
|
||||
exit;
|
||||
}
|
||||
|
||||
// ✅ correct for AJAX
|
||||
if ($action === 'inline_edit') {
|
||||
ob_end_clean();
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['ok' => true]);
|
||||
exit;
|
||||
}
|
||||
```
|
||||
|
||||
First discovered and fixed in `admin/import-export.php` on tomsjavajive.com (2026-05-22).
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
name: feedback-ssh-passwords
|
||||
description: SSH password rotation order for home lab servers; escalation path from myron to root
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: feedback
|
||||
originSessionId: f0b18417-cc26-4fdf-87ec-7b2d69b02c44
|
||||
---
|
||||
|
||||
Try passwords in this order when SSH password auth is needed for home lab hosts:
|
||||
|
||||
1. `Joker1974!@#`
|
||||
2. `Joker1974!!!`
|
||||
3. `Joker1974!`
|
||||
|
||||
Root login is allowed on Proxmox hosts (PVE1 10.48.200.90, PVE2 10.48.200.91) directly.
|
||||
On some VMs, login as `myron / Joker1974!!!` then `sudo su` or `sudo -i` to escalate to root.
|
||||
|
||||
**Why:** User confirmed these are the rotating passwords used across the home lab.
|
||||
|
||||
**How to apply:** Before trying key auth failures or giving up on SSH, cycle through these three variants. [[project-jarvis]]
|
||||
@@ -0,0 +1,62 @@
|
||||
---
|
||||
name: feedback-yealink-api
|
||||
description: "Yealink T48S web API quirks — RSA/AES login, token-gated writes, correct page/field names for SIP account config"
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: feedback
|
||||
originSessionId: 002fe81e-7e03-414d-b842-1f94f1390a22
|
||||
---
|
||||
|
||||
Yealink T48S web API (firmware 66.86.0.15) — complete working flow:
|
||||
|
||||
## Login (PKCS1v15 + AES-CBC hybrid)
|
||||
|
||||
1. GET `/servlet?m=mod_listener&p=login&q=loginForm` — fetch RSA public key (`g_rsa_n`, `g_rsa_e`) and initial `JSESSIONID` cookie
|
||||
2. Generate random 16-byte AES key + IV; encrypt plaintext `{rand};{JSESSIONID};{password}` with AES-128-CBC zero-padding (NOT PKCS7), base64 result → `pwd`
|
||||
3. RSA-encrypt AES key hex string and IV hex string separately with PKCS1v15 → `rsakey`, `rsaiv`
|
||||
- **Critical**: encrypt the ASCII hex string (e.g. `"a1b2c3..."`) not raw bytes — Yealink's `pkcs1pad2` uses `charCodeAt` per character
|
||||
- **Critical**: AES key/IV hex must be **lowercase**
|
||||
4. POST `username=admin&pwd=<b64>&rsakey=<hex>&rsaiv=<hex>` to `/servlet?m=mod_listener&p=login&q=login` with `JSESSIONID` cookie
|
||||
5. Returns `{"authstatus":"done"}` on success; cookie jar updates with new JSESSIONID
|
||||
|
||||
**Lockout**: 3 failed attempts → ~10 min lockout (polling the login page also resets the timer — stop ALL requests to the phone during lockout)
|
||||
|
||||
## SIP Account Config (account-register page)
|
||||
|
||||
- **Page**: `account-register` (NOT `account-basic` — that page only has anonymous-call advanced fields)
|
||||
- **Load**: GET `/servlet?m=mod_data&p=account-register&q=load`
|
||||
- **Write**: POST `/servlet?m=mod_data&p=account-register&q=write&token=<g_strToken>`
|
||||
- Token is **required** — without it returns 403; with it returns 200 + empty `_RES_INFO_` div (that empty response IS success)
|
||||
- Token comes from `g_strToken` variable in the loaded page HTML
|
||||
|
||||
**Correct field names** for SIP account 1:
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| `var_accountID` | `0` (0-indexed) |
|
||||
| `AccountEnable` | `1` |
|
||||
| `AccountLabel` | display label |
|
||||
| `AccountDisplayName` | caller ID name |
|
||||
| `AccountRegisterName` | SIP auth username (e.g. `1000`) |
|
||||
| `AccountUserName` | SIP username (e.g. `1000`) |
|
||||
| `server1` | SIP server IP (e.g. `134.209.72.226`) |
|
||||
| `port1` | SIP port (e.g. `5080`) |
|
||||
| `Transport1` | `0` = UDP |
|
||||
| `Expires1` | registration expiry seconds |
|
||||
| `AccountPassword` | AES-encrypted password (same AES key/IV as login) |
|
||||
|
||||
**Password encryption for writes**: Same AES-CBC approach as login — encrypt plaintext password bytes with zero-padding, base64 result → `AccountPassword`. Send same `rsakey` + `rsaiv` alongside.
|
||||
|
||||
## Autoprovision Trigger
|
||||
|
||||
GET `/servlet?m=mod_data&p=settings-autop&q=autopnow&token=<g_strToken>` → returns `{"ret":"ok","data":"3"}` on success
|
||||
|
||||
## Reboot
|
||||
|
||||
POST `/servlet?m=mod_data&p=settings-upgrade&q=write&type=reboot`
|
||||
|
||||
## SIP Registration Status
|
||||
|
||||
Load page contains JS: `ccStatus = g_json.ParseJSON(...)` with JSON like `{"Account1":"1000@134.209.72.226:2"}` — status codes: `0`=disabled, `1`=registered, `2`=registering, `3`=failed
|
||||
|
||||
**Why:** All this was reverse-engineered from Yealink's `commonjs.js` (`pkcs1pad2` function) across multiple sessions after many failed approaches (textbook RSA, wrong plaintext format, wrong field names, missing token).
|
||||
**How to apply:** Use this as the reference any time we script Yealink T48S configuration via its web API. Scripts are saved at `/tmp/yfix_server.py` and `/tmp/ydiag_write.py` (on PVE1) as working examples.
|
||||
@@ -0,0 +1,59 @@
|
||||
---
|
||||
name: feedback-yealink-provisioning
|
||||
description: Yealink T48S + FusionPBX provisioning — complete root causes and fixes for BLF buttons not showing
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: feedback
|
||||
originSessionId: f0b18417-cc26-4fdf-87ec-7b2d69b02c44
|
||||
---
|
||||
|
||||
**THE ROOT CAUSE OF BLF BUTTONS NOT SHOWING (confirmed fix 2026-05-29):**
|
||||
|
||||
Yealink phones ignore DSS key settings in `.boot` files — they only apply them from `.cfg` files. FusionPBX's nginx rewrite for `{mac}.boot` stripped the `file=` param, so the phone received the full 122KB config as a `.boot` file and silently ignored all linekey settings.
|
||||
|
||||
**Fix:** Two-part:
|
||||
1. Create `{$mac}.boot` template in `/var/www/fusionpbx/resources/templates/provision/yealink/t48s/` containing:
|
||||
```
|
||||
#!version:1.0.0.1
|
||||
include:config "y000000000065.cfg"
|
||||
include:config "{$mac}.cfg"
|
||||
overwrite_mode = 1
|
||||
```
|
||||
2. Change nginx rewrite in `/etc/nginx/sites-enabled/fusionpbx`:
|
||||
- OLD: `rewrite "^.*/provision/([A-Fa-f0-9]{12})(\.boot)$" /app/provision/index.php?mac=$1;`
|
||||
- NEW: `rewrite "^.*/provision/([A-Fa-f0-9]{12})(\.boot)$" /app/provision/index.php?mac=$1&file=%7b%24mac%7d.boot;`
|
||||
|
||||
This makes `{mac}.boot` return a 164-byte boot file with includes. Phone then fetches `{mac}.cfg` as a `.cfg` file, applies ALL settings including DSS/BLF keys.
|
||||
|
||||
**After provisioning on firmware 66.86.0.15:** Phone requires a physical power cycle to register and show BLF buttons. `Update Now` downloads the config but doesn't auto-reboot on this firmware.
|
||||
|
||||
---
|
||||
|
||||
**Other critical lessons:**
|
||||
|
||||
**1. overwrite_mode = 1 is required** — default is 0, phone ignores all config changes after first provision.
|
||||
- Set in `{$mac}.boot` template (and all `y000000000000.boot` templates)
|
||||
|
||||
**2. Factory reset clears the provisioning URL** — must re-enter manually:
|
||||
- Menu > Settings > Advanced (password: admin) > Auto Provision
|
||||
- Server URL: `https://fusion.orbishosting.com/app/provision/`
|
||||
- Username: `provision-master`, Password: `Joker1974!!!`
|
||||
- Then: Update Now → power cycle
|
||||
|
||||
**3. BLF type = 16 in FusionPBX** (confirmed). NOT type=2 (Speed Dial), NOT type=3.
|
||||
- FusionPBX template uses type=16 for BLF (requires `pickup_value` field)
|
||||
- `{if type == "1" || type == "16"}` → pickup_value in `{$mac}.cfg` template confirms this
|
||||
|
||||
**4. features.auto_linekeys.enable = 0** in `y000000000065.cfg` template — prevents phone firmware from auto-assigning SIP account over BLF keys.
|
||||
|
||||
**5. External sofia profile: manage-presence = passive** (not true).
|
||||
- Internal profile: manage-presence = true (already correct in FusionPBX default)
|
||||
- External profile must be passive so BLF SUBSCRIBEs from phones on port 5080 delegate to internal
|
||||
- Fix: UPDATE v_sip_profile_settings SET value='passive' WHERE profile=external AND name='manage-presence'
|
||||
- Then delete `/var/cache/fusionpbx/FusionPBX.configuration.sofia.conf` and reload sofia
|
||||
|
||||
**6. git safe.directory for www-data** — Fix: `git config --system --add safe.directory /var/www/fusionpbx`
|
||||
|
||||
**7. After manual provision (Update Now):** phone may not register until power cycled, especially firmware 66.86.0.15.
|
||||
|
||||
**How to apply:** When BLF buttons don't appear despite config downloading correctly, check: (1) is {mac}.boot returning 164 bytes or 122KB? (2) is external sofia profile passive? (3) did the phone power cycle after provisioning?
|
||||
@@ -0,0 +1,47 @@
|
||||
---
|
||||
name: do-server-backup
|
||||
description: "DO server (165.22.1.228) config backup to GitHub — weekly cron, restore wizard, full rebuild guide"
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: project
|
||||
originSessionId: c454fc50-f93d-4ddd-b9f3-f3f442e89fb9
|
||||
---
|
||||
|
||||
GitHub repo `myronblair/do-server-config` (private) — all scripts, systemd units, WireGuard, OLS vhosts, cron, MySQL creds.
|
||||
|
||||
**Why:** So the DO server (orbis) can be fully rebuilt after a droplet failure in ~90 minutes.
|
||||
|
||||
## What's Backed Up
|
||||
- `scripts/` — jarvis-deploy.sh, jarvis-watchdog.sh, jarvis-backup.sh, jarvis-agent.py, ttg-backup.sh
|
||||
- `systemd/` — jarvis-agent.service, fastapi_ssh_server.service
|
||||
- `wireguard/` — wg0.conf (includes private keys — private repo)
|
||||
- `network/` — netplan 50-cloud-init.yaml, hosts, hostname
|
||||
- `cron/` — root_custom (JARVIS lines), root_full (everything)
|
||||
- `ols-vhosts/` — all 8 site OLS vhost configs
|
||||
- `mysql/` — /root/.my.cnf, database list
|
||||
- `infra/` — snapshot of /opt/infra/
|
||||
- `smtp-docs/` — /opt/smtp-for-websites/ docs
|
||||
|
||||
## Schedule
|
||||
Weekly Sunday 4am: `0 4 * * 0 /usr/local/bin/do-server-backup >> /var/log/do-server-backup.log 2>&1`
|
||||
|
||||
## Manual trigger
|
||||
`/usr/local/bin/do-server-backup` on DO server
|
||||
|
||||
## What's NOT backed up
|
||||
- Website files (all in GitHub repos)
|
||||
- Databases (jarvis-backup.sh daily → /var/backups/jarvis/, 7-day retention)
|
||||
- SSL certs (re-issue via CyberPanel)
|
||||
- Gitignored configs (api/config.php files — recreate manually from examples)
|
||||
- CyberPanel itself (reinstall script: sh <(curl https://cyberpanel.net/install.sh))
|
||||
|
||||
## Restore flow
|
||||
1. New Ubuntu 24.04 droplet
|
||||
2. `apt install git && git clone https://<PAT>@github.com/myronblair/do-server-config.git /opt/do-server-config`
|
||||
3. `bash /opt/do-server-config/restore.sh` (8-phase interactive wizard)
|
||||
4. Install CyberPanel, create sites, pull GitHub repos
|
||||
5. Restore DBs from jarvis-backup.sh archive
|
||||
6. Recreate gitignored config files
|
||||
|
||||
## MySQL root password
|
||||
Z9Of4NVs6ji74x (also in mysql/my.cnf in repo)
|
||||
@@ -0,0 +1,103 @@
|
||||
---
|
||||
name: fusionpbx-freeswitch-setup
|
||||
description: FusionPBX on DO 134.209.72.226; Yealink T48S ext 1000/1001/1002; SignalWire SIP trunk; inbound routing; provisioning
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: project
|
||||
originSessionId: 84bfb029-16a6-4be4-aca0-308e896c1219
|
||||
---
|
||||
|
||||
FusionPBX (FreeSWITCH) PBX on DigitalOcean 134.209.72.226.
|
||||
**SSH:** root / Joker1974!@# (must proxy via 165.22.1.228 — direct SSH blocked)
|
||||
**FusionPBX web:** https://fusion.orbishosting.com (admin / fY7XP5swgtpbzrYLhkeVYkA4744)
|
||||
**DB:** fusionpbx user / pSJaF9mUJqPr4Sj5mwJyRqvCCpc, host 127.0.0.1
|
||||
**Domain:** `134.209.72.226` (uuid: de6d867b-54d2-43f4-b1ed-8fd66803acac) — all devices under this domain
|
||||
|
||||
## SIP Profile
|
||||
Only `external` profile running (port 5080, UDP+TCP). No internal profile.
|
||||
Phones register on external profile — non-standard but working.
|
||||
Key settings (2026-06-02):
|
||||
- `auth-calls = true`
|
||||
- `apply-inbound-acl = providers`
|
||||
- `proxy-media = true` (fixes NAT audio issues)
|
||||
- `aggressive-nat-detection = true`, `NDLB-force-rport = true`
|
||||
- `minimum-session-expires = 300`
|
||||
|
||||
**Warning:** Every `sofia profile external restart` drops all phone registrations. Prefer `reloadxml` + `reloadacl` where possible.
|
||||
|
||||
## Extensions
|
||||
- 1000: Myron Blair — Yealink T48S at 10.48.200.2, MAC 80:5e:c0:35:04:77, password `Xk9mPw3nQv7rLs2t`
|
||||
- 1001: Tommy Ivy — Yealink T48S at 10.48.200.43, password `Tv8xNm4pWq6rZs3k`
|
||||
- 1002: Home — Yealink AX86R at 10.48.200.65, password `yXHaJTwa8rj?$GkrVFQB`
|
||||
|
||||
**1001 short registration:** Registers with ~120s expiry. Causes brief unavailability during re-reg. Fix properly by setting registration expiry to 3600s on the phone itself.
|
||||
|
||||
## Phones NAT
|
||||
All phones come from FortiGate NAT IP **97.247.128.120** (updated 2026-06-17, was 97.154.109.245). This IP is in the `providers` ACL — required for both inbound call routing AND outbound calls from phones.
|
||||
|
||||
## providers ACL (v_access_controls uuid: 47da18a2-6085-4740-a316-6d1bce8240b5)
|
||||
Contains: all SignalWire IP ranges (172.110.216.0/21 + individual IPs) + 97.247.128.120 (FortiGate/phones).
|
||||
|
||||
## SignalWire Gateway
|
||||
- FusionPBX gateway name: `signalwire`, profile: `external`
|
||||
- Username: `fusion@orbis-hosting-0364f5f67488.sip.signalwire.com`
|
||||
- `register = false` (IP-based auth), state NOREG / status UP = correct
|
||||
|
||||
**CRITICAL — transport=udp required:**
|
||||
SignalWire SIP Gateway External URI MUST be:
|
||||
`sip:18177645007@134.209.72.226:5080;transport=udp`
|
||||
Without `;transport=udp`, SignalWire uses TCP from 152.42.144.114 / 159.65.244.171 which FreeSWITCH silently drops (no log entry, no response). Only UDP from 172.110.223.179 works. 20/22 calls failed before this fix.
|
||||
|
||||
## Inbound Call Routing (DID: +18177645007)
|
||||
SignalWire sends caller's number as Request-URI destination (not the DID) even with SIP Gateway configured. Single-mode Lua handler can't match this to v_destinations → falls to not-found.
|
||||
|
||||
**Fix:** Global catch-all dialplan:
|
||||
- Name: `signalwire-inbound`, context: `public`, order: 100, domain_uuid: NULL
|
||||
- Expression: `^.*$` → `transfer 900 XML 134.209.72.226`
|
||||
- If deleted, calls fall through to not-found (404)
|
||||
|
||||
Public dialplan order:
|
||||
1. caller-details (10, global, continue=true)
|
||||
2. signalwire-inbound (100, global) → IVR 900
|
||||
3. 18177645007 (100, domain-specific, expression ^(.*)$) → linked via v_destinations
|
||||
4. not-found (999, global)
|
||||
|
||||
## IVR
|
||||
- Extension 900: active IVR, greeting: `ivr_menu_16k.wav`
|
||||
- Extension 800: old FIFO queue (disabled)
|
||||
- IVR dialplan in domain context 134.209.72.226, name "IVR", matches `^900$`
|
||||
|
||||
## Yealink Provisioning
|
||||
URL: `https://fusion.orbishosting.com/app/provision/`
|
||||
Boot file: `{mac}.boot`, model cfg: `y000000000065.cfg`, device cfg: `{mac}.cfg`
|
||||
Yealink web login uses textbook RSA (no padding): encrypt password with g_rsa_n/g_rsa_e from login page using `pow(m,e,n)`.
|
||||
**Web lockout:** Multiple failed logins lock the web UI for several minutes.
|
||||
Provision trigger: `GET /servlet?p=autoprovision-cfg&q=autoprovision`
|
||||
Reboot API: `POST /servlet?p=reboot&q=reboot` (empty body)
|
||||
|
||||
**2026-06-02 issue:** `yealink_firmware_t48s = t48s-66.81.0.110.rom` in v_default_settings caused phone to get stuck downloading non-existent firmware. Fixed by disabling that setting (enabled=false). Phone 1000 (10.48.200.2) had its config reset during this process.
|
||||
|
||||
**Ext 1000 recovery:** If 1000 not registering — go to phone screen: Menu → Settings → Advanced → admin → Accounts → Account 1:
|
||||
server `134.209.72.226`, port `5080`, auth/user `1000`, password `Xk9mPw3nQv7rLs2t`
|
||||
|
||||
## Key Commands
|
||||
```bash
|
||||
# Reload ACL without restart
|
||||
fs_cli -x "reloadacl"
|
||||
# Reload dialplan/XML config
|
||||
fs_cli -x "reloadxml"
|
||||
# Restart external profile (drops registrations — avoid)
|
||||
fs_cli -x "sofia profile external restart"
|
||||
# Check registrations
|
||||
fs_cli -x "sofia status profile external reg"
|
||||
# Check gateway
|
||||
fs_cli -x "sofia xmlstatus gateway"
|
||||
# Clear dialplan cache
|
||||
rm -f /var/cache/fusionpbx/dialplan.public.*
|
||||
# Clear sofia profile cache
|
||||
rm -f /var/cache/fusionpbx/fusion.configuration.sofia.conf
|
||||
```
|
||||
|
||||
## fail2ban Whitelist
|
||||
- 107.178.2.130 (office), 97.247.128.120 (home WAN — updated 2026-06-17, was 97.154.109.245)
|
||||
- sip-auth-ip iptables chain — can get the FortiGate IP blocked; check with `iptables -L sip-auth-ip -n`
|
||||
@@ -0,0 +1,98 @@
|
||||
---
|
||||
name: fusionpbx-backup
|
||||
description: "FusionPBX (134.209.72.226) config backup to GitHub — weekly cron, restore wizard, PostgreSQL dump, full rebuild guide"
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: project
|
||||
originSessionId: c454fc50-f93d-4ddd-b9f3-f3f442e89fb9
|
||||
---
|
||||
|
||||
GitHub repo `myronblair/fusionpbx-config` (private) — PostgreSQL DB dump + FreeSWITCH configs + full rebuild guide.
|
||||
|
||||
**Why:** FusionPBX stores ALL config in PostgreSQL — extensions, dialplans, SIP gateways, IVR, ring groups, devices, voicemail, users. The DB dump IS the backup.
|
||||
|
||||
**How to apply:** Reference when discussing FusionPBX DR, the backup cron, or if the server needs to be rebuilt. See [[fusionpbx-freeswitch-setup]] for full FusionPBX operational config.
|
||||
|
||||
## SSH Access (critical — port 22 firewalled from internet)
|
||||
Only accessible from: 107.178.2.130 (FortiGate home) and 97.154.109.245 (FortiGate secondary).
|
||||
**From anywhere else, relay through DO:**
|
||||
```bash
|
||||
sshpass -p 'Gonewalk1974!@#' ssh -o StrictHostKeyChecking=no root@165.22.1.228 \
|
||||
'sshpass -p "Joker1974!@#" ssh -o StrictHostKeyChecking=no root@134.209.72.226 "command"'
|
||||
```
|
||||
|
||||
## Repo Structure
|
||||
- `database/fusionpbx.sql.gz` — Full PostgreSQL dump (gzip compressed; 306MB raw → ~29MB)
|
||||
- `database/postgres_globals.sql` — PostgreSQL roles/passwords
|
||||
- `freeswitch/` — vars.xml, freeswitch.xml, extensions.conf, sip_profiles/, autoload_configs/
|
||||
- `fusionpbx-app/config.php` — DB credentials for FusionPBX web app
|
||||
- `nginx/fusionpbx.conf` — nginx config (includes provisioning URL rewrites)
|
||||
- `fail2ban/` — jail.local (trusted IPs: 107.178.2.130, 97.154.109.245)
|
||||
- `network/` — netplan 50-cloud-init.yaml, hosts, hostname
|
||||
- `systemd/` — 9 FusionPBX service units (active_calls, email_queue, event_guard, etc.)
|
||||
- `ssh/authorized_keys`
|
||||
- `recordings/` — call recordings (~4KB currently)
|
||||
|
||||
## Schedule
|
||||
Weekly Sunday 5am: `0 5 * * 0 /usr/local/bin/fusionpbx-backup >> /var/log/fusionpbx-backup.log 2>&1`
|
||||
|
||||
## Manual trigger
|
||||
`/usr/local/bin/fusionpbx-backup` on the fusion server (or via DO relay)
|
||||
|
||||
## What's NOT backed up
|
||||
- SSL certs — re-issue: `certbot --nginx -d fusion.orbishosting.com`
|
||||
- FusionPBX web app `/var/www/fusionpbx/` — reinstalled by official installer
|
||||
- FreeSWITCH binary — installed by FusionPBX installer
|
||||
- Voicemail audio files — small, not critical
|
||||
|
||||
## Full Rebuild Flow (30–45 min)
|
||||
|
||||
### 1. New Debian 12 droplet
|
||||
Create fresh DO droplet, same region. SSH in (relay via DO if needed).
|
||||
|
||||
### 2. Clone repo and run restore
|
||||
```bash
|
||||
apt update && apt install -y git
|
||||
git clone https://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@github.com/myronblair/fusionpbx-config.git /opt/fusionpbx-config
|
||||
bash /opt/fusionpbx-config/restore.sh
|
||||
```
|
||||
|
||||
### 3. Restore script phases (interactive)
|
||||
1. SSH authorized_keys + hostname
|
||||
2. Run FusionPBX official installer (separate terminal, ~10-15 min):
|
||||
`wget -O - https://raw.githubusercontent.com/fusionpbx/fusionpbx-install.sh/master/debian/install.sh | bash`
|
||||
→ When asked for domain: `fusion.orbishosting.com`
|
||||
3. **Critical: PostgreSQL restore** — stops all services, drops+recreates DB, restores from `.sql.gz`
|
||||
4. FreeSWITCH config files
|
||||
5. FusionPBX app config.php (DB credentials)
|
||||
6. nginx config
|
||||
7. fail2ban
|
||||
8. Recordings
|
||||
9. Backup script + cron
|
||||
10. SSL (manual: `certbot --nginx -d fusion.orbishosting.com`)
|
||||
|
||||
### 4. Post-restore checks
|
||||
- Update fail2ban trusted IPs if FortiGate IP changed
|
||||
- Update Yealink provisioning URL if server IP changed (was 134.209.72.226)
|
||||
- Verify SignalWire trunk: FusionPBX → Accounts → Gateways
|
||||
- Delete Sofia XML cache: `rm /var/cache/fusionpbx/FusionPBX.configuration.sofia.conf`
|
||||
- Test ext 1000 (Myron Yealink T48S at 10.48.200.43)
|
||||
- Test ext 1001 (Tommy)
|
||||
- Test IVR 900
|
||||
|
||||
## Key Credentials
|
||||
| Item | Value |
|
||||
|------|-------|
|
||||
| FusionPBX web | https://fusion.orbishosting.com (admin / fY7XP5swgtpbzrYLhkeVYkA4744) |
|
||||
| Root SSH | root / Joker1974!@# |
|
||||
| PostgreSQL | fusionpbx database, user fusionpbx |
|
||||
| Relay DO server | root@165.22.1.228 / Gonewalk1974!@# |
|
||||
|
||||
## Architecture Notes
|
||||
- FusionPBX uses Lua XML handler — FreeSWITCH queries PostgreSQL via PHP/Lua for all routing. Static XML config in `/etc/freeswitch/` is mostly skeleton.
|
||||
- SignalWire SIP trunk uses `transport=udp` — TCP caused re-INVITE issues (gateway External URI must end in `;transport=udp`)
|
||||
- Ext 1000 (Yealink T48S) registers from behind FortiGate on port 5080 with `aggressive-nat-detection=true`
|
||||
- FusionPBX cache at `/var/cache/fusionpbx/FusionPBX.configuration.sofia.conf` — delete to force full Sofia reload
|
||||
|
||||
## PostgreSQL Dump Size Note
|
||||
306MB uncompressed, 29MB gzipped. Exceeds GitHub's 100MB limit uncompressed. Must use gzip (`pg_dump | gzip > fusionpbx.sql.gz`). Restore.sh handles both `.sql.gz` (zcat) and plain `.sql` formats.
|
||||
@@ -0,0 +1,79 @@
|
||||
---
|
||||
name: project-infra-todo
|
||||
description: Infrastructure TODO list — outstanding issues and fixes needed across homelab
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: project
|
||||
originSessionId: b1e93a6a-f101-4ea4-aafb-9cb7e2958821
|
||||
---
|
||||
|
||||
# Infrastructure TODO
|
||||
|
||||
Last updated: 2026-06-28
|
||||
|
||||
---
|
||||
|
||||
## 🔴 OPEN
|
||||
|
||||
- [x] **Synology iSCSI → Proxmox storage** — COMPLETE 2026-06-27. SynologyLVM (lvmthin, 1.86TB) active. SynologyiSCSI raw device also added. NAS at 10.48.200.249, IQN: iqn.2000-01.com.synology:NAS.Target-1.6296e09c4cb. Set as default Proxmox storage. NAS hostname fixed in /etc/hosts (was resolving to Tailscale IP — root cause of past VM corruptions). SynologyProx CIFS stays for backups/ISOs.
|
||||
|
||||
- [ ] **FortiGate DNS + Synology Reverse Proxy for all VMs** — Use Synology's built-in Reverse Proxy (DSM → Control Panel → Application Portal → Reverse Proxy) instead of NPM. FortiGate DNS overrides point all .lan domains → 10.48.200.249 (Synology). NPM kept but no longer primary.
|
||||
- **Step 1 — FortiGate DNS**: https://192.168.20.1 (admin / Joker1974!!!) → Network → DNS → Local DNS Records. Each .lan entry → 10.48.200.249
|
||||
- **Step 2 — Synology Reverse Proxy rules** (DSM → Control Panel → Application Portal → Reverse Proxy):
|
||||
| Source FQDN | Destination IP | Port | Notes |
|
||||
|------------|----------------|------|-------|
|
||||
| proxmox.lan | 10.48.200.90 | 8006 | HTTPS backend, enable WebSocket |
|
||||
| jarvis.lan | 10.48.200.211 | 80 | HTTP |
|
||||
| hoa.lan | 10.48.200.97 | 8123 | HTTP, **enable WebSocket** (HA requires it) |
|
||||
| homebridge.lan | 10.48.200.18 | 8581 | HTTP |
|
||||
| jellyfin.lan | 10.48.200.33 | 8096 | HTTP, enable WebSocket |
|
||||
| novacpx.lan | 10.48.200.110 | 8882 | HTTPS backend |
|
||||
| sonarr.lan | 10.48.200.35 | 8989 | HTTP |
|
||||
| radarr.lan | 10.48.200.35 | 7878 | HTTP |
|
||||
| qbit.lan | 10.48.200.35 | 8080 | HTTP |
|
||||
| ollama.lan | 10.48.200.210 | 11434 | HTTP |
|
||||
| npm.lan | 10.48.200.200 | 81 | HTTP |
|
||||
| nas.lan | 10.48.200.249 | 5001 | HTTPS (DSM itself) |
|
||||
- **Step 3 — Client DNS**: Set Windows DNS to FortiGate (192.168.20.1) or PVE1 (10.48.200.90) so .lan resolves
|
||||
- **WebSocket**: Must be enabled on proxmox.lan, hoa.lan, jellyfin.lan rules or those UIs will break
|
||||
|
||||
- [ ] **Home Assistant VM109 post-boot setup** — HA is booting (supervisor starting). Once port 8123 is up:
|
||||
1. Restore Google Drive backup (file ID: `1mLE1S9dSvxl0RYQnCt020WT-UZnQuxqP`)
|
||||
2. Install Tailscale addon (go to Supervisor > Add-on Store)
|
||||
3. Re-integrate JARVIS ↔ HA (212 entities)
|
||||
4. Resize disk from 32GB → 150GB (`qm resize 109 sata0 +118G` while VM stopped, then resize partition inside HA)
|
||||
|
||||
|
||||
|
||||
- [x] **CT110 WireGuard filesystem read-only** — fsck run, filesystem clean and rw. wg-clients.conf updated with new MediaStack pubkey. 2026-06-24.
|
||||
|
||||
- [x] **CT110 wg-clients auto-start** — added `/etc/local.d/wg-clients.start` (OpenRC local service). wg-clients comes up on boot. 2026-06-24.
|
||||
|
||||
- [x] **MediaStack QEMU guest agent** — installed and running, `qm guest exec 103` verified working 2026-06-24.
|
||||
|
||||
- [x] **Tailscale re-auth on PVE1** — completed 2026-06-24.
|
||||
|
||||
- [x] **NovaCPX stale ARP fix permanence** — static ARP for 10.48.200.201 (bc:24:11:67:1d:47) set as PERMANENT via systemd `static-arp.service` on NovaCPX, enabled on boot 2026-06-24.
|
||||
|
||||
- [x] **web.orbishosting.com — Ollama link** — verified working 2026-06-24.
|
||||
|
||||
- [x] **MediaStack backup to new storage** — VM 103 disk now on GoFlex storage. Backup job runs nightly at 21:00 to SynologyProx and backs up VM regardless of disk location. Verified 2026-06-24.
|
||||
|
||||
- [x] **NAS Git Server — Hybrid Mirror Setup** — COMPLETE 2026-06-29. Gitea 1.26.4 (ARM64) on Synology NAS at 10.48.200.249:3000, HTTPS at gitea.orbishosting.com. All 25 GitHub repos mirrored (every 8h). 4 private NAS-only repos: infra-private, fortigate-config, proxmox-secrets, jarvis-secrets. Auto-starts on boot via /usr/local/etc/rc.d/gitea.sh. Added to web.orbishosting.com dashboard.
|
||||
|
||||
- [x] **Synology NAS → FortiSwitch** — COMPLETE 2026-06-28. NAS LAN2 → FortiSwitch Port 6, NAS LAN1 → FortiSwitch Port 7. Bonding configured as **Adaptive Load Balancing (ALB)** in Synology DSM (802.3ad LACP not available on FortiGate 60F FortiOS for managed FortiSwitch via CLI or GUI). ALB provides outbound load balancing + redundancy without switch LACP support. NAS remains at 10.48.200.249.
|
||||
|
||||
---
|
||||
|
||||
## ✅ COMPLETED (2026-06-24 session)
|
||||
|
||||
- [x] MediaStack VM 103 restored from 2026-06-23 backup (I/O errors on Synology disk)
|
||||
- [x] MediaStack disk moved off Synology to new storage
|
||||
- [x] WireGuard kill-switch rebuilt on MediaStack — new keypair, CT110 peer updated, hardcoded fwmark, LAN exception correct
|
||||
- [x] WireGuard tunnel verified — exits via DO (165.22.1.228), handshake active
|
||||
- [x] Ollama listening on 0.0.0.0:11434 (was 127.0.0.1 only) — added systemd override
|
||||
- [x] CT110 LAN IP corrected to 10.48.200.67 (was wrongly documented as 10.48.200.19)
|
||||
- [x] NovaCPX 502s fixed — flushed stale ARP on NovaCPX for NPM's IP
|
||||
- [x] web.orbishosting.com WireGuard CT link updated to 10.48.200.67
|
||||
- [x] JARVIS admin URL updated to https://jarvis.orbishosting.com/admin/ everywhere
|
||||
- [x] web.orbishosting.com — Downloads card added (INFRASTRUCTURE-REFERENCE.md, syncs daily from JARVIS)
|
||||
@@ -0,0 +1,167 @@
|
||||
---
|
||||
name: project-jarvis
|
||||
description: "JARVIS AI Iron Man HUD — DigitalOcean 165.22.1.228; full admin portal at /admin; network auto-scan via PVE1; GitHub: myronblair/jarvis"
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: project
|
||||
originSessionId: f0b18417-cc26-4fdf-87ec-7b2d69b02c44
|
||||
---
|
||||
|
||||
JARVIS is hosted on **PVE1 VM 211** (10.48.200.211), migrated from DO 2026-06-18. URL: https://jarvis.orbishosting.com (via NPM → VM 211). Admin: https://jarvis.orbishosting.com/admin/
|
||||
|
||||
**How to apply:** Files at `/var/www/jarvis/` on VM 211. SSH: `sshpass -p 'Joker1974!!!' ssh -o StrictHostKeyChecking=no root@10.48.200.211`
|
||||
|
||||
## Credentials
|
||||
- Login: myron / Joker1974!!!
|
||||
- DB: jarvis_db / jarvis_user / J4rv1s_Pr0t0c0l_2026!
|
||||
- MySQL root: b71e5c1a8c7457541b9c1db822de37adfa271926a38b6c20
|
||||
- phpMyAdmin: /phpmyadmin (myron / Joker1974!!!)
|
||||
- HA token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJjZmQyMTYxNzdkZGY0MGQ5YjlkNjFhMTFiZmViZTNhNCIsImlhdCI6MTc3OTI0MTI2MywiZXhwIjoyMDk0NjAxMjYzfQ.wD3yYiCHh6iEuH1mZckg4dgr3zOJHLmlMj_N0OyzdR4
|
||||
- Agent registration key: f846a9aaf7ce9a61742c63c87c4186052a71d2a580c65518
|
||||
- Proxmox API token: root@pam!jarvis=c45b5feb-f9a9-445d-a626-14fbb959f78b
|
||||
|
||||
## Network Map (verified 2026-06-17)
|
||||
|
||||
### PVE1 VMs (10.48.200.90, orbisne.fortiddns.com)
|
||||
| VMID | Name | IP | Agent ID | Status |
|
||||
|------|------|----|----------|--------|
|
||||
| 100 | SynchroNet-50 | 10.48.200.50 | none | running |
|
||||
| 101 | HomeAssistant-97 | 10.48.200.97 | homeassistant_ha | online |
|
||||
| 102 | UmbrelOS | DHCP | none | running |
|
||||
| 104 | Windows10-DHCP | DHCP | none | running |
|
||||
| 105 | Frigate | DHCP | none | running — **not in use, no integration planned** |
|
||||
| 112 | Jellyfin-33 | 10.48.200.33 | jellyfin_7e386833 | online (fixed 2026-06-17) |
|
||||
| 103 | MediaStack-35 | 10.48.200.35 | MediaStack_2c00b1b8 | online (was VM113 pre-2026-06-22 restore) |
|
||||
| 118 | HomeBridge-26 | 10.48.200.18 | homebridge_b57cbaea | online (fixed 2026-06-17) |
|
||||
| 120 | NovaCPX-110 | 10.48.200.110 | novacpx_e3b07264 | online |
|
||||
|
||||
### PVE2 VMs (10.48.200.91)
|
||||
| VMID | Name | IP | Agent ID | Status |
|
||||
|------|------|----|----------|--------|
|
||||
| 302 | NetworkBackup-99 | 10.48.200.99 | networkbackup_NetworkB | online |
|
||||
|
||||
### Other Agents
|
||||
- **JARVIS DO**: 165.22.1.228 (agent: jarvis-do_orbis) — online
|
||||
- **PVE1**: 10.48.200.90 (agent: claude_pve) — online
|
||||
- **PVE2**: 10.48.200.91 (agent: pve2_pve2) — online
|
||||
- **FortiGate**: 10.48.200.1 (agent: fortigate_gw) — online
|
||||
- **WireGuard CT**: (agent: wireguard_360460f7, no LAN IP) — online
|
||||
- **Yealink T48S**: 10.48.200.43 (agent: yealink_t48s) — online
|
||||
- **mini_it12**: 10.48.200.87 (agent: mini_it12_windows, Windows) — offline since 2026-06-12
|
||||
|
||||
### Gone / No Longer Exist
|
||||
- Ollama VM 210 — was listed as deleted but IS running at 10.48.200.210 as VM 106 (was VM210 pre-restore). OLLAMA_HOST=0.0.0.0:11434 fixed 2026-06-24.
|
||||
- alien-pc_windows — not registered (Dell devices at .66/.67 exist on network but no agent)
|
||||
|
||||
### Agent Config Note
|
||||
Agents with old `server_url` config key crash on startup — must use `jarvis_url`. Fixed on homebridge and jellyfin 2026-06-17. If any other agent starts failing, copy config to /etc/jarvis-agent/config.json with `jarvis_url` key.
|
||||
|
||||
## Agent System
|
||||
- Push-based: heartbeat 10s, metrics 30s
|
||||
- agent.php uses CF-Connecting-IP header for real client IP (Cloudflare-aware)
|
||||
- Platform detection: windows/mac/linux/tablet — tablet shows view-only message
|
||||
- Subnet fallback match: if exact IP miss, matches same /24
|
||||
- Shell commands supported with `{"allowed": true}` in command_data
|
||||
- Installer: `curl -sk https://jarvis.orbishosting.com/install-agent.sh | bash -s <hostname> <linux|proxmox>`
|
||||
- For VMs needing sudo: `echo "Joker1974!" | sudo -S bash /tmp/install.sh <hostname> linux`
|
||||
|
||||
### Agent Versions (as of 2026-06-12)
|
||||
- **Linux v3.1**: adds version to registration payload, fixes self_update cfg scope bug in execute_command
|
||||
- **Windows v3.0**: real self-update (was stub), screenshot (PIL+PS fallback), sysinfo, re-registers on startup
|
||||
- **macOS v3.0**: new agent — CPU via `top -l 2`, mem via `sysctl`+`vm_stat`, screenshot via `screencapture -x`
|
||||
- Config location (mac): `~/.jarvis-agent/config.json` | agent_type: "macos" | agent_id: "{HOSTNAME}_mac"
|
||||
- **Old agents with `cfg` scope bug**: shell and update commands fail with `name 'cfg' is not defined` — auto-updates within 24h via periodic check in main() where cfg IS in scope
|
||||
- registered_agents table has `version VARCHAR(20)` column and 'macos' in agent_type ENUM
|
||||
|
||||
### Workers Admin Tab (added 2026-06-12)
|
||||
- VERSION column shows current vs latest version with color coding (green=current, red=outdated, yellow=unknown)
|
||||
- Update button: cyan "⬆ UPDATE" if outdated, dim "↻ UPDATE" if current
|
||||
- `agentUpdateFlow()`: popup modal, polls workers_list every 4s up to 90s, updates version cell in-place on completion
|
||||
|
||||
## Network Scanning
|
||||
- PVE1 cron: `*/3 * * * * /usr/local/bin/jarvis-netscan.sh` — nmap 10.48.200.0/24, pushes to `/api/netscan`
|
||||
- netscan.php authenticated via X-Registration-Key header
|
||||
- network.php includes netscan-discovered devices (online, last 15 min) in network panel
|
||||
- RUN NETWORK SCAN button: queues shell command to PVE1 agent, auto-refreshes panel after 45s
|
||||
- DO cannot SSH to PVE1 local IP — must use orbisne.fortiddns.com or agent commands
|
||||
- Site monitoring updated 2026-06-09: parkerslingshot key now points to parkerslingshotrentals.com (was parkerslingshot.epictravelexpeditions.com) in facts_collector.php, alerts.php, do_server.php
|
||||
|
||||
## Admin Portal (/admin)
|
||||
- URL: https://jarvis.orbishosting.com/admin — same login as JARVIS
|
||||
- Tabs: Dashboard, Agents, Network, Alerts, KB Facts, KB Intents, Home Assistant, News, Proxmox VMs, Sites, Users, **Tasks, Appointments**
|
||||
- Network tab: shows ALL discovered devices (not just named), filter online/offline/named, Scan Now queues PVE1 command
|
||||
- HA tab: reads from ha_entities table (real-time); toggle calls DO→HA directly (HA_URL = orbisne.fortiddns.com:8123)
|
||||
- News tab: custom pinned news stored in kb_facts (category='custom_news'), merged into main news feed
|
||||
- Proxmox VMs tab: uses cluster API (both PVE1+PVE2), shows CPU/RAM/disk/uptime/network per VM
|
||||
- Tasks tab: full CRUD (add/edit/mark done/delete), filter by status/category
|
||||
- Appointments tab: full CRUD, upcoming 90 days view
|
||||
|
||||
## Proxmox API
|
||||
- Accessible via orbisne.fortiddns.com:8006 (FortiGate forwards port 8006)
|
||||
- stats_cache.php uses cluster/resources API to get ALL VMs from both nodes
|
||||
- PVE2 VMs only accessible via cluster API (no direct external port forward for PVE2)
|
||||
|
||||
## Key Files (on DO at /home/jarvis.orbishosting.com/)
|
||||
- public_html/index.html — Iron Man HUD UI
|
||||
- public_html/admin/index.php — Admin portal (single-file PHP+JS)
|
||||
- public_html/api.php — API router
|
||||
- api/config.php — all config constants
|
||||
- api/endpoints/agent.php — agent registration/heartbeat/metrics/commands
|
||||
- api/endpoints/chat.php — 4-tier chat: KB intent → action intents → Ollama → Groq → Claude
|
||||
- api/endpoints/network.php — network device list (agents + named + netscan)
|
||||
- api/endpoints/netscan.php — push endpoint for PVE1 nmap results
|
||||
- api/endpoints/stats_cache.php — every 5min: Proxmox (cluster API), HA, weather, news
|
||||
- api/endpoints/facts_collector.php — every 3min: system stats, site health, HA facts
|
||||
- api/endpoints/do_server.php — reads /proc directly (no SSH loopback)
|
||||
|
||||
## DB Schema Notes
|
||||
- `agent_metrics` columns: id, agent_id, metric_type, metric_data (JSON longtext), recorded_at
|
||||
- metric_type='system'; CPU/RAM/disk live inside metric_data JSON
|
||||
- Extract with: JSON_EXTRACT(metric_data,'$.cpu_percent'), JSON_EXTRACT(metric_data,'$.memory.percent')
|
||||
- NO cpu_pct/mem_pct/disk_pct columns — always use JSON_EXTRACT
|
||||
|
||||
## Chat Architecture
|
||||
- Tier 1b: Action intents (network_scan → returns real DB data + queues PVE1 netscan)
|
||||
- network_scan intent: action type, returns real device count, never fabricates
|
||||
- Groq model: compound-beta-mini (NOT groq/compound-beta-mini)
|
||||
|
||||
## Planner System (added 2026-05-31)
|
||||
- Tables: `tasks` (title, notes, category ENUM personal/work/todo, priority ENUM low/normal/high/urgent, status ENUM pending/in_progress/done/cancelled, due_date, due_time, completed_at) and `appointments` (title, description, category, start_at, end_at, location, all_day, reminder_min, alerted)
|
||||
- API endpoint: `/api/planner/{tasks|appointments|today|done}` (GET=list, POST=save, DELETE=delete)
|
||||
- Voice intents in chat.php Tier 0.7: "add task X", "my tasks", "mark X done", "schedule X on date", "my calendar", "daily briefing"
|
||||
- Home page: small top-bar badge shows "N TASKS · N APPTS" when items due today; no new panels
|
||||
|
||||
## Voice System (updated 2026-05-31)
|
||||
- Continuous SpeechRecognition — mic always open, button is mute toggle (🎤 sleep / 🟢 listen / 🔇 mute)
|
||||
- Wake phrase (phase 1): "wake up JARVIS" or "daddy's home" → activates; JARVIS responds once
|
||||
- Command trigger (phase 2): "JARVIS [command]" executes; opens 17-second free-listen window for follow-ups
|
||||
- After 30 min no commands → voice sleeps; after 5 min idle → page reloads silently (no greeting)
|
||||
- Mic paused during ElevenLabs TTS via recognition.abort() + isSpeaking flag; resumes 300ms after audio ends
|
||||
- ElevenLabs: voice ID JBFqnCBsd6RMkjVDRZzb (George), model eleven_turbo_v2_5, key in config.php
|
||||
|
||||
## Arc Reactor AI Routing (updated 2026-06-17)
|
||||
- **Arc Reactor daemon**: `/opt/jarvis-arc/reactor.py` (Python, port 7474); service: `jarvis-arc`
|
||||
- **Deploy source**: `/home/jarvis.orbishosting.com/deploy/reactor.py` → copy to `/opt/jarvis-arc/reactor.py` + `systemctl restart jarvis-arc`
|
||||
- **llm_call() providers**: "claude" → Claude API, "groq" → Groq, "ollama" → local Ollama; cascades groq→ollama on failure
|
||||
- **Guardian anomaly alerts** (line ~1025): Groq `llama-3.3-70b-versatile` — 2-3 sentence Iron Man alert when CPU/RAM/disk/service thresholds trip
|
||||
- **SITREP** (line ~1068): Groq by default — comprehensive text briefing across all agents
|
||||
- **Vision: text-only sysinfo** (line ~691): Groq — when agent returns JSON snapshot (no image)
|
||||
- **Vision: actual screenshot** (line ~664): Claude `claude-opus-4-8-20251101` — stays on Claude, Groq has no vision models
|
||||
- **Email drafting, research, tool_loop**: still Claude — complex reasoning tasks
|
||||
|
||||
## kb_facts Fix (2026-06-17)
|
||||
- `storeFact()` ON DUPLICATE KEY UPDATE now explicitly sets `updated_at=NOW()` — previously MySQL wouldn't bump the timestamp if fact_value hadn't changed, causing do_server.php's 15-min freshness check to return empty sites
|
||||
- `$fresh()` in facts_collector.php was querying `WHERE fact_category=?` (wrong column); fixed to `WHERE category=?`
|
||||
- Site health checks now hit `http://127.0.0.1` with `Host:` header instead of public HTTPS URL (avoids Cloudflare 524 timeouts on self-check)
|
||||
|
||||
## Known Quirks
|
||||
- LSAPI deadlock: session_write_close() in api.php after auth
|
||||
- lsphp segfaults on -l flag; use php8.3 -l for syntax checking
|
||||
- DO cannot reach 10.48.200.x directly — use DDNS or agent commands
|
||||
- Proxmox local IP in config.php (PROXMOX_HOST=10.48.200.90) but API calls use orbisne.fortiddns.com
|
||||
- stats_cache.php uses orbisne.fortiddns.com:8006 (not PROXMOX_HOST) for Proxmox API
|
||||
- HA_URL = http://orbisne.fortiddns.com:8123 (FortiGate forwards 8123→HA); service calls work from DO
|
||||
- ha.php entity list reads from ha_entities table (NOT api_cache) — real-time data from HA agent
|
||||
- When editing index.html with Python patches: always use file-based scripts (not heredocs or inline), avoid double-brace `}}` near function closings
|
||||
- Arc Reactor bugs fixed 2026-06-12: capabilities panel uses `s?.capabilities || s?.handlers`; Guardian ts() variable shadowing fixed (renamed evTs); Vision always fetches fresh agents_list
|
||||
- Arc reactor DB bugs fixed 2026-06-12: column is `metric_data` not `metrics_json`; system data is flat JSON not nested under "system" key; conversations column is `content` not `message`; disk uses `mount` key not `mountpoint`
|
||||
@@ -0,0 +1,45 @@
|
||||
---
|
||||
name: jarvis-ha-integration
|
||||
description: "JARVIS ↔ Home Assistant two-way integration — status, what's installed, how it works"
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: project
|
||||
originSessionId: d9685e6b-8f79-4948-82e5-fbae607f7aa0
|
||||
---
|
||||
|
||||
HA is accessible at https://hoa.orbishosting.com (via NPM) or http://10.48.200.97:8123 (LAN direct).
|
||||
HA login: myronblair@outlook.com / Joker1974!!!
|
||||
After 2026-06-22 Proxmox restore: HA is now VM 109 (was VM 101). QEMU guest agent not installed.
|
||||
HA token (Jarvis2): eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiIzNmI0N2I1Njk5ZGQ0MTQ2ODMwZWFmYjZiYTQ1MjJkMSIsImlhdCI6MTc4MDIwMzU5NCwiZXhwIjoyMDk1NTYzNTk0fQ.sYRok-jRDlA4lFgWxLQELcEjkJNGQdprk6ZziLwLtXE
|
||||
|
||||
## Custom Component (installed 2026-05-31)
|
||||
Repo: myronblair/jarvis → ha_integration/custom_components/jarvis_agent/
|
||||
Installed at: /config/custom_components/jarvis_agent/ on HA VM (10.48.200.97)
|
||||
Config added to /config/configuration.yaml (jarvis_agent: block at end)
|
||||
|
||||
**Why:** Replaces PHP→DDNS→HA REST API with HA-initiated outbound polling — more reliable.
|
||||
|
||||
## How it works
|
||||
- HA pushes all entity state changes to JARVIS /api/agent/ha_state (debounced 2s)
|
||||
- HA polls /api/agent/heartbeat every 10s for queued commands
|
||||
- JARVIS admin panel toggle → queues command in agent_commands table → HA executes natively
|
||||
- 212 entities live in ha_entities DB table, updated in real-time
|
||||
- Agent registered as ID 15, hostname "homeassistant", IP 172.30.32.1 (Docker network)
|
||||
|
||||
## JARVIS Admin Panel HOME tab
|
||||
- 4-column table: domain icon | device name | state | toggle/run button
|
||||
- Unavailable entities filtered out automatically (reappear on next cache refresh)
|
||||
- Scenes get ▶ RUN button; switches/lights get toggle slider
|
||||
- Cache refreshed every 5 min by stats_cache.php cron
|
||||
|
||||
## Webhook fix (2026-05-31)
|
||||
webhook.php had wrong require path (../../ instead of /../) causing 500 since May 25.
|
||||
Fixed and committed. Auto-deploy pipeline working again.
|
||||
|
||||
## HA VM SSH
|
||||
- Port 22 on orbisne.fortiddns.com forwards to HA Ubuntu VM (not PVE1)
|
||||
- Password auth failing — likely key-only or fail2ban
|
||||
- Use HA web terminal (Settings → Add-ons → Advanced SSH & Web Terminal) for shell access
|
||||
- QEMU guest agent NOT installed in VM 101 (qm guest exec doesn't work)
|
||||
|
||||
**How to apply:** When working on HA component or HA VM files, use HA web terminal or HA File Editor addon. Cannot SSH directly.
|
||||
@@ -0,0 +1,274 @@
|
||||
---
|
||||
name: project-jarvis-todo
|
||||
description: "Master JARVIS TODO — agent deployment, self-healing, Windows service, HA integration, all outstanding work"
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: project
|
||||
originSessionId: e8442c3a-86d9-4b82-8f6d-071acd19159a
|
||||
---
|
||||
|
||||
# JARVIS Master TODO
|
||||
|
||||
Last updated: 2026-06-29
|
||||
|
||||
---
|
||||
|
||||
## ✅ FIXED THIS SESSION (2026-06-29) — ROUND 2
|
||||
|
||||
- [x] **HA Poller deployed on VM211** — `jarvis-ha-poller.py` running as `jarvis-ha-poller.service`. Polls HA at `http://10.48.200.97:8123` every 30s. 241 entities now pushing (lights, switches). Token expires 2033.
|
||||
- [x] **Missing DB tables created** — `tasks`, `appointments`, `usage_patterns` tables added. Fixed `registered_agents` enum to include `windows`/`macos` and `version` column.
|
||||
- [x] **schema.sql updated** — DB schema dumped from live VM211 to `db/schema.sql`, now includes all tables.
|
||||
- [x] **ha.php domain filter** — Added `camera`, `siren`, `remote`, `todo`, `lawn_mower` to `$skipDomains`. Only `light` and `switch` (plugs) show in HOME tab.
|
||||
- [x] **web.orbishosting.com fixed** — Root cause: Epson printer had ARP conflict at 10.48.200.200 (NPM's IP). FortiGate VIP for HTTP/HTTPS correctly forwards to 10.48.200.200. Fixed by: (1) bouncing NPM's eth0 to send gratuitous ARP, (2) setting permanent ARP entry on PVE1. https://web.orbishosting.com → NPM → NovaCPX (returns 401 Basic Auth — NovaCPX site auth).
|
||||
- [x] **PVE1 static ARP** — `/etc/network/if-up.d/npm-static-arp` persists `10.48.200.200 → BC:24:11:67:1D:47` across reboots.
|
||||
|
||||
## ✅ FIXED THIS SESSION (2026-06-29) — ROUND 1
|
||||
|
||||
- [x] **JARVIS API not executing PHP** — nginx `location ^~ /api` (no trailing slash) was intercepting `/api.php` and serving it as static text. Fixed to `location ^~ /api/`. PHP-FPM at `/run/php/php8.3-fpm.sock` confirmed working. `/api/ping` now returns JSON.
|
||||
- [x] **api.php backward-compat path normalization** — Added path rewrite so old `/api/endpoints/agent.php` format routes to the `agent` endpoint. Agents on old configs can now register.
|
||||
- [x] **DB schema: version + windows/macos** — Added `version VARCHAR(32)` to `registered_agents`; expanded `agent_type` enum to `linux|homeassistant|proxmox|windows|macos`.
|
||||
- [x] **Ollama models in config.php** — `OLLAMA_MODEL_PRIMARY` and `OLLAMA_MODEL_HEAVY` both set to `llama3.1:8b`. VM106 Ollama upgraded to 32GB RAM, 8 cores.
|
||||
- [x] **Windows agent installer** — Created `install-windows.ps1`: one PowerShell command installs Python, pywin32, downloads agent, creates config, registers+starts Windows Service. No open PowerShell needed after install.
|
||||
- [x] **Linux installer URL** — `install.sh` was hardcoded to `http://10.48.200.211` (LAN only). Fixed to default `https://jarvis.orbishosting.com`. LAN installs override with `JARVIS_URL=http://10.48.200.211`.
|
||||
|
||||
---
|
||||
|
||||
## 🔴 CRITICAL — Outstanding
|
||||
|
||||
### A. Epson Printer IP Conflict — NEEDS PERMANENT FIX
|
||||
Epson printer keeps taking 10.48.200.200 (NPM's static IP). Temporary fix: PVE1 has static ARP + gratuitous ARP from NPM. **Real fix**: assign Epson printer a different static IP in its web admin (find printer IP when it comes back up, log in to its config page, set static IP ≠ 10.48.200.200). DHCP reservation in FortiGate DHCP server for printer's MAC also works.
|
||||
|
||||
### B. Windows Agent on Myron's Desktop — NEEDS ADMIN POWERSHELL
|
||||
Run this in an **Admin PowerShell** (not Claude Code terminal):
|
||||
```powershell
|
||||
$env:JARVIS_REG_KEY='f846a9aaf7ce9a61742c63c87c4186052a71d2a580c65518'
|
||||
& 'C:\Users\myron\repos\jarvis\public_html\agent\install-windows.ps1'
|
||||
```
|
||||
After install: `Get-Service JARVISAgent` should show Running.
|
||||
|
||||
### C. web.orbishosting.com NovaCPX 401
|
||||
Site routes correctly to NovaCPX but returns `401 Basic realm="Blair HQ"`. Need to check CyberPanel on NovaCPX (10.48.200.110) — either the website isn't created for web.orbishosting.com, or HTTP auth is enabled on the default site. Access CyberPanel at https://10.48.200.110:8090 to check.
|
||||
|
||||
### D. Re-install JARVIS HA Custom Component (VM109 rebuilt)
|
||||
```bash
|
||||
# From PVE1, get HA terminal or use Proxmox console for VM109:
|
||||
# Copy from JARVIS server to HA config:
|
||||
ssh root@10.48.200.211 'tar czf /tmp/ha-component.tgz -C /var/www/jarvis ha-component'
|
||||
# Then on HA VM or via PVE1 -> VM109 console:
|
||||
# mkdir -p /config/custom_components
|
||||
# tar xzf ha-component.tgz -C /config/
|
||||
# Restart HA
|
||||
```
|
||||
After restart: `ha_entities` should fill. Also restore HA backup file ID `1mLE1S9dSvxl0RYQnCt020WT-UZnQuxqP` from Google Drive via HA UI.
|
||||
|
||||
### B. Push to GitHub + Verify Auto-Deploy
|
||||
The fixes in this session need to be committed and pushed so VM211 picks them up (webhook deploy):
|
||||
```bash
|
||||
cd C:\Users\myron\repos\jarvis
|
||||
git add -A && git commit -m "Fix nginx PHP, API paths, Windows installer, install.sh URL"
|
||||
git push
|
||||
```
|
||||
After push: verify VM211 auto-deployed (`journalctl -u jarvis-deploy -n 20` on VM211).
|
||||
|
||||
### C. Install Agent on Ollama VM106 (10.48.200.210) — new VM, no agent
|
||||
```bash
|
||||
# From PVE1:
|
||||
ssh root@10.48.200.210 "curl -sk https://jarvis.orbishosting.com/agent/install.sh | bash -s ollama106 linux"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🟠 HIGH — Deploy Agents to All Hosts
|
||||
|
||||
**Linux/Proxmox (LAN) one-liner:**
|
||||
```bash
|
||||
JARVIS_URL=http://10.48.200.211 curl -sk https://jarvis.orbishosting.com/agent/install.sh | bash -s <hostname> <linux|proxmox>
|
||||
```
|
||||
|
||||
**Linux (External/DO):**
|
||||
```bash
|
||||
curl -sk https://jarvis.orbishosting.com/agent/install.sh | bash -s <hostname> linux
|
||||
```
|
||||
|
||||
**Windows (Admin PowerShell):**
|
||||
```powershell
|
||||
$env:JARVIS_REG_KEY='f846a9aaf7ce9a61742c63c87c4186052a71d2a580c65518'
|
||||
irm https://jarvis.orbishosting.com/agent/install-windows.ps1 | iex
|
||||
```
|
||||
|
||||
**Mac:**
|
||||
```bash
|
||||
curl -sk https://jarvis.orbishosting.com/agent/install-mac.sh | bash -s -- --key f846a9aaf7ce9a61742c63c87c4186052a71d2a580c65518
|
||||
```
|
||||
|
||||
**Deployment status table:**
|
||||
|
||||
| Host | IP | Type | Status | Action Needed |
|
||||
|------|-----|------|--------|--------|
|
||||
| PVE1 | 10.48.200.90 | proxmox | ❓ check | Verify in Workers tab |
|
||||
| PVE2 | 10.48.200.91 | proxmox | ❓ check | Verify in Workers tab |
|
||||
| JARVIS VM211 | 10.48.200.211 | linux | ❓ check | Self-monitors |
|
||||
| Ollama VM106 | 10.48.200.210 | linux | ❌ missing | Install now (see Critical C) |
|
||||
| Jellyfin VM112 | 10.48.200.33 | linux | ❓ check | Verify in Workers tab |
|
||||
| MediaStack VM103 | 10.48.200.35 | linux | ❓ check | Verify in Workers tab |
|
||||
| HomeBridge VM118 | 10.48.200.18 | linux | ❓ check | Verify in Workers tab |
|
||||
| NovaCPX VM120 | 10.48.200.110 | linux | ❓ check | Verify in Workers tab |
|
||||
| SynchroNet VM100 | 10.48.200.50 | linux | ❌ missing | Install if SSH accessible |
|
||||
| NetworkBackup | 10.48.200.99 | linux | ❓ check | Verify in Workers tab |
|
||||
| HA VM109 | 10.48.200.97 | homeassistant | ❌ missing | See Critical A |
|
||||
| CT110 WireGuard | 10.48.200.67 | linux | ❌ missing | apk add python3, install agent |
|
||||
| DO Server | 165.22.1.228 | linux | ❓ check | Verify in Workers tab |
|
||||
| Myron's Desktop (this PC) | DHCP | windows | ❌ missing | Run install-windows.ps1 |
|
||||
| Windows VM104 | DHCP | windows | ❌ missing | Run install-windows.ps1 |
|
||||
| mini_it12 | 10.48.200.87 | windows | ❌ offline | Last seen 2026-06-12, re-install |
|
||||
| Mac machines | any | macos | ❌ missing | Run install-mac.sh |
|
||||
|
||||
---
|
||||
|
||||
## 🟠 HIGH — Self-Healing Details
|
||||
|
||||
**Linux** — systemd `Restart=always` + `RestartSec=10`. Already built into install.sh service file.
|
||||
|
||||
**Windows** — After install, run once to add recovery actions:
|
||||
```powershell
|
||||
sc.exe failure JARVISAgent reset=86400 actions=restart/10000/restart/30000/restart/60000
|
||||
```
|
||||
|
||||
**Self-update** — All agents auto-update every 24h. Push new agent code to GitHub → VM211 deploys → all agents pick up update within 24h. For urgent: JARVIS Admin → Workers → UPDATE button per agent.
|
||||
|
||||
**Alpine/OpenRC** (CT110):
|
||||
```sh
|
||||
# /etc/local.d/jarvis-agent.start
|
||||
nohup sh -c 'while true; do python3 /opt/jarvis-agent/jarvis-agent.py; sleep 10; done' &
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🟠 HIGH — Windows Agent Compiled Executable
|
||||
|
||||
Current installer works (installs Python silently) but a standalone `.exe` is cleaner for restricted machines.
|
||||
|
||||
Build steps (run on any Windows machine with Python):
|
||||
```powershell
|
||||
pip install pyinstaller pywin32
|
||||
pyinstaller --onefile --hidden-import=win32timezone --hidden-import=win32security `
|
||||
C:\Users\myron\repos\jarvis\agent\jarvis-agent-windows.py -n jarvis-agent
|
||||
# Upload dist/jarvis-agent.exe to VM211:/var/www/jarvis/public_html/agent/
|
||||
```
|
||||
|
||||
Then update `install-windows.ps1` to download the exe and use `.\jarvis-agent.exe --startup auto install`.
|
||||
|
||||
---
|
||||
|
||||
## 🟡 MEDIUM — HA Integration (VM109)
|
||||
|
||||
Full post-rebuild checklist:
|
||||
- [ ] Restore Google Drive backup (`1mLE1S9dSvxl0RYQnCt020WT-UZnQuxqP`)
|
||||
- [ ] Re-install JARVIS HA component (see Critical A)
|
||||
- [ ] Install Tailscale addon (Settings → Add-ons → Search Tailscale)
|
||||
- [ ] Resize disk: power off → `qm resize 109 sata0 +118G` → boot → `ha os datadisk resize`
|
||||
- [ ] Verify `HA_URL=http://orbisne.fortiddns.com:8123` in config.php
|
||||
- [ ] After component reinstall: verify `ha_entities` fills (~2587 rows)
|
||||
|
||||
**HA HOME tab filter** — after backup restore, audit `ha.php` `$skipKeywords` to ensure Tuya/TP-Link/Z-Wave switches aren't being filtered out.
|
||||
|
||||
---
|
||||
|
||||
## 🟡 MEDIUM — JARVIS Server Health Checks
|
||||
|
||||
```bash
|
||||
# SSH to VM211:
|
||||
|
||||
# Verify cron jobs
|
||||
crontab -l
|
||||
# Should have: */5 * * * * php /var/www/jarvis/api/endpoints/stats_cache.php
|
||||
# */3 * * * * php /var/www/jarvis/api/endpoints/facts_collector.php
|
||||
|
||||
# Arc Reactor status
|
||||
systemctl status jarvis-arc
|
||||
curl -s http://10.48.200.211:7474/health
|
||||
|
||||
# Backups
|
||||
ls -lh /var/backups/jarvis/
|
||||
|
||||
# JARVIS ping
|
||||
curl -s https://jarvis.orbishosting.com/api/ping
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🟢 LOW — FortiGate DNS + Synology Reverse Proxy
|
||||
|
||||
Adds `.lan` domain access. Full instructions in `project_infra_todo.md`.
|
||||
Key entries: jarvis.lan → VM211:80, proxmox.lan → 10.48.200.90:8006, hoa.lan → VM109:8123.
|
||||
|
||||
---
|
||||
|
||||
## 🔑 Key Constants
|
||||
|
||||
| Item | Value |
|
||||
|------|-------|
|
||||
| Registration key | `f846a9aaf7ce9a61742c63c87c4186052a71d2a580c65518` |
|
||||
| JARVIS URL (external) | `https://jarvis.orbishosting.com` |
|
||||
| JARVIS LAN | `http://10.48.200.211` |
|
||||
| HA Token | `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...` (in config.php, expires 2026) |
|
||||
| Proxmox API token | `root@pam!jarvis=c45b5feb-f9a9-445d-a626-14fbb959f78b` |
|
||||
|
||||
---
|
||||
|
||||
## 🔴 OPEN (pre-existing)
|
||||
|
||||
- [ ] **HA HOME tab — show all lights, plugs, switches** — currently 17 lights show but only 3 useful switches (Sirens, CEC Scanner, ESPHome) pass the filter. Need to audit what real smart plug/switch entities exist in HA (Tuya, TP-Link Tapo, Z-Wave, etc.) and ensure they appear in the JARVIS HOME tab. The `$skipKeywords` filter in `api/endpoints/ha.php` strips camera/HACS junk — verify real device switches aren't accidentally filtered. Also check if HA custom component is syncing all entity domains.
|
||||
|
||||
- [ ] **Claude API credits** — image-based Vision Protocol (`handle_screenshot` with actual PNG) uses `claude-opus-4-8`. Top up at console.anthropic.com if vision fails. Guardian/SITREP now on Groq so those no longer drain credits.
|
||||
|
||||
- [x] **HA agent persistence** — SOLVED. The HA custom component (`jarvis_agent`) runs inside HA's Docker container (IP 172.30.32.1) and auto-starts with HA. Online and healthy. The old standalone Python script at 10.48.200.97 is obsolete.
|
||||
|
||||
---
|
||||
|
||||
## ✅ COMPLETED (2026-06-18 session)
|
||||
|
||||
- [x] JARVIS fully migrated DO → PVE1 VM 211 (8c/16GB, nginx/PHP8.3/MariaDB/Redis/Arc Reactor)
|
||||
- [x] All 3 new VMs on PVE1: JARVIS-211, NPM-200, Ollama-210 (IP changed from .95 → .210, Reolink owns .95)
|
||||
- [x] Tailscale on all key hosts — full mesh, all 13+ nodes documented
|
||||
- [x] FortiGate VIPs updated to 97.247.237.97; JARVIS on port 1972, HOA on 8123
|
||||
- [x] NPM running at http://10.48.200.200:81 (Docker, proxy hosts for hoa/novacpx)
|
||||
- [x] JARVIS backups — /var/backups/jarvis/, daily cron 7am UTC (2am CDT), 7-day retention
|
||||
- [x] Jellyfin agent — v3.1 online at 10.200.0.3 via PVE1 password SSH
|
||||
- [x] HA agent — v3.1 running on HA VM at 10.48.200.97 via HA web terminal
|
||||
- [x] PVE1 ImageMagick — installed
|
||||
- [x] Vision screenshots tab — already existed in admin under Arc Reactor → Vision Protocol
|
||||
- [x] MediaStack SSH key — DO key generated and copied to MediaStack via PVE1 hop
|
||||
- [x] Workers terminology — already "JARVIS AGENT WORKERS" in admin
|
||||
- [x] install-agent.sh — default URL updated to http://10.48.200.211
|
||||
- [x] Website webhooks — all 7 repos → tomtomgames.com/webhook.php (DO); JARVIS repo → port 1972
|
||||
- [x] webhook.php fixed (broken define from bad sed), synced to DO
|
||||
- [x] Service monitor updated — nginx/php-fpm/mariadb/redis/arc/agent (not OLS-era services)
|
||||
- [x] DO server WEB HOST block on front page — shows DO CPU/RAM/DISK via Tailscale agent
|
||||
- [x] Network devices cleaned up — 23 named devices, all infrastructure labeled
|
||||
- [x] Agent configs fixed — all 8+ agents pointing to new JARVIS VM, correct watch_services per host
|
||||
- [x] Facts collector fixed — external site checks, correct column names, proper timeouts
|
||||
- [x] CLAUDE.md + INFRASTRUCTURE-REFERENCE.md fully updated and pushed
|
||||
|
||||
---
|
||||
|
||||
## ✅ COMPLETED (2026-06-17 session)
|
||||
|
||||
- [x] Phase 3 JS modularization — jarvis-protocols.js split into 3 panel files
|
||||
- [x] Guardian/SITREP/Vision text → Groq (image analysis stays Claude)
|
||||
- [x] kb_facts freshness fix (storeFact updated_at, $fresh() column name)
|
||||
- [x] Site health local loopback fix
|
||||
- [x] Cloudflare Rocket Loader fix (face-api.js data-cfasync)
|
||||
- [x] Session fix (api.php skip logic too broad)
|
||||
- [x] JS syntax fix (apostrophe in face-api label)
|
||||
- [x] All 8 online Linux/Proxmox agents → v3.1 with version in heartbeat
|
||||
|
||||
---
|
||||
|
||||
## ✅ COMPLETED (2026-06-12 session)
|
||||
|
||||
- [x] Agent v3.1 Linux, v3.0 Windows, v3.0 macOS
|
||||
- [x] Workers tab VERSION column + agentUpdateFlow
|
||||
- [x] Arc Reactor systemd active, tracked in git
|
||||
- [x] All 13 "make it stand out" improvements
|
||||
- [x] MediaStack NAS migration
|
||||
@@ -0,0 +1,70 @@
|
||||
---
|
||||
name: project-mediastack
|
||||
description: MediaStack VM on PVE1 — Sonarr/Radarr/Prowlarr/qBittorrent behind WireGuard VPN through CT110→DO
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: project
|
||||
originSessionId: b1e93a6a-f101-4ea4-aafb-9cb7e2958821
|
||||
---
|
||||
|
||||
## VM Details (updated 2026-06-24)
|
||||
- **VM ID:** 103 | **Name:** MediaStack-35 | **IP:** 10.48.200.35
|
||||
- **Hypervisor:** PVE1 (10.48.200.90)
|
||||
- **Disk:** 50GB on **GoFlex** storage (moved off SynologyProx 2026-06-24 due to I/O errors)
|
||||
- **OS:** Ubuntu 24.04 (noble cloud image)
|
||||
- **QEMU guest agent:** installed and running (installed 2026-06-24)
|
||||
- **SSH:** PVE1 key → `ssh -o StrictHostKeyChecking=no -i /root/.ssh/id_rsa root@10.48.200.35`
|
||||
- **GitHub:** `myronblair/mediastack` cloned at `/opt/mediastack`
|
||||
|
||||
## Services, Ports & Credentials
|
||||
| Service | Port | Login | API Key |
|
||||
|---------|------|-------|---------|
|
||||
| qBittorrent | :8080 | admin / Joker1974!!! | — |
|
||||
| Sonarr | :8989 | — | `b43e04350a594846b4ee95261c29e9e0` |
|
||||
| Radarr | :7878 | — | `53c4268360444feeae5f98c0cc24e0e3` |
|
||||
| Prowlarr | :9696 | — | `9d0ce6c5660743b5bf1c7951efc62252` |
|
||||
|
||||
All services run as root (NFS ACL requires root for writes).
|
||||
|
||||
## VPN Architecture (updated 2026-06-24)
|
||||
|
||||
### wg0 — Internet kill-switch (primary VPN)
|
||||
- **Interface:** `wg0` | **VPN IP:** `10.200.0.4/24`
|
||||
- **Endpoint:** CT110 at `10.48.200.67:51821` → NordVPN (us9156, 2.56.190.66:51820) → internet
|
||||
- **Exit IP:** `2.56.190.69` (NordVPN US, verified 2026-06-29)
|
||||
- **Kill-switch:** iptables rules — REJECT all non-wg0 non-fwmark traffic; LAN 10.48.200.0/24 always allowed
|
||||
- **Config:** `/etc/wireguard/wg0.conf` — fwmark hardcoded as `51820` (not dynamic, avoids PostDown race)
|
||||
- **Auto-start:** `systemctl enable wg-quick@wg0` (enabled 2026-06-24)
|
||||
- **DNS:** `10.48.200.90` (PVE1 dnsmasq)
|
||||
- **MediaStack pubkey:** `CaG79S1fJeJDlYCMhHz8BrDfizBq+OiGnO5VzFIk3gE=`
|
||||
- **CT110 pubkey:** `Fqb1KLfHe1r3+Hwhem7YGZB2KikGYy/8pPsOIP4rn18=` (updated 2026-06-29 — old key was RXxD...)
|
||||
- **NordVPN exit IP:** 2.56.190.69 (us9156.nordvpn.com) — verified 2026-06-29
|
||||
|
||||
### wg1 — Jellyfin media access (NOT internet VPN)
|
||||
- MediaStack is WireGuard server on `wg1` (port 51820, 10.200.0.1/24)
|
||||
- Jellyfin (10.48.200.33) connects as peer (10.200.0.3)
|
||||
- Used for NFS media file access only
|
||||
|
||||
## Media Storage
|
||||
- Downloads: `/mnt/nas/video/downloads` (Synology NAS NFS)
|
||||
- Movies: `/mnt/nas/video/movies` | TV: `/mnt/nas/video/tv`
|
||||
- Old paths `/media/movies` and `/media/tv` are NFS mounts from NAS (Jellyfin backward compat)
|
||||
- Jellyfin fstab: `10.48.200.35:/media/movies /mnt/mediastack/movies nfs defaults,_netdev 0 0`
|
||||
|
||||
## Indexer — IPTorrents
|
||||
- Cookie auth in Prowlarr: `uid=2237410; pass=JzLP2niTWxBJAZIU3yvtLbJzD55kdLeB`
|
||||
- Cookies expire — if indexer fails, log into iptorrents.com in browser, copy uid+pass cookies
|
||||
|
||||
## JARVIS Agent
|
||||
- Agent ID: `MediaStack_2c00b1b8` | Config: `/opt/jarvis-agent/config.json`
|
||||
- Registration key: `f846a9aaf7ce9a61742c63c87c4186052a71d2a580c65518` | `ssl_verify: false`
|
||||
|
||||
## PBS Backup
|
||||
- Nightly at 21:00 → SynologyProx storage
|
||||
- Backs up VM regardless of which storage the disk lives on
|
||||
|
||||
## Known Issues
|
||||
- **wg-quick down/up over SSH kills the connection** — PostDown briefly removes LAN ACCEPT before REJECT; SSH reply is dropped. Always use VM console for wg0 cycling, or use `nohup` background.
|
||||
- **NFS write failures** = services not running as root
|
||||
- **Radarr "0 active indexers"** = blocked in DB; fix: `sqlite3 /var/lib/radarr/radarr.db "DELETE FROM IndexerStatus WHERE ProviderId=1;"`
|
||||
- **Stale NFS file handle on Jellyfin** = lazy unmount + remount on Jellyfin VM
|
||||
@@ -0,0 +1,99 @@
|
||||
---
|
||||
name: project-novacpx
|
||||
description: NovaCPX — custom Linux web hosting control panel (cPanel alternative) built from scratch
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: project
|
||||
originSessionId: c454fc50-f93d-4ddd-b9f3-f3f442e89fb9
|
||||
---
|
||||
|
||||
NovaCPX is a full web hosting control panel built from scratch with 4 dedicated ports: Admin :8882, Reseller :8881, User :8880, Webmail (Roundcube) :8883.
|
||||
|
||||
**Why:** User wants a cPanel/Plesk alternative they own outright, with distinctive UI, auto-installer, and extensible feature system.
|
||||
|
||||
**How to apply:** Direct SSH to VM works (no PVE hop needed). All code in /tmp/novacpx locally + pushed to GitHub myronblair/novacpx.
|
||||
|
||||
## VM Details
|
||||
- Host: PVE1 VM 120, name HostPanel-110
|
||||
- IP: 10.48.200.110 (static)
|
||||
- OS: Ubuntu 24.04 LTS
|
||||
- **SSH (direct — works from Claude Code):** `sshpass -p 'Joker1974!!!' ssh -o StrictHostKeyChecking=no root@10.48.200.110`
|
||||
- **SCP (direct):** `sshpass -p 'Joker1974!!!' scp -o StrictHostKeyChecking=no FILE root@10.48.200.110:/path`
|
||||
- PVE1 hop NOT needed and currently broken (permission denied on orbisne.fortiddns.com SSH)
|
||||
- Panel web root: /srv/novacpx/public
|
||||
- Repo on VM: /opt/novacpx-src
|
||||
- Source of truth for deploy scripts: /opt/novacpx-src/deploy/
|
||||
|
||||
## GitHub
|
||||
- Repo: myronblair/novacpx (private)
|
||||
- Branches: `main` (stable releases, PATCH auto-bump) and `beta` (beta releases, -beta.N auto-bump)
|
||||
- Auto-deploy: push to main or beta → GitHub webhook → VM pulls (deploy-runner.sh cron every min)
|
||||
- PAT: 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
|
||||
|
||||
## Ports
|
||||
- 8880 — User panel
|
||||
- 8881 — Reseller panel
|
||||
- 8882 — Admin/datacenter panel
|
||||
- 8883 — Roundcube webmail
|
||||
|
||||
## Architecture
|
||||
- Backend: PHP 8.3 REST API (/api/{endpoint}/{action})
|
||||
- Auth: session cookie `ncpx_session` (login returns token, set as cookie) + Bearer tokens for API. Both use SHA256 hash lookup in sessions/api_tokens tables.
|
||||
- DB: **SQLite** at /var/lib/novacpx/panel.db (migrated from MySQL 2026-06-09)
|
||||
- DB.php has translate() layer: ON DUPLICATE KEY→ON CONFLICT, DATE_ADD/DATE_SUB→datetime(), NOW()→datetime('now')
|
||||
- **novacpx_version table**: tracks install history; columns: id, version, installed_at, notes, git_commit
|
||||
- **settings table**: panel_version key tracks current version; update_channel (stable/beta) controls which GitHub branch to check/pull
|
||||
- Feature registry: 70+ pluggable features in 20 categories
|
||||
- Update channels: stable=origin/main (major/minor), beta=origin/beta (patch/pre-release)
|
||||
|
||||
## VM Credentials
|
||||
- Admin panel: `admin / Admin2026!`
|
||||
- Root SSH: `root / Joker1974!!!`
|
||||
- MySQL (customer sites): novacpx_user / 6fyWj6vYnJDKEQvNANzj
|
||||
- WP provisioning MySQL user: novacpx_wp / tCXAU1K2WX31xUAMY9EM
|
||||
- Config: /etc/novacpx/config.ini (root:www-data 640)
|
||||
|
||||
## JARVIS Agent
|
||||
- Installed 2026-06-09; agent_id: novacpx_e3b07264
|
||||
- Status: online, reporting heartbeats to JARVIS every 10s
|
||||
- Config: /opt/jarvis-agent/config.json
|
||||
- Key config fields: server_url, host_header, api_key, agent_type: linux, heartbeat_interval: 10
|
||||
|
||||
## Versioning (as of 2026-06-10)
|
||||
- Current git version: 1.0.27 (GitHub main)
|
||||
- Active deploy channel: beta (VM settings)
|
||||
- GitHub Actions auto-bumps VERSION on push to main (PATCH) or beta (-beta.N)
|
||||
- deploy-runner.sh writes new version to novacpx_version + settings.panel_version after every webhook deploy
|
||||
- deploy-runner.sh also copies VERSION to web root (/srv/novacpx/public/VERSION) — fixed 2026-06-10
|
||||
- apply-novacpx-update endpoint does the same for manual updates
|
||||
- Updates page shows installed version, latest remote version, and active channel badge
|
||||
|
||||
## Settings Page
|
||||
- Loads current values from DB via server-options API (panel_name, default_php, nameservers, update_channel)
|
||||
- Saves each field via save-option API individually
|
||||
- Update channel dropdown shows stable vs beta with explanatory labels
|
||||
|
||||
## Docker App Catalog (as of 2026-06-10)
|
||||
- **140 apps** across 15 categories in DockerManager.php
|
||||
- Categories: Web/CMS, Productivity, Dev, Analytics, Wiki/Docs, Messaging/Chat, Security/Auth, Business, Design/Collab, AI/LLM, Developer Tools, Databases, Monitoring, Networking/Security, CMS/E-commerce, Project Mgmt, Communication, File/Storage, ERP/Business, Media, Smart Home, Dashboards/Admin
|
||||
- Security fixes applied (code review 2026-06-09): shell injection fixes in WordPressManager, PHPManager, install.sh sudoers hardening (removed `ufw *` wildcard, removed `curl *` and `env *` NOPASSWD), SQLite syntax fix, WP-CLI download size validation
|
||||
- Per-account uninstall (uninstall-account API action), per-stack Reinstall button
|
||||
- Admin Docker page has App Catalog tab to launch apps on behalf of accounts
|
||||
|
||||
## nginx / phpMyAdmin (fixed 2026-06-12)
|
||||
- Apache2 was holding port 80 — stopped and disabled: `systemctl stop apache2 && systemctl disable apache2`
|
||||
- nginx now running and enabled on boot
|
||||
- phpMyAdmin accessible at `http://10.48.200.110/phpmyadmin` (returns 200)
|
||||
- nginx config: `/etc/nginx/sites-enabled/default` with /phpmyadmin location block
|
||||
- phpmyadmin.conf in /etc/nginx/conf.d/ is empty (just a comment) — all config in sites-enabled/default
|
||||
|
||||
## Known Quirks
|
||||
- PVE1 SSH (orbisne.fortiddns.com) currently permission-denied — use direct IP 10.48.200.110 instead
|
||||
- api/.htaccess needed for URL routing
|
||||
- NOVACPX_ROOT in api/index.php is dirname(__DIR__) = /srv/novacpx/public (NOT 2 levels up)
|
||||
- SQLite only — never use MySQL syntax (ON DUPLICATE KEY, NOW(), etc.)
|
||||
- sudo tee pattern needed for writing /etc/postfix/* files as www-data
|
||||
- Docker stacks backed by docker_compose_stacks table (separate from docker_containers)
|
||||
- Panel reachable at https://10.48.200.110:8882 (self-signed cert with SAN for IP)
|
||||
- PHP-FPM pools are root-owned; www-data cannot file_exists()/unlink() them — must use `sudo rm -f`
|
||||
- git cherry-pick to beta required after each main push (GitHub Actions version bumps create divergence)
|
||||
@@ -0,0 +1,72 @@
|
||||
---
|
||||
name: project-novacpx-tools
|
||||
description: NovaCPX development tools and session-start checklist — load at start of every NovaCPX session
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: project
|
||||
originSessionId: c454fc50-f93d-4ddd-b9f3-f3f442e89fb9
|
||||
---
|
||||
|
||||
## Session-start checklist (run at start of every NovaCPX session)
|
||||
|
||||
1. **Verify working directory**: `ls /tmp/novacpx/` — if missing, repo needs re-cloning
|
||||
2. **Test VM reachability** (direct — PVE1 hop NOT needed):
|
||||
```bash
|
||||
sshpass -p 'Joker1974!!!' ssh -o StrictHostKeyChecking=no -o ConnectTimeout=8 root@10.48.200.110 'echo vm-ok'
|
||||
```
|
||||
> PVE1 (orbisne.fortiddns.com) SSH is currently broken (permission denied). Direct to 10.48.200.110 works fine.
|
||||
3. **Load TODO**: read `/root/.claude/projects/-home-myron/memory/project_novacpx_todo.md`
|
||||
4. **Check panel live**: `curl -sk -o /dev/null -w "%{http_code}" https://10.48.200.110:8882/`
|
||||
|
||||
## Direct SSH / SCP (preferred method)
|
||||
```bash
|
||||
# Run command on VM
|
||||
sshpass -p 'Joker1974!!!' ssh -o StrictHostKeyChecking=no root@10.48.200.110 'command here'
|
||||
|
||||
# Copy file to VM
|
||||
sshpass -p 'Joker1974!!!' scp -o StrictHostKeyChecking=no /tmp/novacpx/panel/api/endpoints/foo.php \
|
||||
root@10.48.200.110:/srv/novacpx/public/api/endpoints/foo.php
|
||||
```
|
||||
|
||||
## API auth pattern (session cookie)
|
||||
```bash
|
||||
# Login and get token
|
||||
TOKEN=$(curl -sk -X POST "https://10.48.200.110:8882/api/auth/login" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"username":"admin","password":"Admin2026!"}' | python3 -c "import sys,json; print(json.load(sys.stdin)['data']['token'])")
|
||||
|
||||
# Use token as ncpx_session cookie
|
||||
curl -sk "https://10.48.200.110:8882/api/system/version" -H "Cookie: ncpx_session=$TOKEN"
|
||||
```
|
||||
|
||||
## Tools in /tmp/novacpx/tools/
|
||||
|
||||
| Script | Purpose | Usage |
|
||||
|--------|---------|-------|
|
||||
| `nova-ssh.sh` | SSH into VM (double-hop via PVE1 — currently broken) | Use direct SSH instead |
|
||||
| `nova-push.sh` | Push single file via base64/double-hop (broken) | Use direct scp instead |
|
||||
| `nova-deploy.sh` | Full panel rsync (PVE1 hop — broken) | Use direct scp or git push |
|
||||
| `nova-status.sh` | Check SSH + port health | `bash tools/nova-status.sh [--full]` |
|
||||
| `nova-logs.sh` | Stream VM logs | `bash tools/nova-logs.sh [apache\|access\|install\|fail2ban\|all]` |
|
||||
| `nova-db.sh` | Run queries on VM DB | `bash tools/nova-db.sh [--tables\|--users\|--reset-admin pw\|"SQL"]` |
|
||||
|
||||
## Key VM paths
|
||||
- Panel web root: `/srv/novacpx/public/`
|
||||
- Git repo (source): `/opt/novacpx-src/` (what gets pulled by webhook/deploy-runner.sh)
|
||||
- Config: `/etc/novacpx/config.ini` (root:www-data 640)
|
||||
- DB: `/var/lib/novacpx/panel.db` (SQLite)
|
||||
- Deploy runner: `/opt/novacpx-src/deploy/deploy-runner.sh` (cron runs every min)
|
||||
- Webhook: `/opt/novacpx-src/deploy/webhook.php` (linked at /srv/novacpx/public/deploy/webhook.php)
|
||||
- Logs: `/var/log/apache2/error.log`, `/var/log/novacpx/access.log`, `/var/log/novacpx/deploy.log`
|
||||
- JARVIS agent: `/opt/jarvis-agent/`
|
||||
- Cron scripts: `/srv/novacpx/public/bin/` (cache-update-check.php, collect-stats.php, notify-checks.php)
|
||||
|
||||
## VM credentials
|
||||
- VM IP: 10.48.200.110 (PVE1 VM 120)
|
||||
- Root: `root / Joker1974!!!`
|
||||
- Admin panel: `admin / Admin2026!`
|
||||
- MySQL (customer sites): `novacpx_user / 6fyWj6vYnJDKEQvNANzj`
|
||||
- Ports: 8880 (user), 8881 (reseller), 8882 (admin), 8883 (webmail)
|
||||
|
||||
**Why:** [[project-novacpx-todo]]
|
||||
**How to apply:** Start every NovaCPX session by running the session-start checklist so you know immediately if the VM is reachable before writing code.
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
name: project-parkerslingshotrentals
|
||||
description: "parkerslingshotrentals.com — Polaris Slingshot rental site on DO 165.22.1.228; booking system, waiver, admin portal, Square payment pending"
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: project
|
||||
originSessionId: 002fe81e-7e03-414d-b842-1f94f1390a22
|
||||
---
|
||||
|
||||
Parker County Slingshot Rentals — LIVE at https://www.parkerslingshotrentals.com (DO 165.22.1.228, CyberPanel).
|
||||
Deploy path: `/home/parkerslingshotrentals.com/public_html/`
|
||||
|
||||
**Why:** Single-vehicle slingshot rental business in Weatherford, TX. Needs online booking, waiver, payments, and admin management.
|
||||
|
||||
## Credentials
|
||||
- Admin portal: /admin/index.php — user: admin / pass: Parker2026! (URL-token auth, no cookies)
|
||||
- DB: park_slingshot / park_slingshotuser / 4@rxg*8kovxCr7w6 on localhost
|
||||
- Deploy path: /home/parkerslingshotrentals.com/public_html/
|
||||
- SendGrid API key: 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
|
||||
- Square production access token: EAAAl3FsAu_2ri8kZE_ENEyi2T_C8HXXm5XQFY6Lbnd8SX6FqYp8J_upUeXNYh7v
|
||||
- Square application ID: sq0idp-YSM7BU9IVyOWSzpeP-0nzQ
|
||||
- GitHub repo: myronblair/parkerslingshotrentals
|
||||
|
||||
## Admin login fix
|
||||
PHP sessions were unreliable (LiteSpeed page caching + session dir permissions).
|
||||
Replaced with HMAC-signed cookie auth — no session files needed.
|
||||
Admin .htaccess has CacheEnable off.
|
||||
|
||||
## Packages
|
||||
- half-day: $99 / 4 hrs
|
||||
- full-day: $169 / 8 hrs
|
||||
- weekend: $299 / 48 hrs
|
||||
|
||||
## Booking flow (6 steps tracked in admin)
|
||||
1. Booking submitted (auto)
|
||||
2. Booking confirmed (status dropdown)
|
||||
3. Waiver signed (waiver.php?ref=PSR-XXXXXX — canvas e-signature)
|
||||
4. Insurance verified (admin toggle)
|
||||
5. Deposit received (admin toggle)
|
||||
6. License verified (admin toggle at pickup)
|
||||
|
||||
## Pending tasks
|
||||
- Task #3: Square deposit payment integration (credentials above)
|
||||
- Task #6: Vehicle photos (waiting on user)
|
||||
@@ -0,0 +1,42 @@
|
||||
---
|
||||
name: proxmox-backup
|
||||
description: "Proxmox PVE1/PVE2 config backup to GitHub — weekly cron, restore script, repo structure"
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: project
|
||||
originSessionId: c454fc50-f93d-4ddd-b9f3-f3f442e89fb9
|
||||
---
|
||||
|
||||
GitHub repo `myronblair/proxmox-config` (private) — full config backup + disaster recovery.
|
||||
|
||||
**Why:** So both Proxmox nodes can be rebuilt quickly from scratch after hardware failure without losing VM configs, network, custom scripts, or services.
|
||||
|
||||
**How to apply:** Reference this when discussing Proxmox maintenance, DR planning, or if a node goes down.
|
||||
|
||||
## Repo Structure
|
||||
- `shared/` — cluster-wide: all VM/LXC .conf files, storage.cfg, datacenter.cfg, user.cfg, corosync.conf, jobs.cfg, firewall, ha, sdn
|
||||
- `pve/` — PVE1 (10.48.200.90): network, cron, scripts, systemd (filebrowser, jarvis-agent, ollama), ssh/authorized_keys
|
||||
- `pve2/` — PVE2 (10.48.200.91): network, cron, scripts (just pve-remove-nag.sh), systemd (jarvis-agent)
|
||||
- `backup.sh` — runs on each node, pulls repo, collects files, commits+pushes
|
||||
- `restore.sh pve1|pve2` — interactive disaster recovery wizard
|
||||
|
||||
## Schedule
|
||||
Weekly cron on both nodes: `0 3 * * 0 /usr/local/bin/proxmox-backup >> /var/log/proxmox-backup.log 2>&1`
|
||||
|
||||
## Manual trigger
|
||||
`/usr/local/bin/proxmox-backup` on either node
|
||||
|
||||
## What's NOT backed up (intentional)
|
||||
- `/etc/pve/priv/` — CA private key, cluster auth keys (Proxmox regenerates these)
|
||||
- SSH private keys
|
||||
- Large binaries: ollama, filebrowser, blockalign, urbackupclientctl
|
||||
- VM disk images → covered by PBS at 10.48.200.85
|
||||
|
||||
## Restore flow
|
||||
1. Fresh Proxmox install → set hostname + IP
|
||||
2. `apt install git && git clone https://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@github.com/myronblair/proxmox-config.git /opt/proxmox-config`
|
||||
3. `bash /opt/proxmox-config/restore.sh pve1` (interactive, confirms each step)
|
||||
4. Reboot for network, then restore VMs from PBS
|
||||
|
||||
## PVE2 disk space issue (2026-06-09)
|
||||
PVE2 was at 100% disk — removed old kernels to free ~9GB. Now at 96% (4.4GB free). Worth monitoring.
|
||||
@@ -0,0 +1,49 @@
|
||||
---
|
||||
name: project-smtp-credentials
|
||||
description: SMTP and email credentials for all websites — CyberMail API, verified 2026-06-06
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: reference
|
||||
originSessionId: f0b18417-cc26-4fdf-87ec-7b2d69b02c44
|
||||
---
|
||||
|
||||
## CyberMail Account (all sites)
|
||||
- **Dashboard:** https://platform.cyberpersons.com
|
||||
- **API Key (all sites):** `sk_live_7f9b0f9a29f6de31a0d229d4af75d56b094ad724fc58a57d`
|
||||
- **Send Endpoint:** `POST https://platform.cyberpersons.com/email/v1/send`
|
||||
- **Auth:** `Authorization: Bearer {api_key}`
|
||||
- **DO blocks SMTP port 587** — use API over HTTPS (port 443) for all DO-hosted sites
|
||||
- **Last verified:** 2026-06-06 — live test send confirmed, all 5 sites checked
|
||||
|
||||
---
|
||||
|
||||
## tomsjavajive.com — CyberMail ✅ LIVE (verified 2026-06-06)
|
||||
- **From:** noreply@tomsjavajive.com
|
||||
- **Key stored in:** `settings` DB table, key `cybermail_api_key`
|
||||
- **getSetting()** reads from `settings` table (setting_key / setting_value columns) — NOT site_settings
|
||||
- **Mailer:** `includes/functions.php` → `sendEmail()` calls CyberMail API
|
||||
- **Fixed 2026-06-06:** `email_cybermail` setting had `"api_key":"Joker1974!!!"` (wrong) — corrected to real API key
|
||||
- **Note:** TJJ admin UI (admin/emails.php, admin/integrations.php) still shows SendGrid help links — cosmetic only
|
||||
|
||||
## tomtomgames.com — CyberMail ✅ LIVE (verified 2026-06-06)
|
||||
- **From:** noreply@tomtomgames.com
|
||||
- **Key stored in:** `includes/config.php` as `CYBERMAIL_API_KEY` constant
|
||||
- **Mailer:** `includes/mailer.php` → `cybermailSend()` | alias: `sendgridSend()`
|
||||
- **SMTP constants also defined** (SMTP_HOST, SMTP_USER, SMTP_PASS) for fallback reference
|
||||
|
||||
## epictravelexpeditions.com — CyberMail ✅ LIVE (verified 2026-06-06)
|
||||
- **From:** noreply@orbishosting.com (sends via orbishosting.com domain)
|
||||
- **Key stored in:** `/home/epictravelexpeditions.com/public_html/api/config.php` (gitignored)
|
||||
- **Mailer:** `api/includes/mailer.php` → `sendgridSend()` (name kept for compat, calls CyberMail)
|
||||
|
||||
## parkerslingshotrentals.com — CyberMail ✅ LIVE (verified 2026-06-06)
|
||||
- **From:** noreply@orbishosting.com
|
||||
- **Key stored in:** `/home/parkerslingshotrentals.com/public_html/db.php` (in git)
|
||||
- **sendEmail()** in db.php calls CyberMail API directly
|
||||
|
||||
## orbishosting.com / jarvis / orbis — No transactional email
|
||||
|
||||
---
|
||||
|
||||
## GitHub Repo
|
||||
**myronblair/smtp-for-websites** (private, master branch) — credentials reference archive
|
||||
@@ -0,0 +1,104 @@
|
||||
---
|
||||
name: project-tomsjavajive
|
||||
description: Tom's Java Jive coffee shop e-commerce — DB creds, admin portal map, known schema quirks, and fixed bugs
|
||||
metadata:
|
||||
type: project
|
||||
originSessionId: 002fe81e-7e03-414d-b842-1f94f1390a22
|
||||
---
|
||||
|
||||
PHP e-commerce site for a Fort Worth coffee shop. On DO server 165.22.1.228.
|
||||
|
||||
## Credentials & Access
|
||||
- **SSH:** root / Gonewalk1974!@# @ 165.22.1.228
|
||||
- **DB:** toms_tjj_db / toms_tjj_user / +60wlPc+55e@gFq4 (localhost)
|
||||
- **Admin login:** `admin@tomsjavajive.com / Joker1974!!!` OR `myronblair@outlook.com / Joker1974!!!` (both work, reset 2026-06-14)
|
||||
- **Stripe:** placeholder keys in config (test mode — real keys must be added manually)
|
||||
- **GitHub:** myronblair/tomsjavajive (private)
|
||||
|
||||
## File Structure
|
||||
```
|
||||
/home/tomsjavajive.com/public_html/
|
||||
admin/ — admin portal
|
||||
includes/header.php — nav (Content group: Splash Box, About Us Text; Catalog group: Import/Export at bottom)
|
||||
customers.php — customer CRUD + wallet adjust
|
||||
reviews.php — review list + inline edit modal with star picker
|
||||
splashes.php — Homepage splash blocks CRUD (drag-drop image upload, icon picker, drag-to-reorder)
|
||||
about-us.php — About Us text CRUD (live preview, paragraph-aware)
|
||||
import-export.php — Inventory export CSV + import CSV (smart/replace) + inline table editing
|
||||
api/upload-splash.php — handles splash image uploads → /uploads/splashes/
|
||||
api/ — backend API endpoints
|
||||
account/ — customer-facing portal
|
||||
wishlist.php
|
||||
rewards.php
|
||||
reviews.php
|
||||
config/
|
||||
config.php — site config (Stripe, SendGrid, etc.) — in git
|
||||
database.php — DB credentials — GITIGNORED
|
||||
includes/ — shared PHP includes
|
||||
uploads/splashes/ — splash block images (owned nobody:nobody, 755)
|
||||
```
|
||||
|
||||
## Database Schema Notes
|
||||
- **products table:** no `slug` column — product URLs use `?id=product_id` (not `?slug=`)
|
||||
- **wallet_transactions.type enum:** deposit, withdrawal, purchase, refund, reward, loyalty_redemption, credit, debit
|
||||
- **loyalty_transactions.type enum:** earn, redeem, adjustment, birthday_bonus, referral_bonus, referral_welcome, tier_upgrade
|
||||
- **customers table:** has `lifetime_points` (INT) and `loyalty_tier` (VARCHAR 20) columns added 2026-05-22
|
||||
- **Collation:** ALL tables must be utf8mb4_unicode_ci — mixed collation (general_ci vs unicode_ci) causes JOIN errors (MySQL 1267)
|
||||
|
||||
## Admin Nav Groups
|
||||
- **Dashboard** — dashboard.php
|
||||
- **Catalog** — products, categories, inventory, import-export
|
||||
- **Orders** — orders, fulfillment
|
||||
- **Customers** — customers, reviews
|
||||
- **Content** — splashes (Splash Box), about-us (About Us Text)
|
||||
- **Analytics, Settings, etc.**
|
||||
|
||||
## Homepage DB-Driven Sections
|
||||
- **Splash blocks:** `homepage_splashes` table → feature cards above products (scrollable if >4)
|
||||
- **About Us text:** `about_us_sections` table → paragraphs under "Our Story" heading
|
||||
|
||||
## Google Merchant Feed — Fixed 2026-06-17
|
||||
- Feed URL: `https://tomsjavajive.com/merchant-feed.php`
|
||||
- Title was being built as `$p['name'] . ' ' . $categoryLabel . ' Coffee'` — doubled the suffix for products whose names already include "Whole Bean Coffee" / "Ground Coffee"
|
||||
- Fix: title now uses `$p['name']` as-is, matching exactly what's shown on the site
|
||||
- Products are approved in Google Merchant Center
|
||||
|
||||
## Known Bugs Fixed (2026-05-22)
|
||||
- `p.slug` in wishlist/reviews queries → replaced with `p.product_id`, URLs use `?id=`
|
||||
- `wallet_transactions` adjust_wallet used wrong enum values (credit/debit) → fixed to deposit/withdrawal
|
||||
- `reviews` table uses `comment` (not `content`) and `is_approved` (not `status`)
|
||||
- `rewards.php` crashed because `lifetime_points`/`loyalty_tier` didn't exist → added via ALTER TABLE
|
||||
- Collation mismatch on wishlist, loyalty_transactions, loyalty_tiers, product_types, loyalty_settings → all converted to unicode_ci
|
||||
|
||||
## Pages Added (2026-06-04)
|
||||
- `faq.php` — accordion FAQ: Orders & Payment, Coffee & Products, Coffee Freshness & Storage, Account & Loyalty
|
||||
- `shipping.php` — rates table (3–5 days standard after processing), "every order made fresh to ship" messaging
|
||||
- `returns.php` — three-tier policy: Your Responsibility / Our Responsibility / Shared Responsibility (covers coffee cost up to $25 on shared issues)
|
||||
- `returns.php` — adapted from DripShipper policy language
|
||||
- `track-order.php` — lookup by order_number + email; shows progress stepper, tracking number/link, items, shipping address; logged-in users see recent orders
|
||||
- `privacy.php` — full privacy policy adapted from DripShipper; GDPR section, children's info, log files, third-party cookies
|
||||
- `includes/footer.php` — Privacy Policy link added to Support section
|
||||
|
||||
## Email (CyberMail) — Fixed 2026-06-14
|
||||
- API key: `sk_live_7f9b0f9a29f6de31a0d229d4af75d56b094ad724fc58a57d` (stored in DB as `cybermail_api_key`)
|
||||
- From email: `noreply@tomsjavajive.com` (stored as `cybermail_from_email`)
|
||||
- From name: `Toms Java Jive` (stored as `cybermail_from_name`)
|
||||
- **CyberMail API requires separate `from` and `from_name` fields** — NOT the combined `Name <email>` format. Using `Name <email>` in the `from` field returns "Invalid 'from' email address" error.
|
||||
- Fixed in: `includes/email.php` (Email class send method) and `includes/functions.php` (sendEmail function)
|
||||
|
||||
## Product Image Upload — Fixed 2026-06-14
|
||||
- Upload endpoint: `/admin/upload-image.php`
|
||||
- Saved to: `/uploads/products/` (must be owned by `tomsj4710:nogroup`, chmod 755)
|
||||
- **Do NOT include `header.php` in upload-image.php** — it outputs full HTML which breaks JSON response
|
||||
- Upload-image.php uses `require_once '../includes/auth.php'` + `AdminAuth::getUser()` check directly
|
||||
- JS in product-edit.php uses `fetch('/admin/upload-image.php', {credentials: 'same-origin', ...})`
|
||||
- Textarea for image URLs must be `name="image_urls"` (form handler reads `$_POST['image_urls']`)
|
||||
|
||||
## CSV Import — Fixed 2026-06-14
|
||||
- `tags`, `images`, `dimensions` columns have MySQL `CHECK (json_valid())` constraints
|
||||
- CSV cells with plain text (e.g. `coffee,dark roast`) or plain URLs must be converted to JSON arrays before insert
|
||||
- `toJsonField()` helper in import-export.php handles: already-valid JSON (pass-through), comma-separated → JSON array, empty → NULL
|
||||
- Always wrap `$r['tags']` and `$r['images']` with `toJsonField()` in any import code
|
||||
|
||||
**Why:** Reference when debugging or extending Tom's Java Jive.
|
||||
**How to apply:** Always check these schema quirks before writing new queries against this DB.
|
||||
@@ -0,0 +1,65 @@
|
||||
---
|
||||
name: project-tomsjavajive-email
|
||||
description: "Tom's Java Jive email service — CyberMail (CyberPersons), API key stored in config.php"
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: project
|
||||
originSessionId: f0b18417-cc26-4fdf-87ec-7b2d69b02c44
|
||||
---
|
||||
|
||||
## Email Service: CyberMail by CyberPersons
|
||||
|
||||
**API Key:** `sk_live_d52bf062797105aeaafac9954c21ff988e9b41b77315807d`
|
||||
**API Key Management:** https://platform.cyberpersons.com/email/api-keys/
|
||||
**Webmail / Hosting Management:** https://platform.cyberpersons.com/email/webmail/hosting/
|
||||
|
||||
**Stored in:** `/home/tomsjavajive.com/public_html/config/config.php`
|
||||
- Constant: `CYBERMAIL_API_KEY`
|
||||
- Replaced the old `SENDGRID_API_KEY` placeholder
|
||||
|
||||
## Email Handler
|
||||
- File: `/home/tomsjavajive.com/public_html/includes/email.php`
|
||||
- Class: `SendGridEmail` (still named SendGrid — rename when integrating CyberMail API)
|
||||
- Sends: order confirmation, shipping notification, password reset, welcome, abandoned cart
|
||||
- Currently references `CYBERMAIL_API_KEY` constant (was SENDGRID_API_KEY)
|
||||
|
||||
## CyberMail API Reference
|
||||
- **Send:** `POST https://platform.cyberpersons.com/email/v1/send`
|
||||
- **Status:** `GET https://platform.cyberpersons.com/email/v1/messages/{message_id}`
|
||||
- **Account Stats:** `GET https://platform.cyberpersons.com/email/v1/account/stats`
|
||||
- **Auth:** `Authorization: Bearer {api_key}`
|
||||
|
||||
## Error Codes
|
||||
| HTTP | error.type | Description |
|
||||
|------|-----------|-------------|
|
||||
| 400 | invalid_request | Missing required fields or invalid email format |
|
||||
| 403 | domain_not_verified | Sending domain not verified |
|
||||
| 403 | domain_not_found | Domain not registered to account |
|
||||
| 403 | account_inactive | Account suspended or inactive |
|
||||
| 403 | forbidden | API key domain/IP restriction |
|
||||
| 404 | not_found | Message ID not found |
|
||||
| 429 | rate_limit_exceeded | Rate limit reached (includes retry_after field) |
|
||||
| 500 | send_failed | Sending failed after failover |
|
||||
| 503 | service_unavailable | No healthy mail nodes |
|
||||
|
||||
## PHP Integration
|
||||
- `email.php` uses `Authorization: Bearer` header, curl over HTTPS (port 443 — no DO block)
|
||||
- Success returns `['success'=>true, 'message_id'=>'...']`
|
||||
- Failure returns `['success'=>false, 'error'=>'friendly message', 'error_type'=>'code', 'code'=>httpCode]`
|
||||
- 429 errors include retry_after seconds in the error message
|
||||
- **Required fields:** `from`, `to`, `subject`, `html` (or `text`)
|
||||
- **Optional:** `text`, `cc`, `bcc`, `reply_to`, `tags`, `metadata`, `headers`
|
||||
- **Success response:** 202 with `data.message_id`, `data.status`
|
||||
- **Domain must be verified** at platform.cyberpersons.com before sending
|
||||
|
||||
## SMTP Credentials (blocked by DigitalOcean — use API instead)
|
||||
- Host: mail.cyberpersons.com | Port: 587 | Security: STARTTLS
|
||||
- Username: `smtp_49a1fa9c0f15d2d7`
|
||||
- Password: `T3mOFSMK1SG1l4D1d7N8NefRd8xypwMy`
|
||||
- DO blocks outbound port 587 — API over HTTPS is the working approach
|
||||
|
||||
## Current Status
|
||||
- email.php rewritten to use CyberMail API (curl over HTTPS port 443)
|
||||
- `SendGridEmail` class renamed to `Email`, `sendEmail()` helper unchanged
|
||||
- Blocked by: `tomsjavajive.com` domain not verified in CyberMail dashboard
|
||||
- Fix: verify domain at platform.cyberpersons.com (add DNS TXT/CNAME records)
|
||||
@@ -0,0 +1,30 @@
|
||||
---
|
||||
name: project-tomtomgames-email
|
||||
description: "TomTomGames email service — CyberMail API + SMTP, same API key as tomsjavajive"
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: project
|
||||
originSessionId: f0b18417-cc26-4fdf-87ec-7b2d69b02c44
|
||||
---
|
||||
|
||||
## Email Service: CyberMail (same account as tomsjavajive.com)
|
||||
|
||||
**API Key:** `sk_live_7f9b0f9a29f6de31a0d229d4af75d56b094ad724fc58a57d` (verified working 2026-06-06)
|
||||
**SMTP Host:** mail.cyberpersons.com | Port: 587 | Security: STARTTLS
|
||||
**SMTP Username:** `smtp_ad34c4d915da7bfc`
|
||||
**SMTP Password:** `m47o2-UqPgM-IBeYNRz-uHSJAHnPGe9w`
|
||||
**From:** noreply@tomtomgames.com
|
||||
|
||||
## Files Updated
|
||||
- `/home/tomtomgames.com/includes/config.php` — CYBERMAIL_API_KEY + SMTP constants
|
||||
- `/home/tomtomgames.com/includes/mailer.php` — rewritten to use CyberMail API via cybermailSend()
|
||||
- `/home/tomtomgames.com/public_html/api/admin.php` — mail() replaced with cybermailSend()
|
||||
|
||||
## Email Functions
|
||||
- `cybermailSend($to, $name, $subject, $text, $html, $tags)` — primary send function
|
||||
- `sendgridSend()` — kept as alias (calls cybermailSend) for backward compatibility
|
||||
- `sendVerificationEmail($email, $alias, $token)` — registration/resend verification
|
||||
|
||||
## Emails Sent
|
||||
- Account verification (registration + resend)
|
||||
- Password reset (admin.php)
|
||||
@@ -0,0 +1,33 @@
|
||||
---
|
||||
name: project-webserver
|
||||
description: CyberPanel/OpenLiteSpeed DO server at 165.22.1.228 hosting tomsjavajive.com and 5 other sites
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: project
|
||||
originSessionId: 002fe81e-7e03-414d-b842-1f94f1390a22
|
||||
---
|
||||
|
||||
CyberPanel server running OpenLiteSpeed + MariaDB + PHP (lsphp).
|
||||
|
||||
**SSH:** root / Gonewalk1974!@# @ 165.22.1.228
|
||||
|
||||
**Sites hosted** (all under /home/<domain>/public_html/):
|
||||
- tomsjavajive.com — coffee shop e-commerce (PHP, custom built, Stripe, loyalty/rewards)
|
||||
- epictravelexpeditions.com
|
||||
- orbishosting.com — email only via CyberPanel; no local site (forwarded/maintained elsewhere — do NOT treat as a stub needing a site built)
|
||||
- orbis.orbishosting.com
|
||||
- parkerslingshotrentals.com
|
||||
- tomtomgames.com
|
||||
|
||||
**Stack:** OpenLiteSpeed, MariaDB 10.11, PHP (lsphp), Redis, Memcached, PowerDNS, Postfix/Dovecot, CyberPanel
|
||||
|
||||
**tomsjavajive.com structure:**
|
||||
- /home/tomsjavajive.com/public_html/
|
||||
- admin/ — admin portal (dashboard, products, orders, customers, analytics, etc.)
|
||||
- api/ — backend API endpoints
|
||||
- account/ — customer account pages
|
||||
- config/ — config.php, database.php
|
||||
- includes/ — shared PHP includes
|
||||
|
||||
**Why:** IP changed from 206.189.229.53 to 165.22.1.228 as of 2026-05-22.
|
||||
**How to apply:** Use 165.22.1.228 for all SSH access to these sites.
|
||||
@@ -0,0 +1,69 @@
|
||||
---
|
||||
name: project-yealink-phones
|
||||
description: Complete Yealink phone inventory — 5 physical phones (T48S/T57W/AX86R) + 3 voicemail-only virtual extensions on FusionPBX
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: project
|
||||
originSessionId: 5419c63f-5e28-41c3-9055-3d9a33550b52
|
||||
---
|
||||
|
||||
## Physical Phones
|
||||
|
||||
| IP | MAC | Model | Label | Ext | Status |
|
||||
|----|-----|-------|-------|-----|--------|
|
||||
| 10.48.200.2 | `80:5e:c0:35:04:77` | T48S | Myron Blair Desk Phone | 1000 | Online |
|
||||
| 10.48.200.43 | `80:5e:0c:15:0c:4f` | T48S | Tommy Ivy Desk Phone | 1001 | Online |
|
||||
| 10.48.200.65 | `c4:fc:22:13:e1:89` | AX86R | Myron Blair AX86 WiFi Work Phone | 1002 | Online |
|
||||
| 10.48.200.83 | `80:5e:0c:e9:44:f8` | T57W | Kitchen Phone | 1003 | Online |
|
||||
| 10.48.200.85 | `80:5e:0c:30:75:96` | T57W | Master Bedroom Phone | 1004 | Online |
|
||||
| 10.48.200.3 | `c4:fc:22:28:63:71` | T57W | United Mirror & Glass | External SIP | Online |
|
||||
|
||||
## Virtual Extensions (Voicemail Only — No Physical Phone)
|
||||
|
||||
| Ext | Name |
|
||||
|-----|------|
|
||||
| 1010 | Parker County Slingshot |
|
||||
| 1011 | Epic Travel Expeditions |
|
||||
| 1012 | Tom's Java Jive |
|
||||
|
||||
## IVR
|
||||
|
||||
| Ext | Purpose |
|
||||
|-----|---------|
|
||||
| 900 | Auto-attendant (IVR) |
|
||||
|
||||
## SIP Credentials
|
||||
|
||||
| Ext | SIP Password |
|
||||
|-----|-------------|
|
||||
| 1000 | `Xk9mPw3nQv7rLs2t` |
|
||||
| 1001 | `Tv8xNm4pWq6rZs3k` |
|
||||
| 1002 | `yXHaJTwa8rj?$GkrVFQB` |
|
||||
|
||||
## FusionPBX Connection
|
||||
|
||||
- Server: `134.209.72.226`, Port: `5080`, Transport: UDP
|
||||
- SSH: relay through DO (`165.22.1.228`) → FusionPBX (`134.209.72.226`)
|
||||
- Web: `https://fusion.orbishosting.com` (admin / fY7XP5swgtpbzrYLhkeVYkA4744)
|
||||
- Provisioning URL: `https://fusion.orbishosting.com/app/provision/` (provision-master / Joker1974!!!)
|
||||
|
||||
## Yealink Web UI Login
|
||||
|
||||
T48S phones use RSA-encrypted password login (PKCS#1 v1.5). T57W uses HTTPS on port 8080.
|
||||
|
||||
- After factory reset, provisioning URL is cleared — must re-enter manually on phone
|
||||
- Path: Menu → Settings → Advanced → Auto Provision
|
||||
- To re-provision without reboot: Menu → Settings → Advanced → Auto Provision → Update Now
|
||||
|
||||
## BLF Buttons (confirmed working 2026-05-29)
|
||||
|
||||
- Device profile "yealink" (UUID 2c68fe07-b29a-4429-a3c2-7ce9010c69ff)
|
||||
- 10 BLF keys, type=16 in FusionPBX
|
||||
- Buttons: Myron 1000, Tommy 1001, Myron-WkPh 1002, Kitchen 1003, Bedroom 1004, PC Slingshot 1010, Park 5901/5902/5903, Page All
|
||||
|
||||
## Key Notes
|
||||
|
||||
- `manage-presence = true` set in FreeSWITCH external sofia profile (DB-managed)
|
||||
- BLF type=16 required in FusionPBX (pickup_value required)
|
||||
- `overwrite_mode=1` required in provisioning
|
||||
- AVOID: `sofia profile external restart` — drops all registrations
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
name: user-cryptex
|
||||
description: Physical Cryptex safe combination key — 3D printed on Creality K2 Pro
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: user
|
||||
originSessionId: b1e93a6a-f101-4ea4-aafb-9cb7e2958821
|
||||
---
|
||||
|
||||
**Cryptex safe key:** `NEBYMJ`
|
||||
|
||||
Printed on Creality K2 Pro. Physical combination lock safe.
|
||||
@@ -1,75 +0,0 @@
|
||||
# FusionPBX Custom Configs (134.209.72.226)
|
||||
|
||||
## Yealink T48S Provisioning — Critical Fixes
|
||||
|
||||
### Problem: BLF buttons never applied from provisioning
|
||||
Root cause: nginx rewrite for `{mac}.boot` stripped the `file=` param, so FusionPBX
|
||||
served the full 122KB config as a boot file. Yealink ignores DSS keys in .boot files —
|
||||
they only apply from .cfg files.
|
||||
|
||||
### Fix 1: nginx rewrite (in /etc/nginx/sites-enabled/fusionpbx)
|
||||
OLD: rewrite "^.*/provision/([A-Fa-f0-9]{12})(\.boot)$" /app/provision/index.php?mac=$1;
|
||||
NEW: rewrite "^.*/provision/([A-Fa-f0-9]{12})(\.boot)$" /app/provision/index.php?mac=$1&file=%7b%24mac%7d.boot;
|
||||
|
||||
### Fix 2: {$mac}.boot template
|
||||
Created: /var/www/fusionpbx/resources/templates/provision/yealink/t48s/{$mac}.boot
|
||||
Content: boot file with includes pointing to y000000000065.cfg and {$mac}.cfg
|
||||
Phone flow: {mac}.boot (164 bytes) → y000000000065.cfg → {mac}.cfg (full config applied)
|
||||
|
||||
### Fix 3: y000000000065.cfg template changes
|
||||
- features.auto_linekeys.enable = 0 (prevents phone overriding BLF keys)
|
||||
|
||||
### Fix 4: All y000000000000.boot templates
|
||||
- overwrite_mode = 1 (forces re-provision on every reboot, default was 0)
|
||||
|
||||
### Fix 5: External sofia profile
|
||||
- manage-presence = passive (not true — BLF SUBSCRIBEs delegate to internal profile)
|
||||
- Fix: UPDATE v_sip_profile_settings SET value='passive' WHERE profile=external AND name='manage-presence'
|
||||
- Then delete /var/cache/fusionpbx/FusionPBX.configuration.sofia.conf and reload sofia
|
||||
|
||||
## Device Profile "yealink" (UUID 2c68fe07-b29a-4429-a3c2-7ce9010c69ff)
|
||||
|
||||
| Key | Type | Value | Label | Notes |
|
||||
|-----|------|-------|-------|-------|
|
||||
| 1 | 16 (BLF) | 1000 | Myron 1000 | |
|
||||
| 2 | 16 (BLF) | 1001 | Tommy 1001 | |
|
||||
| 3 | 16 (BLF) | 1002 | Myron Vanguard | |
|
||||
| 4 | 12 | 1003 | PC Slingshot | |
|
||||
| 5 | 12 | 1004 | Epic Travel | |
|
||||
| 6 | 12 | 1005 | Toms Java | |
|
||||
| 7 | 13 (Speed Dial) | *5901 | Park 5901 | Press during call=park, idle=retrieve |
|
||||
| 8 | 13 (Speed Dial) | *5902 | Park 5902 | |
|
||||
| 9 | 13 (Speed Dial) | *5903 | Park 5903 | |
|
||||
| 11 | 16 (BLF) | *724 | Page All | |
|
||||
|
||||
Park buttons use Speed Dial (type=13) not BLF — BLF for park requires mod_presence
|
||||
which is not installed. Speed Dial works: press during call parks it, press idle retrieves.
|
||||
|
||||
## BLF Type Reference (Yealink T48S firmware 66.86.x, FusionPBX)
|
||||
- type=16 = BLF (requires pickup_value field in template)
|
||||
- type=13 = Speed Dial
|
||||
- type=12 = (user-defined)
|
||||
- type=1 = Line
|
||||
|
||||
## Provisioning URL
|
||||
- Server: https://fusion.orbishosting.com/app/provision/
|
||||
- Auth: provision-master / Joker1974!!! (Digest)
|
||||
- After factory reset: must re-enter manually via Menu > Settings > Advanced > Auto Provision
|
||||
- Firmware 66.86.0.15: requires power cycle after "Update Now" to register
|
||||
|
||||
## fail2ban Whitelist (/etc/fail2ban/jail.local)
|
||||
- 107.178.2.130 (office)
|
||||
- 97.154.109.245 (home WAN)
|
||||
|
||||
## Phones
|
||||
- Ext 1000 (Myron): MAC 805ec0350477, firmware 66.86.0.15, IP 10.48.200.2
|
||||
- Ext 1001 (Tommy): MAC 805e0c150c4f, firmware 66.86.0.160, IP 10.48.200.43
|
||||
|
||||
## IVR Audio
|
||||
- /var/lib/freeswitch/recordings/134.209.72.226/ivr_menu.wav
|
||||
- American male voice (Festival TTS), 27s, 8kHz 16-bit mono PCM
|
||||
|
||||
## mod_presence
|
||||
- NOT installed — FreeSWITCH built from source at /usr/src/freeswitch-1.11/
|
||||
- Basic extension BLF works via manage-presence=true on internal sofia profile
|
||||
- Park slot BLF would require mod_presence — workaround: Speed Dial buttons
|
||||
@@ -1,10 +0,0 @@
|
||||
[DEFAULT]
|
||||
ignoreip = 127.0.0.1/8 ::1 107.178.2.130 97.154.109.245
|
||||
|
||||
[ssh]
|
||||
enabled = true
|
||||
port = 22
|
||||
protocol = ssh
|
||||
filter = sshd
|
||||
logpath = /var/log/auth.log
|
||||
action = iptables-allports[name=sshd, protocol=all]
|
||||
@@ -1,9 +0,0 @@
|
||||
# In /etc/nginx/sites-enabled/fusionpbx
|
||||
# Critical fix: pass file= param so FusionPBX returns a boot file (not full config)
|
||||
# Phone ignores DSS/BLF keys when received in a .boot file — must come from .cfg
|
||||
|
||||
# CORRECT:
|
||||
rewrite "^.*/provision/([A-Fa-f0-9]{12})(\.boot)$" /app/provision/index.php?mac=$1&file=%7b%24mac%7d.boot;
|
||||
|
||||
# WRONG (original — serves full 122KB config as .boot, phone ignores linekeys):
|
||||
# rewrite "^.*/provision/([A-Fa-f0-9]{12})(\.boot)$" /app/provision/index.php?mac=$1;
|
||||
@@ -1,7 +0,0 @@
|
||||
#!version:1.0.0.1
|
||||
## The header above must appear as-is in the first line
|
||||
|
||||
include:config "y000000000065.cfg"
|
||||
include:config "{$mac}.cfg"
|
||||
|
||||
overwrite_mode = 1
|
||||
@@ -1,7 +0,0 @@
|
||||
#!version:1.0.0.1
|
||||
## The header above must appear as-is in the first line
|
||||
|
||||
include:config "y000000000065.cfg"
|
||||
include:config "{$mac}.cfg"
|
||||
|
||||
overwrite_mode = 1
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
['back_bathroom', 'back_bedroom', 'back_door', 'back_yard', 'camper', 'car', 'car_port', 'dining_room', 'down_hill', 'front_bedroom', 'front_door', 'front_yard', 'garage', 'hallway', 'hdmibroadcast', 'kitchen', 'konnected_alarm', 'living_room', 'master_bedroom', 'office', 'outdoors', 'side_yard', 'storage', 'utility_room']
|
||||
@@ -0,0 +1 @@
|
||||
404: Not Found
|
||||
@@ -0,0 +1 @@
|
||||
404: Not Found
|
||||
@@ -0,0 +1 @@
|
||||
404: Not Found
|
||||
@@ -0,0 +1 @@
|
||||
404: Not Found
|
||||
@@ -0,0 +1 @@
|
||||
404: Not Found
|
||||
Reference in New Issue
Block a user