- install.sh, install-agent.sh: require JARVIS_REG_KEY env var or interactive prompt instead of baked-in key (matches install-mac.sh/install-windows.ps1 behavior) - netscan.php: reuse AGENT_REGISTRATION_KEY constant instead of a duplicate literal - agent.php + api.php: add session-authed "regkey" action so the admin install modal fetches the current key at runtime - jarvis-agents.js: fetch reg key via /api/agent/regkey instead of hardcoding it; pass JARVIS_REG_KEY in the Linux install one-liner - INFRASTRUCTURE-REFERENCE.md: scrub old key literal (rotated; real value lives only in api/config.php on VM211) Key rotated on the box + rolled out to all 11 agents (verified all re-register online). New value is in the gitignored api/config.php only. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
73 KiB
INFRASTRUCTURE REFERENCE — COMPLETE SYSTEM MAP
Last Updated: 2026-07-07 (WAN IP change + FortiGate VIP update; JARVIS auto-deploy pipeline fully restored; admin panel fixes — Works tab, Site Health, Email Intelligence/Outbox; backup systems audited and fixed to include actual data, not just DB/config; new Blair HQ Backup Downloads feature)
Owner: Myron Blair — myronblair@outlook.com
TABLE OF CONTENTS
- Network Overview
- Cloud Servers
- On-Premise — Proxmox Hypervisors
- On-Premise — Virtual Machines
- NAS Storage
- Websites (all on DO)
- JARVIS AI System
- Phone System (FusionPBX)
- Networking & VPN
- Backup Systems
- SSH Quick Reference
- Critical Credentials Master List
- Git & Repository Management
- Network Equipment & Client Device Inventory
1. NETWORK OVERVIEW
INTERNET
│
▼
[Cloudflare CDN] ──────────────────────────────────────────────────────────────
│ (proxied DNS for public sites)
│
├─► [DigitalOcean 165.22.1.228] — CyberPanel/OLS — All websites (7 sites)
│
└─► [FusionPBX 134.209.72.226] — FreeSWITCH PBX (SSH via DO relay)
HOME NETWORK (FortiGate router at 10.48.200.1)
WAN: 97.245.77.197 (dynamic, DDNS: orbisne.fortiddns.com — changed 2026-07-07,
previously 97.154.207.5, and 97.154.109.245 before that. All 35 FortiGate
VIPs' extip updated to match on each change — see Section 9 for the full list.)
│
├─► PVE1 Proxmox 10.48.200.90 (primary hypervisor)
│ ├── VM 101 10.48.200.97 Home Assistant
│ ├── VM 112 10.48.200.33 Jellyfin
│ ├── VM 103 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 106 10.48.200.210 Ollama (local LLM + vision) — llama3.1:8b, llava:7b
│ └── CT110 10.48.200.19/.67 WireGuard exit container (disabled at boot 2026-07-06, legacy/unused)
│
├─► 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 (VIP list confirmed 2026-07-07 via `show firewall vip` — this
replaces the earlier partial/approximate list; all extip values = current WAN IP above):
homeassistant-8123 → 10.48.200.97:8123 (Home Assistant)
proxmox1-8006 → 10.48.200.90:8006 (PVE1 web UI)
proxmox2-8007to8006 → 10.48.200.91:8006 (PVE2 web UI, ext 8007)
proxmoxbku-8007to8008 → 10.48.200.92:8007 (ext 8008)
reolink-9000/1935/554/8000 → 10.48.200.95 (4 VIPs, one per port)
proxmox-ssh-claude-connection → 10.48.200.29:22
jarvis-8443 → 10.48.200.211:80 (JARVIS — working forward, use this for external HTTP to JARVIS)
jarvis-1972 → 10.48.200.211:80 (legacy port, confirmed working again 2026-07-07 after the WAN IP/VIP update — earlier notes calling this "dead" were from before that fix)
tunnel-51820 / Wireguard-CT110 → 10.48.200.67:51821 (UDP, WireGuard — 2 VIPs, same target)
dns-53 → 10.48.200.90:53
bbs-23 → 10.48.200.112:23 (SynchroNet BBS)
NOVACPX-* (18 VIPs) → 10.48.200.110 or .200 — HTTP/HTTPS/user/reseller/admin/webmail/SSH/FTP/SMTP/POP3/IMAP/DNS ports for NovaCPX hosting panel
NPM-HTTP / NPM-HTTPS → 10.48.200.200:80/443 (Nginx Proxy Manager, VM 105)
No VIP maps external port 80 directly to JARVIS — use jarvis-8443 (or the working
jarvis-1972) for external HTTP access instead.
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 (7 sites) — webhook deploy for websites |
Key Paths:
-
All sites:
/home/<domain>/public_html/ -
Deploy log: per-site (website deploys only)
-
Watchdog log:
/usr/local/lsws/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: website deploy runner (every 1 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 | Direct via Tailscale: ssh root@100.74.46.120 — 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:
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:
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 100 — SynchroNet (PVE1)
| Field | Value |
|---|---|
| IP | 10.48.200.112 |
| OS | Windows |
| Purpose | SynchroNet BBS (bulletin board system) |
| Note | VM is named "SynchroNet-50" in Proxmox but its real IP is .112, not .50 — .50 is an unrelated Raspberry Pi 5 hobby device (see Section 14). Confirmed 2026-07-06. |
VM 105 — Nginx Proxy Manager (PVE1)
| Field | Value |
|---|---|
| IP | 10.48.200.200 |
| Purpose | Reverse proxy management (NPM) |
| Note | Confirmed 2026-07-06; VM name NPM-200 matches its IP correctly (unlike SynchroNet/Ollama above). |
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_commandstable → 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 24.04.4 LTS (verified 2026-07-06; previously logged as 22.04 — reinstalled/upgraded at some point) |
| SSH | ssh root@10.48.200.33 — password: Joker1974!!! (enabled 2026-06-14) |
| Web UI | http://10.48.200.33:8096 (Jellyfin 10.11.11) |
| Purpose | Media streaming server — Movies and TV shows |
| JARVIS Agent | jarvis-agent.service running (verified 2026-07-06) |
| Remote access | Tailscale installed, node jellyfin-112 at 100.81.145.48 — used for off-LAN streaming access |
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: 635142c218f2457e813a2de8dec75b05 (regenerated 2026-07-06 — previous token 7c0ccf78... had gone stale/invalid. The account's real username is admin, not myron — confirmed via the Users table in /var/lib/jellyfin/data/jellyfin.db; it's hidden from the public login list, which is why /Users/Public returns empty.)
If library scan needed:
curl -X POST "http://10.48.200.33:8096/Library/Refresh" \
-H "X-Emby-Token: 635142c218f2457e813a2de8dec75b05"
If NFS stale after MediaStack changes:
umount -l /mnt/mediastack/movies && umount -l /mnt/mediastack/tv
mount /mnt/mediastack/movies && mount /mnt/mediastack/tv
VM 103 — MediaStack (PVE1)
| Field | Value |
|---|---|
| IP | 10.48.200.35 |
| OS | Ubuntu 24.04.4 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 |
| Not Docker | Despite the name, all services below run bare-metal via systemd, not docker-compose |
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 rotates (US Dallas servers), not a fixed IP (previous "181.214.226.188" was just a snapshot, not stable). All download/general traffic exits via NordVPN with LAN traffic exempted (Kill Switch + Firewall + LAN Discovery all enabled as of 2026-07-06 — see Section 9 for the full incident/fix history). If downloads stall, check nordvpn status first, then ip rule show for rules 32764/32765/table 205.
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":
systemctl stop radarr
sqlite3 /var/lib/radarr/radarr.db "DELETE FROM IndexerStatus WHERE ProviderId=1;"
systemctl start radarr
SSH from DO:
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 tomain)
VM 106 — Ollama Local LLM + Vision (PVE1)
| Field | Value |
|---|---|
| IP | 10.48.200.210 |
| OS | Ubuntu (cloud image) |
| SSH | ssh root@10.48.200.210 via PVE1 hop — password: Joker1974!!! (also reachable as ssh myron@10.48.200.210 — password Joker1974!, then sudo). VM's name is Ollama-95 but its real IP is .210, not .95 — a prior version of this doc had a stray SSH line pointed at .95 (nothing listens there); confirmed 2026-07-06 that .210 is correct. |
| Purpose | Local AI inference — chat (llama3.1:8b) + vision (llava:7b) |
| API | http://10.48.200.210:11434 (Ollama REST API) |
| JARVIS Agent | ID: ollama-ai_ubuntu |
| Models | llama3.1:8b (chat/Tier 1), llava:7b (vision cascade) |
JARVIS uses this as Tier 1 AI — if Ollama is down, falls back to Groq (cloud).
Vision cascade: Arc Reactor calls Claude first; if Claude credits depleted, falls back to llava:7b via Ollama.
Vision is enabled via: /etc/systemd/system/jarvis-arc.service.d/vision.conf → OLLAMA_VISION_MODEL=llava:7b
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 |
| 2026-07-06 incident | MediaStack's wg0 client for this tunnel (/etc/wireguard/wg0.conf) had a PostUp hook installing its own iptables kill-switch (REJECT all output not via wg0 or marked 51820), and wg-quick@wg0.service was still enabled at boot on MediaStack despite this tunnel being unused — this caused a full LAN/SSH lockout to MediaStack the moment that service came up. Disabled wg-quick@wg0 at boot on MediaStack to prevent recurrence; the tunnel itself and CT110 are untouched. See NordVPN section below for the related (separate) LAN Discovery bug found in the same incident. |
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 and its subpaths /volume1/video/movies, /volume1/video/tv — all exported to MediaStack (10.48.200.35) only, per /etc/exports on the NAS (verified 2026-07-06)
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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 (rotated 2026-07-05 — old PAT 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 was found exposed in .git/config on all 6 original sites and must be treated as compromised/revoked)
jarvis.orbishosting.com — JARVIS AI Dashboard (MOVED TO PVE1 VM 211)
| Field | Value |
|---|---|
| URL | http://jarvis.orbishosting.com (port 80 — old :1972 reference was wrong, corrected 2026-07-04) |
| Path | /var/www/jarvis/ (on JARVIS VM 10.48.200.211) |
| 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.
worktracking.orbishosting.com — ChuckCo Time Keeper
| Field | Value |
|---|---|
| URL | https://worktracking.orbishosting.com |
| Path | /home/worktracking.orbishosting.com/public_html/ |
| GitHub | myronblair/chucko (private) |
| Gitea | myron/chucko (pull-mirror of GitHub) |
| Local clone | C:\Users\myron\repos\chucko on admin Windows machine |
| Purpose | Work-tracking app for a flat-rate 5-day (Fri–Thu) work week — self-reported hours via personal secret-URL tokens (no login), single shared admin password, phone-friendly screenshot pages for texting workers/payer |
| Admin URL | https://worktracking.orbishosting.com/admin/login.php — password Joker1974!!! |
| DB | workt_track_db / workt_track_user / ZWCNMRP2N5NVPsghmve5aRS9 |
| Linked from Blair HQ | web.orbishosting.com dashboard's "Websites" card has direct links to the admin login and the all-workers overview page (site-wide token 972f82cbf7832fdb2cffcdcc84129a4af69e30bd) |
| Note | Built 2026-07-05. includes/config.php (DB creds, admin password hash, site token) lives outside public_html/webroot and is intentionally NOT in the git repo. |
| Admin login rate limiting | Added 2026-07-06 — login_attempts table (ip_address, attempts, last_attempt) in workt_track_db; 5 failed attempts locks that IP out for 15 minutes. |
| Code review (2026-07-06) | 5 findings fixed and deployed: w.php mark_paid now rejects any week_start that isn't the true current week (was trusting client input); admin/worker.php no longer double-HTML-escapes the page title; all.php now shows a Paid/Unpaid badge per worker for the displayed week; s.php/p.php/all.php validate the week param before building dates (malformed input used to throw an uncaught DateTime exception); admin login rate-limited (see above). |
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 |
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) |
CyberMail API key: sk_live_7f9b... |
Code review pass — all 4 DO-hosted business sites (2026-07-06)
Full security/correctness review of tomsjavajive.com, tomtomgames.com, parkerslingshotrentals.com, epictravelexpeditions.com (orbishosting.com apex and orbis.orbishosting.com excluded — not live/do-not-touch per earlier note). 10 findings, all fixed, tested, committed, and pushed to each site's main branch same day.
Critical (live exploitable, now fixed):
- tomsjavajive.com
api/orders.phphad a literal// Admin check would go herecomment — anyone who knew/found anorder_idcould silently change any order's status (cancelled/delivered/refunded) or overwrite tracking numbers, and read another customer's full order (name, email, address, items), with zero auth. Fixed:update_statusnow requiresAdminAuth::isLoggedIn(); theGET ?id=lookup now requires admin or the order's own customer. - parkerslingshotrentals.com
uploads/— customer driver's license and insurance-card photos were directly downloadable with no login at all (theOrder deny,allow/Require all deniedpattern inuploads/.htaccessdoesn't work on this OpenLiteSpeed setup, same class of gotcha as the.gitexposure found earlier). Verified live via a throwaway test file before fixing. Fixed with the workingRewriteRule .* - [F,L]pattern in both the nesteduploads/.htaccessand the root.htaccess— required an actualsystemctl restart lshttpdto take effect (touching/usr/local/lsws/cgidalone, which only prevents the cron's own restart trigger, was NOT sufficient for a new rewrite rule to be picked up — worth remembering for future.htaccesschanges on this server).
High (fixed):
- tomsjavajive.com
admin/orders.php— the exact "same named PDO param reused twice" bug that already bitawardPoints()had recurred in the order search box (:searchbound once, referenced 3 times), causing a fatalSQLSTATE[HY093]on every admin search. Fixed with distinct:search1/:search2/:search3. - tomtomgames.com
admin/index.php— stored XSS:renderGamerOverview()inserted username/alias/email intoinnerHTMLwithout theescHtmlA()helper used correctly everywhere else in the same file. Alias has no character restriction, so a malicious alias could execute script in an admin's session the moment they open that user's profile. Fixed.
Medium (fixed):
- tomtomgames.com
includes/square.php(untracked by git — lives outsidepublic_html, fix deployed to the server only) —charge()/refund()generated a freshuniqid()idempotency key on every call, defeating Square's duplicate-protection entirely. Fixed: keyed offmd5(source_id)for charges andmd5(payment_id . amount)for refunds, so retries/double-clicks are recognized as duplicates. - parkerslingshotrentals.com
contact.php— booking availability check + insert had no locking, allowing a double-booking race under concurrent submissions; the deposit-hold idempotency key was suffixed withtime()(changes every second, so retries aren't deduped). Fixed: wrapped the check+insert in a MySQLGET_LOCK/RELEASE_LOCKpair scoped to the requested date range, and made the idempotency key stable ({ref}-dep, no time suffix). - epictravelexpeditions.com
api/config.php— DB credentials, JWT secret, admin password hash, and mail API key sat in plaintext inside the webroot (protected only by an.htaccessrewrite rule, unlike every sibling site where secrets already live outsidepublic_html). Relocated to/home/epictravelexpeditions.com/api-secrets.php(was already gitignored, so no git history exposure)..gititself was already correctly relocated togit-data/(just a 49-byte pointer file in the webroot, blocked by.htaccess) — no action needed there.
Low (fixed):
- tomtomgames.com
api/purchase.php—logActivity()referenced undefined$paymentMethod/$amountDollars(should be$method/$priceCents) in two places, producing PHP warnings and blank values in the purchase audit log for every transaction. Fixed. - epictravelexpeditions.com
api/api/testimonials.php— the public image-upload endpoint (no login required, by design) had no rate limiting, allowing storage/bandwidth abuse via scripted repeat uploads. Added aupload_rate_limitstable + per-IP cap (5 uploads/hour).
7. JARVIS AI SYSTEM
URL: http://jarvis.orbishosting.com
Files: /var/www/jarvis/ on JARVIS VM (PVE1 VM 211 — 10.48.200.211, 8 cores, 16GB RAM)
DB: jarvis_db — jarvis_user / J4rv1s_Pr0t0c0l_2026!
Login: myron / Joker1974!!!
Admin portal: http://jarvis.orbishosting.com/admin
Security hardening (2026-07-06 code review)
Full front-end + admin panel review found and fixed 8 issues, 2 of them live critical exposures:
- INFRASTRUCTURE-REFERENCE.md was publicly downloadable with zero auth (static nginx path bypassed the admin session check entirely). Fixed: file moved to
/var/www/jarvis-private/INFRASTRUCTURE-REFERENCE.md(ownedwww-data:www-data, mode 640, NOT underpublic_htmlso nginx never serves it directly), and the DOCS tab now downloads it via a new authenticateddocs_downloadaction inadmin/index.phpthat gates on the existingloggedIn()check and streams the file withreadfile(). - Two full backup copies of the 5000-line admin panel (
index.php.bak2,index.php.bak.<date>) were sitting inpublic_html/admin/and downloadable with no auth, exposing the entire admin source/attack surface. Relocated to/root/jarvis-old-backups/(no secrets were found in them, so no credential rotation was needed). esc()(the admin panel's JS HTML-escaper) doesn't escape', so it doesn't protect values embedded inside a single-quoted JS string within anonclickattribute — HTML-decoding happens before the JS parser sees it. Added a properescJs()helper (backslash + quote + newline escaping, then HTML-escape) and applied it to the Network/Alerts/Intents/Custom-News/Calendar-Feeds edit-modalonclickhandlers, which were reachable by e.g. any device on the LAN setting a malicious DHCP/mDNS hostname.- Same class of bug on the front-end dashboard (
assets/js/jarvis-app.js,assets/js/panels/jarvis-agents.js): device names and news article titles/sources were inserted intoinnerHTMLcompletely unescaped — a rogue LAN device or a malicious/compromised news feed could inject script that runs with the logged-in session. AddedescHtml()/escJs()helpers directly injarvis-app.jsand applied them to device names, VM names, agent hostnames, and news content. session.cookie_httponlywas Off server-wide (PHP default), meaning the actual session cookie — not just the app's own bearer token — was readable viadocument.cookiefrom any of the above XSS bugs. Fixed at the PHP-FPM level (/etc/php/8.3/fpm/php.ini):session.cookie_httponly = 1,session.cookie_samesite = Lax,php8.3-fpmrestarted. Verified live:Set-Cookienow includesHttpOnly; SameSite=Lax.api.phphadAccess-Control-Allow-Origin: *— tightened to an explicit allow-list of the real JARVIS origin only, withAccess-Control-Allow-Credentials: trueonly sent when the origin matches.- Two admin actions (Arc Reactor restart/setup) called an undefined function
k()instead of the real JSON responderj(), causing a PHP fatal error even though the underlyingsystemctlcommand still fired. Fixed (verified via direct API test — clean{"ok":true,...}response now). - Calendar feed passwords were stored and returned in plaintext via
cal_feeds_list'sSELECT *. Changed to return ahas_passwordboolean instead of the raw password (the edit UI never actually displayed the password back anyway — write-only field, "leave blank to keep").
All fixes verified via direct API testing (SSH + curl through the login/action flow) since this doesn't have a staging environment. Pushed to myronblair/jarvis master, commit 24bc876.
Functional bugs fixed (2026-07-06)
- "WEB HOST" card on the front dashboard always showed
--%/offline. Root cause: the DO server (165.22.1.228) never had the JARVIS monitoring agent installed — every other host in the fleet had one, this one didn't. Installed it withcurl -sk http://10.48.200.211/install-agent.sh | bash -s jarvis-do linux(hostname argjarvis-do+ the DO server's actual machine hostnameorbisproduces the expectedagent_id=jarvis-do_orbisthatdo_server.phpqueries for). Also found and fixed two secondary issues hit along the way: the agent's config pointed at a dead/stale Tailscale peer (jarvis-211, 100.77.178.42, offline 9+ days) instead of the current active one (jarvis-211-1, 100.78.153.71) — likely left over from a VM Tailscale re-auth at some point; and a stale cached API key in/var/lib/jarvis-agent/state.jsonfrom a registration attempt that never actually completed server-side, which had to be deleted to force a clean re-registration. Verified live:do_serverfield in/api/donow returns realcpu/mem/disk/online:trueinstead of an empty array. - "WEBSITES" list (part of the same JARVIS SERVER panel) was always empty, and the KB intent generator's 4-hour "don't run again too soon" guard was potentially never actually throttling correctly. Root cause, found while investigating the above:
api/config.phpsetsdate_default_timezone_set('America/Chicago'), and several places compute "how old is this DB timestamp" via PHP'stime() - strtotime($mysqlDatetimeString). Since MySQL'sNOW()/stored datetimes are naive UTC strings,strtotime()under a non-UTC default timezone misinterprets them as being in Chicago time, which throws every such comparison off by the UTC offset (5-6 hours) — in this case makingfacts_collector.php's freshness gate for thesites(and incidentallyproxmox/ollama) categories always look artificially fresh, so the site-health checks that populate the WEBSITES list stopped actually running. Fixed infacts_collector.php's$fresh()helper andkb_intent_generator.php's run-guard by moving the elapsed-time comparison entirely into SQL (updated_at > DATE_SUB(NOW(), INTERVAL ? SECOND)), which sidesteps PHP timezone handling altogether. Also fixed a leftover cosmetic label (do_server.php) still showingjarvis.orbishosting.com:1972from before the JARVIS port fix. - Note for future work: the
time() - strtotime($dbTimestamp)anti-pattern appears in a couple of other files (chat.php,email.php,planner.php) but only for display formatting of dates, not elapsed-time threshold checks — lower priority, not fixed in this pass, but worth a look if any displayed timestamps look off by a few hours.
Major fixes (2026-07-07)
/var/www/jarvis finally became a real git repo. It had no .git at all — the actual live admin panel had diverged completely from myronblair/jarvis on GitHub (the 2026-07-06 security review above was done via direct SSH edits on the live server, never committed anywhere). Reconciled by committing the live state as the new baseline and merging origin/master history with -s ours (preserves lineage without overwriting the live content), then pushed. /tmp/jarvis-deploy (a separate, stale clone used briefly as a staging area) is now superseded — don't use it; edit /var/www/jarvis directly.
KB Intent Generator cron was silently broken since ~2026-07-05. The rotation-engine refactor (moving from a hardcoded topic array to the kb_generator_topics table) had dropped the $SYSTEM prompt and the entire safe_insert() function — every 6-hour run crashed instantly on an uncaught TypeError, invisible everywhere because config.php sets error_reporting(0). Restored both from a .bak2 backup. Table grew from 386 → 900+ real intents once fixed.
GitHub auto-deploy pipeline was completely non-functional — likely since it was first set up, not just recently:
- The GitHub webhook itself pointed at the dead port
:1972(already known-stale) → 502 on every delivery WEBHOOK_SECRETwas never defined inconfig.php→webhook.phpwould have 500'd even if reached- Branch check compared against
refs/heads/main, but this repo has always usedmaster→ every real push would have been silently skipped /usr/local/bin/jarvis-deploy.sh(the queue consumer) didn't exist on this host at all- All fixed: webhook URL updated to use port 1972 (confirmed working again after the 2026-07-07 WAN IP change — Cloudflare passes this non-standard port through cleanly, unlike port 80 which it force-redirects to HTTPS), secret added, branch check fixed,
jarvis-deploy.shrebuilt (git pull + per-file PHP syntax check + auto-revert on failure,/var/log/jarvis/deploy.log, cron* * * * *) andjarvis-watchdog.shrebuilt (checks nginx/php8.3-fpm/mariadb/redis-server, restarts if down,/var/log/jarvis/watchdog.log, cron*/5 * * * *) — both were referenced in the Works tab and by cron history but the actual scripts had never existed on this VM. Verified end-to-end with a real push: webhook → queue → cron puller →git pull→ live, inside ~1 minute.
Admin panel (Works / Site Health / Email Intelligence tabs) — several real bugs, not just polish:
- Facts Collector always showed "UNKNOWN" last-run (log-format regex expected a
[bracketed]timestamp; this script's lines don't have one) — it was actually running fine every 3 min the whole time - Calendar Sync always showed "UNKNOWN" and was never actually scheduled at all (no crontab entry existed, despite the UI listing it as an active "every 15 min" job) — added the missing cron entry, fixed a regex typo (
\d{2}{4}→\d{4}) - Only KB Intent Generator's "RUN" button had a live-streaming-log popup; Facts Collector/Stats Cache/Calendar Sync just fired a toast with no way to see the eventual result. Added a generic
worker_log/worker_historybackend pair and reused the same popup pattern for all of them - Site Health:
parkerslingshotrentals.comshowed as truncated "parkerslingshots" (stale frontend label map referencing an old backend key name that no longer exists) — fixed, and widened the card layout (.site-grid/.site-card, 260px min vs the shared 160px stat-card) since domain names don't fit the generic dashboard-stat width. Also fixed the site-check freshness guard (300s vs a 180s cron interval meant sites were only re-checked every other run) — now 170s - Email Intelligence inbox always 404'd — it proxied to
https://165.22.1.228/api/email, a leftover from before JARVIS moved off the DO server; that endpoint hasn't existed since the migration. Now readsemail_triagedirectly (same tableemail_action_itemsalready used) - Compose/reply email silently produced blank drafts regardless of AI provider status — the PHP dispatcher and the Python reactor used different field names for the same payload (
recipient/subject/auto_sendvs the reactor'sto_email/subject_hint/send;contentvsbodyfor replies). Fixed both call sites llm_call()'s provider fallback never actually fired for any explicitly-requested provider (i.e. every real caller) — a failure on the first-choice provider raised straight up instead of falling through to the others. Fixed; also fixed_ollama_call()silently returning""instead of raising when Ollama reports an error (e.g. model not pulled), which had been masking failures as fake successes- Ollama had no text-completion model installed (only
llava:7b, the vision model) — pulledllama3.1:8b(~4.9GB) so the Claude→Groq→Ollama fallback chain is a real 3-tier chain, not 1.5. Bumped Ollama's call timeout 30s→90s (cold loads alone took 15s+ in testing) - Added Groq 429 retry-with-backoff (parses Groq's own rate-limit-reset header) — this account's tier is only 12,000 tokens/min, and
gmail_triagealone can exhaust it, so transient contention with compose/reply is common - Compose modal used to toast "dispatched" and never check back — if the job failed 30–90s later in the background there was no notification at all, it just silently vanished. Now polls the actual job status (
arc_job_get) until done/failed and shows the real result - Added a missing SEND button for queued drafts in the Outbox — compose had always only ever produced a
status='queued'draft with no way to actually send it. Also fixed VIEW always showing "(no body)" (it read from the list endpoint, which omits body for performance, instead of the single-item endpoint) - Still open: Claude API credits are depleted (billing, not a code issue) — restore at console.anthropic.com if Claude-quality drafting is wanted as the default again
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.210:11434, llama3.1:8b) — local LLM
Vision: Ollama llava:7b (via Arc Reactor _vision_call cascade)
Tier 2: Groq (cloud, model: compound-beta-mini)
Tier 3: Claude API (Anthropic, fallback)
→ ElevenLabs TTS → browser speaker
Arc Reactor (AI Job Processor)
Service: jarvis-arc (systemd) — port 7474
Runtime: /opt/jarvis-arc/ (Python venv, reactor.py)
Log: /var/log/jarvis/arc.log
Admin button: Workers → Daemons → SETUP (live popup) / RESTART
Vision: Claude → Ollama llava:7b → graceful fallback
Vision config: /etc/systemd/system/jarvis-arc.service.d/vision.conf
systemctl status jarvis-arc
systemctl restart jarvis-arc
journalctl -u jarvis-arc -f
To re-deploy Arc Reactor from source: Use Workers → Daemons → SETUP in JARVIS admin (live log popup shows progress).
Planner: Tasks / Directives / Missions
Admin UI sections backed by real schema + live API — verified working 2026-07-02 (created/read/deleted a test row in each, end-to-end).
Tasks — simple to-do list, stored directly in jarvis_db.
- Table:
tasks(title, notes, category, priority [urgent/high/normal/low], status [pending/in_progress/done/cancelled], due_date, due_time) - API:
task_list(GET),task_save(POST, form-encoded),task_done(POST),task_delete(POST)
Directives — OKR-style goals with key results, stored directly in jarvis_db.
- Tables:
directives(title, description, category, status, priority, target_date) +directive_key_results(directive_id, title, current_value, target_value, unit) +directive_links(directive_id, link_type, link_id — links a directive to a task/etc.) - API:
directive_list,directive_get,directive_save(POST, JSON body viaphp://input, id passed as?id=query param on update),directive_delete
Missions — automation workflows, NOT stored in jarvis_db — proxied through Arc Reactor (port 7474) which owns the mission state.
- Arc Reactor endpoints used by admin:
GET/POST /missions,GET /missions/{id},GET /missions/{id}/runs,PUT/POST /missions/{id},DELETE /missions/{id},POST /missions/{id}/run - JARVIS-side mirror tables exist (
missions,mission_runs,mission_steps) but the admin panel reads/writes live via Arc Reactor's HTTP API, not directly against these tables - API:
mission_list,mission_get,mission_runs,mission_save(POST, JSON body, id as?id=on update),mission_delete,mission_run,mission_toggle - If Arc Reactor is down, these calls return
{"error":"Arc Reactor unreachable"}— checksystemctl status jarvis-arcfirst
As of 2026-07-02: all three tables are empty (0 rows) — features are fully functional, just unused so far.
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: [rotated 2026-07-07 — stored in api/config.php on VM211, not documented here]
Install command: curl -sk http://10.48.200.211/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
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.245.77.197 (dynamic — changed 2026-07-07; see Section 1 for the full VIP list, all 35 updated same day)
- DDNS:
orbisne.fortiddns.com(FortiGate auto-updates on IP change) - Note: a WAN IP change requires manually updating every VIP's
extip(the FortiGate does not do this automatically even though DDNS updates) — the FortiGate CLI script used 2026-07-07 is a simple loop ofedit "<vip-name>"/set extip <new-ip>/nextfor all 35 VIPs. Also update Cloudflare's DNS A-records for any*.orbishosting.comhostnames pointing at this WAN IP. - Blocks: outbound port 53 (DNS) — MediaStack uses PVE1 dnsmasq (10.48.200.90) as resolver → 100.100.100.100
- Upstream DNS (changed 2026-07-05): Network → DNS set to "Specify" mode — Primary
1.1.1.1(Cloudflare), Secondary8.8.4.4(Google). Previously defaulted to the router itself (10.48.200.1)/ISP-provided servers. Admin:https://10.48.200.1:9443—admin / Joker1974!!!. Note:8.8.8.8specifically showed as "Unreachable" during setup (transient — ISP's own DNS servers were also showing high latency at that moment);1.1.1.1/8.8.4.4tested healthy and are what's live now.
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:
nordlynxon MediaStack - Exit: rotating US (Dallas) NordVPN servers, not a fixed IP
- Policy routing: table 205 (non-LAN traffic via nordlynx), managed partly by NordVPN itself and partly by a custom
nordvpn-routing.serviceunit (/etc/systemd/system/nordvpn-routing.service) that adds theip rulefor fwmark0xe1f1→ table 205 - Required for IPTorrents access (blocks non-VPN IPs)
2026-07-06 incident (fixed): nordvpnd had been crash-looping since ~2026-06-07 (/var/lib/nordvpn/data/settings.dat was corrupted/empty) — meaning NordVPN was not actually protecting MediaStack's traffic for about a month; downloads were exiting on the plain home IP. Fixed by clearing the corrupt file, restarting the daemon, and re-logging in.
While fixing this, found NordVPN's own "LAN Discovery" setting was disabled. With Routing: enabled and LAN Discovery off, connecting NordVPN's full-tunnel routing suppresses the main routing table's resolution for anything that would exit via eth0 — including same-subnet LAN traffic — so the entire VM became unreachable (SSH/ping) from the rest of the LAN the moment NordVPN connected. Fixed with nordvpn set lan-discovery on, which adds explicit priority rules for private ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16) ahead of the tunnel catch-all. Verified LAN reachability holds with Kill Switch + Firewall both re-enabled after this fix.
If MediaStack becomes unreachable after a NordVPN reconnect again: check nordvpn settings for LAN Discovery: enabled first. If SSH is already dead, the network path itself is unusable — recover via the Proxmox host instead: qm guest exec 103 -- /bin/bash -c 'export HOME=/root; nordvpn ...' (guest-exec needs HOME set manually or the nordvpn CLI fails).
Current confirmed-good settings (2026-07-06): Firewall enabled, Kill Switch enabled, Auto-connect enabled, LAN Discovery enabled, Routing enabled.
10. BACKUP SYSTEMS
Audited 2026-07-07 — file-coverage gap found and fixed in 2 of the 4 systems below. The core question asked: if the source server were lost outright, does the backup actually contain what's needed to restore it, or just a database/config fragment? JARVIS and the DO server both failed that test and are now fixed; Proxmox and FusionPBX were checked and are genuinely fine as designed.
JARVIS Backup
- Script:
/usr/local/bin/jarvis-backup.sh(also at/var/www/jarvis/deploy/) - Output:
/var/backups/jarvis/jarvis_backup_TIMESTAMP.tar.gz - Log:
/var/backups/jarvis/backup.log - Retention: 7 days (auto-purge)
- Trigger: JARVIS admin → Backups → RUN BACKUP NOW, or run script directly
- DB:
jarvis_db—jarvis_user / J4rv1s_Pr0t0c0l_2026! - Fixed 2026-07-07: this was MySQL-dump-only — a DB dump alone is useless without the actual application. Now also archives
/var/www/jarvis(app code +config.php),/opt/jarvis-arc(reactor daemon), the nginx site config, thejarvis-arc.servicesystemd unit, and the root crontab. Also fixed a typo ($SIYE→$SIZE) that silently broke the backup-size line in the log. Latest test run: 20MB.
DO Server Backup
- Repo:
myronblair/do-server-config - Schedule: Weekly, Sunday 4am
- Launcher:
/usr/local/bin/do-server-backupon DO - Fixed 2026-07-07: previously covered scripts/systemd/WireGuard/OLS-vhosts/cron/SSH keys/
/opt/infra— real server configuration — but captured zero actual data: no website files for any of the 7 hosted sites, and only a list of database names (mysql/databases.txt), never the data itself. If the droplet were lost, you'd get the server environment back but lose every site's real content and every business database. Now also archivessites/<domain>/public_html/for all 7 sites (rsync,.gitexcluded — each site's own repo already covers code history) and gzippedmysqldumpoutput for every real business DB (epic_epic_db,epic_parkersling,park_slingshot,toms_tjj_db,tomt_ttg_db,workt_track_db— CyberPanel's own internal DB and MySQL system schemas are skipped). Verified live: all 6 DBs dumped with real content, all 7 sites' files present, repo still only 5.4MB after the first full run (318 files, ~48K lines). - Restore: 8-phase wizard in
restore.sh(predates the 2026-07-07 file/DB additions — the wizard itself hasn't been updated yet to restoresites//databases/, only the original config pieces. Worth revisiting before relying on it for a full restore.) - Downloadable zip: as of 2026-07-07,
backup.shalso writes/opt/do-server-backup.zip(current working tree minus.git, regenerated every run) — see "Blair HQ Backup Downloads" below.
Proxmox Config Backup
- Repo:
myronblair/proxmox-config - Schedule: Weekly, Sunday 3am (both PVE1 and PVE2)
- Launcher:
/usr/local/bin/proxmox-backupon each node - Covers: VM .conf files, network, cron, systemd, scripts (host-level config only, by design)
- VM disks: Verified 2026-07-07 — real nightly
vzdumpjobbackup-aa6b1890-23c0(all VMs, snapshot mode, keep-last=3, 21:00 daily, toSynologyProx) genuinely covers full VM disk data separately. Confirmed viapvesh get /cluster/backup— this is not just documented, it's an active, enabled job. No gap here; config-in-git + data-via-vzdump is a legitimate split, not an oversight.
FusionPBX Backup
- Repo:
myronblair/fusionpbx-config - Schedule: Weekly, Sunday 5am
- Launcher:
/usr/local/bin/fusionpbx-backup - Covers: PostgreSQL dump (gzip, ~29-60MB) + FreeSWITCH configs + call recordings
- Verified 2026-07-07: already does a real
pg_dumpof the actualfusionpbxdatabase (dialplans, SIP gateways, IVR, ring groups, devices, voicemail, users — all real data, not just a name list) pluspg_dumpall --globals-only, plus config files and recordings. No gap here. - Restore: 10-phase wizard in
restore.sh - Known issue (found 2026-07-05, still open): this repo has grown to ~166MB on GitHub / ~196MB on Gitea because the DB dump gets committed directly into git history on every backup run (3 copies in history as of this writing, each ~60MB) rather than being excluded/rotated. Options not yet decided: gitignore the dump going forward, or purge it from history with
git filter-repo+ force-push (destructive, needs explicit sign-off).
Blair HQ Backup Downloads (web.orbishosting.com, added 2026-07-07)
A new Backup Downloads card on the Blair HQ dashboard (next to the existing Backup Status card) surfaces the actual JARVIS and DO Server backup files for direct download — source location, timestamp, and file size are shown, pulled from /downloads/backup-files-status.json.
- Pull script:
/usr/local/bin/pull-backups.shon VM110 (NovaCPX), cron0 5 * * *(daily, safely after both source backups) — SCPs the latestjarvis_backup_*.tar.gzfrom VM211 (key-based SSH; a new ed25519 keypair was generated on VM110 and added to VM211'sauthorized_keysfor this specifically) and/opt/do-server-backup.zipfrom the DO server (password auth viasshpass), then writes the status JSON. Log:/home/webacct/logs/pull-backups.log. - Security fix that made this safe to build:
/home/webacct/public_html/downloads/had zero access protection — anything dropped there (including the infra reference doc, previously) was fetchable by anyone on the open internet with no login, sinceweb.orbishosting.comis fully public (confirmed reachable from outside, HTTP 200). Added HTTP Basic Auth (myron/Joker1974!!!) scoped to the/downloads/location in/etc/nginx/sites-enabled/novacpx-webacct.conf, withbackup-status.jsonandbackup-files-status.jsonexplicitly exempted (exact-matchlocationblocks ahead of the auth'd prefix block) since the dashboard's own client-side JS fetches those with no credentials to send. - Also fixed while auditing this: a daily VM110 cron (
0 4 * * * curl ... -o .../INFRASTRUCTURE-REFERENCE.md) had been silently overwriting the infra doc with an empty file every night since the 2026-07-06 security review relocated the real copy off any public path — the cron's source URL no longer existed. Restored a LAN-only static copy at/var/www/jarvis/public_html/admin/downloads/INFRASTRUCTURE-REFERENCE.mdon VM211 (safe: VM211 isn't internet-reachable directly, only from the internal LAN) so this automation has something real to pull again. The authenticateddocs_downloadaction in the JARVIS admin UI is unaffected either way.
MSP360 Backup Status (Dashboard Integration)
- Client software: MSP360 (CloudBerry) Backup CLI installed on all 6 hosts — PVE1, JARVIS (211), NovaCPX (110), Jellyfin (33), MediaStack (35), Homebridge (18)
- Storage target:
NAS-MSPBackupsdestination → Synology NAS CIFS share, mounted at/mnt/nas-backups/MSPBackups - Mount reliability:
/usr/local/bin/msp360-mount-ensure.sh(cron*/15 * * * *on hosts using the NAS mount) — bind-mounts the MSPBackups subdir onto itself since MSP360's pre-flightmountpointcheck fails on a subdirectory of a CIFS mount otherwise - Collector:
/usr/local/bin/backup-status-collect.shon PVE1 (runs via key-trusted root SSH — PVE1 is the only host with passwordless SSH to all 6 targets; other hosts use password auth viasshpass)- Queries each host's plan via
cbb plan -l(legacy v1 CLI — outputsState:/Last result:fields directly, unlikecbbV2/cbbCommandLineV2which needsplan list -band different parsing) - Writes
/tmp/backup-status.json, thenscps it toroot@10.48.200.110:/home/webacct/public_html/downloads/backup-status.json - Schedule: daily
0 6 * * *on PVE1 (>> /var/log/backup-status-collect.log)
- Queries each host's plan via
- Dashboard card:
web.orbishosting.com"BACKUP STATUS" card (index.html) fetches/downloads/backup-status.jsonclient-side (loadBackupStatus()), color-codes dots byresult(green=Success, yellow=Warning, red=Fail, cyan=Running, gray=unknown) - JSON schema:
{"updated": "<ISO8601 UTC>", "hosts": [{"name","ip","state","result"}, ...]} - Homebridge (2026-07-04): dropped MSP360 entirely. After extensive troubleshooting (RAM starvation, a bug where its account scanned every other host's shared backup data, missing bind-mount depths, CIFS tuning, a full plan recreation) Homebridge's MSP360 agent kept failing with a false "storage drive not mounted" error at a consistent ~60-75s mark, root cause never conclusively identified (survived every environmental fix, looked like an app-level bug tied to any custom/non-default account path). Since Homebridge (VM 118) was already being backed up successfully every night by the cluster-wide Proxmox vzdump job (
backup-aa6b1890-23c0, all VMs, 21:00 daily, keep-last=3, toSynologyProxstorage), MSP360 was stopped/disabled on Homebridge (systemctl disable msp360-backup.service msp360-backupWA.service) and removed from the dashboard collector's per-host MSP360 check. The collector now reads Homebridge's status directly from/mnt/pve/SynologyProx/dump/vzdump-qemu-118-*.vma.zston PVE1 instead of querying an in-guest agent. - Known state (2026-07-04): 4/5 remaining MSP360 hosts report
Warning, NovaCPX reportsFail— plan-level result, not investigated further; worth checking each host's MSP360 GUI/log for root cause if backups need to be trusted for restore. Homebridge reportsSuccessvia Proxmox.
11. SSH QUICK REFERENCE
# 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.210 # Ollama (NOT .95 - that's a naming leftover, nothing listens there)
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; use VMID not IP)
sshpass -p 'Joker1974!!!' ssh root@10.48.200.90 \
'qm guest exec 106 -- bash -c "export HOME=/root; CMD"' # Ollama = VMID 106
# Other VMIDs: Jellyfin=112, MediaStack=103, JARVIS=211, NovaCPX=120, HomeAssistant=101, Homebridge=118
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 | http://jarvis.orbishosting.com | myron | Joker1974!!! |
| JARVIS Admin | http://jarvis.orbishosting.com/admin | myron | Joker1974!!! |
| ChuckCo Time Keeper Admin | https://worktracking.orbishosting.com/admin/login.php | — | 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: 635142c218f2457e813a2de8dec75b05 |
| 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 |
— | — |
| ChuckCo Time Keeper | workt_track_db |
workt_track_user |
ZWCNMRP2N5NVPsghmve5aRS9 |
| FusionPBX | PostgreSQL | fusionpbx |
pSJaF9mUJqPr4Sj5mwJyRqvCCpc |
| MySQL root (DO) | — | root | b71e5c1a8c7457541b9c1db822de37adfa271926a38b6c20 |
API Keys
| Service | Key |
|---|---|
| GitHub PAT | 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 (rotated 2026-07-05, scopes repo+workflow) |
| JARVIS Agent Registration | [rotated 2026-07-07 — stored in api/config.php on VM211, not documented here] |
| 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 | 635142c218f2457e813a2de8dec75b05 |
| 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) | — |
13. GIT & REPOSITORY MANAGEMENT
GitHub (myronblair, 26 private repos as of 2026-07-05) is the permanent/source-of-truth storage. Gitea (gitea.orbishosting.com, hosted on the Synology NAS, login myron / Joker1974!!!) mirrors it one-way — GitHub → Gitea only, via pull-mirrors triggered by POST /api/v1/repos/<owner>/<repo>/mirror-sync. Never push directly to a Gitea remote.
5 repos are Gitea-only by design, never pushed to GitHub (deliberately kept off a third-party cloud service since they hold real credentials): fortigate-config, infra-private, jarvis-secrets, msp360-config, proxmox-secrets.
Local clones live on the admin Windows machine at C:\Users\myron\repos\ (currently chucko, web-dashboard — more cloned there as needed). Periodic maintenance: git gc --aggressive --prune=now to keep loose objects packed.
Per-site deploy pattern (the 7 DO-hosted sites + jarvis + web-dashboard): .git metadata is relocated outside the public webroot (e.g. /home/<site>/git-data with a gitdir: pointer file left in public_html/.git) so .git itself is never web-accessible, while git commands run normally from inside public_html. Most sites deploy via a GitHub webhook → queue file → cron puller (~1 min); chucko (ChuckCo Time Keeper) currently has no auto-deploy hook — pushes are manual (SSH in, git pull/push directly).
Known repo-hygiene issue: fusionpbx-config bloated to ~166-196MB from repeatedly committing a large DB dump straight into history — see Section 10.
14. NETWORK EQUIPMENT & CLIENT DEVICE INVENTORY
Compiled 2026-07-06 from a live ARP scan off PVE1 (~90 hosts), MAC-vendor lookups, and direct confirmation from Myron. Built to support a future VLAN segmentation project — see VLAN-Segmentation-Plan.docx in the home folder for the full plan; this section is the durable factual record to carry forward (e.g. into JARVIS) independent of that plan's status.
14.1 Core Network Equipment
| Device | Model | Role |
|---|---|---|
| Firewall | FortiGate 60F | Primary/active firewall — confirmed the top unit in the rack. A second Fortinet unit is stacked below it; its role is not yet identified — not confirmed as an HA pair. |
| Primary switch | Cisco Catalyst 3560-E Series PoE-48 | 48-port, full PoE, enterprise-managed — full 802.1Q VLAN/trunk support |
| Secondary switch | FortiSwitch 108F-FPOE | 8-port PoE, FortiLink-managed |
| KVM switch | TRENDnet TK-802R | Physical console access to rack servers — not networked |
| WiFi extender 1 | TP-Link RE305 — 10.48.200.16 | WiFi clients only, no wired devices |
| WiFi extender 2 | TP-Link RE305 — 10.48.200.89 | WiFi clients only, no wired devices |
| WiFi extender 3 | TP-Link RE305 — 10.48.200.93 | Wired network printers plugged into its Ethernet port; no WiFi clients on this unit |
| WiFi extender 4 | Brand unconfirmed (Shenzhen Xunman-branded/OEM) — MAC fc:22:1c:30:60:14 seen at 10.48.200.100/.64 |
Wired Pioneer VSX-822 AV receiver plugged into its Ethernet port; no wireless clients of its own — same bridge-mode pattern as extender 3 above |
| Wireless bridge | Good Story Networks WB610H — 10.48.200.80 | Links the main house network to the storage shed (a detached building). OEM manufacturer is Shenzhen LiWiFi Technology Co., Ltd (rebranded by Good Story Networks). Plan: once fully deployed, this bridge replaces the need for the RE305 units at .16 and .89 — see the VLAN plan doc for details. VLAN/802.1Q trunk capability not yet confirmed — check before relying on it for segmented WiFi. |
Note on consumer extenders and VLANs: budget range extenders like the RE305 (and likely extender 4 above) generally cannot map multiple SSIDs to separate VLANs over a trunk — they repeat one network. This matters if/when wireless VLAN segmentation is implemented; see the VLAN plan doc's "Wireless VLAN Feasibility" section.
14.2 Client & Peripheral Device Inventory (by category)
Printers:
| IP | Device |
|---|---|
| 10.48.200.76 | Epson ET-3750 |
| 10.48.200.204 | HP LaserJet 500 Color MFP M570dn (wired to the RE305 at .93) |
| 10.48.200.205 | HP LaserJet M1536dnf MFP (wired to the RE305 at .93) |
| 10.48.200.201, .202 | Unidentified — likely more printers/peripherals on the same RE305 port, given the pattern above (not yet confirmed) |
Storage:
| IP | Device |
|---|---|
| 10.48.200.249 | Synology NAS |
| 10.48.200.41 | WD My Cloud — a second NAS alongside the Synology |
AV / Entertainment:
| IP | Device |
|---|---|
| 10.48.200.42, .72 | Vizio smart TVs |
| 10.48.200.100 | Pioneer VSX-822 AV Receiver — confirmed 2026-07-06, wired into a 4th WiFi range extender/AP (Shenzhen Xunman-branded/OEM, MAC fc:22:1c:30:60:14, no wireless clients of its own). This explains the earlier MAC discrepancy cleanly: the extender reports its own MAC in ARP for the wired Pioneer behind it, same bridge-mode pattern seen with the RE305 at .93 and its wired printers — the Pioneer's own labeled MAC (74:5E:1C:0E:7C:0B, genuine Pioneer Corporation OUI) simply never appears on the wire. 10.48.200.64 shares this same extender's MAC — likely the same device (Pioneer or the extender itself) at a prior IP, not a separate device. |
Smart home / IoT:
| IP | Device |
|---|---|
| 10.48.200.38 | Samsung SmartThings hub (MAC vendor: Physical Graph Corporation, the original SmartThings company) |
| 10.48.200.250, .251 | Goalake Smart Switch 1 and 2 |
| 10.48.200.5, .7, .8, .9, .36, .61, .74 | Generic ESP32/ESP8266-based smart plugs/sensors (Espressif chipset) |
| 10.48.200.14, .60 | Tuya Smart plugs/switches |
| 10.48.200.34 | Bouffalo Lab-chipset IoT device |
| 10.48.200.116 | FN-LINK-chipset IoT device |
| 10.48.200.6, .10, .15, .23, .24, .27, .28, .30, .31, .32, .37, .62, .82, .86, .87, .105 | TP-Link Tapo smart devices (16 total) |
| 10.48.200.17, .39, .40, .46, .53, .68, .71, .106, .115, .118 | Amazon devices (Echo/Fire TV/Kindle) |
Security cameras:
| IP | Device |
|---|---|
| 10.48.200.57, .78, .94, .95, .101, .103, .104 | Reolink cameras + NVR (7 addresses total — one of these is the NVR itself, not confirmed which). Cameras are PoE-connected directly to the Catalyst 3560-E, not cabled to the NVR; the NVR pulls streams over the network like any other client. Feeds are viewed both locally on the LAN and remotely via the Reolink app. |
| 10.48.200.21, .22 | Ring doorbell/camera — also viewed both locally and via the Ring app remotely |
VoIP (Yealink) — see Section 8 for extension details:
.2, .3, .43, .65, .83, .85
Personal computers / hobby devices:
| IP | Device |
|---|---|
| 10.48.200.54 | Apple device (iPhone/iPad/Mac) |
| 10.48.200.66 | Dell PC |
| 10.48.200.52 | Intel-NIC PC |
| 10.48.200.45 | Microsoft device (Surface or Xbox — not yet confirmed which) |
| 10.48.200.50 | Raspberry Pi 5 — hobby/tinkering only, no production workload |
Still unidentified as of 2026-07-06 (MAC vendor lookup only, no direct confirmation yet):
| IP | Vendor signature | Notes |
|---|---|---|
| 10.48.200.13 | Murata Manufacturing | Embedded WiFi module — device unknown |
| 10.48.200.59 | Guangzhou Shiyuan Electronic | Often AV/display equipment — device unknown |
| 10.48.200.119 | Macherey-Nagel GmbH & Co. KG | A lab-equipment brand (chromatography/filtration) — unusual on a home network, device unknown |
| 10.48.200.77 | Liteon Technology | Could be a PC PSU with network mgmt, or a peripheral — device unknown |
| 10.48.200.201, .202 | (shares MAC with the RE305 at .93 and the confirmed printers at .204/.205) | Likely more printers/peripherals, not confirmed |
Minor known artifact, low priority: MAC 7a:e1:7e:44:08:29 is shared across 10.48.200.93 (RE305), .204/.205 (confirmed printers, benign RE305 bridge-mode behavior), and .251 (Goalake Smart Switch 2 — does NOT fit the "wired to the RE305" explanation, so this one specific overlap looks like a genuine duplicate/cloned MAC, common in ultra-budget IoT hardware). Worth a quick check of the Goalake switch's real MAC via its own admin UI at some point; not urgent.
This document contains sensitive credentials. Store securely and do not share.