- Replace all Jellyfin/MediaStack/WireGuard-CT110 references (destroyed 2026-07-23) with StreamHoard/CT104 throughout; add streamhoard.md covering the full consolidated stack, MSP360 backup setup, and migration incidents - Split FusionPBX/SignalWire/landline content into its own voip.md (was scattered across jarvis.md and sites.md, and referenced the old destroyed DO droplet IP) - Fix stale facts: JARVIS webhook port (:1972 -> 80/https), rotated registration key/GitHub PAT, FortiGate admin port (9443 not 443), current WAN-IP-drift/VIP gotchas - Add reference.md for repo inventory notes, assistant hard limits, ZeroTraceGPT IQ, payments migration status - Update gotchas.md with unprivileged-LXC mount limitations and MSP360 dpkg-repack gotcha
7.0 KiB
Critical Gotchas — Read Before Running Commands
Unprivileged LXC containers (Proxmox) — mount limitations
- NFS and CIFS client mounts both fail inside an unprivileged LXC even with the
mount=nfs;cifsfeatures flag set — "Operation not permitted." This is a hard kernel-capability limitation, not a config mistake; don't retry it. - Fix: mount the share on the PVE host itself (fstab,
_netdev), then pass it into the container as an LXC mountpoint (pct set <CTID> -mpN /host/path,mp=/container/path). This persists across reboots on both the host and the container. - A network share's root export directory can have restrictive permissions (e.g. Synology's
hideNFS option sets mode000on the share root) that real root on the PVE host silently bypasses via DAC-override, but an unprivileged container's "root" cannot — causesPermission deniedeven though subfolders are readable. Fix on the source NAS/host, not in the container. - Passing a TUN device (needed for WireGuard-based VPN containers like gluetun) needs explicit
pct set <CTID> -devN /dev/net/tun.
MSP360 / CloudBerry Backup
- CLI binary path has a space:
/opt/local/MSP360\ Backup/bin/cbb(legacy CLI,plan -l/-r/-s) orcbbV2(full plan/account create/edit) — always quote it. dpkg-repacking an already-initialized install captures a package missing its own bootstrap config templates (cloudBackup.conf,wt_config.xmlget consumed/deleted from the package tree after first run). A fresh install from that repacked .deb hangs forever waiting on a file that will never appear. Fix: copy the generated versions of those files from the source machine's live runtime directory into the new install before first start.- A leftover worker process from a killed/deleted plan silently blocks a new plan's worker — the tell is near-zero CPU usage despite the job showing "Running" for many minutes.
ps aux | grep cbbWorker, kill anything referencing an old/deleted plan ID. - Free/Freeware license self-registers via
cbbV2 license activate -f -e <email> -c— no manual key needed.
PHP / OpenLiteSpeed (DO server)
- NEVER use
lsphp -lfor syntax check — it segfaults. Usephp8.3 -l file.php - Run CLI scripts with:
/usr/local/lsws/lsphp85/bin/lsphp /path/script.php - If endpoint uses
ob_start()+ header.php pattern → addob_end_clean()before CSV/JSON output - MySQL charset: always
utf8mb4_unicode_ci— mixing withgeneral_cibreaks JOINs (error 1267) - Cron bug:
*/3 * * * *restartslshttpdif any.htaccessis newer than/usr/local/lsws/cgid— nothing re-touches that dir after restart, causing a restart loop until youtouch /usr/local/lsws/cgidmanually.
SSH / Networking
- DO server (165.22.1.228) cannot reach the local network (10.48.200.x) directly.
- PVE1 SSH via FortiGate DDNS works:
root@orbisne.fortiddns.com(survives WAN IP changes, which happen fairly often — checkcurl ifconfig.mebefore trusting a documented WAN IP). - PVE2 has no external port forward — only reachable locally or via cluster API through PVE1.
- Proxmox API port 8006 IS forwarded:
orbisne.fortiddns.com:8006. - FortiGate admin GUI is on port 9443, not 443 (443/80 both redirect there).
- A host's SSH interactive access can be intermittently flaky (e.g. through nested nested plink→ssh→ssh hops) while its own automated scripts using the same key work fine every time — that's usually not a real security/access problem, just a quirk of the ad-hoc path.
JARVIS Agents
- Agent config:
/etc/jarvis-agent/config.json| Runtime state:/var/lib/jarvis-agent/state.json - 401 "Invalid agent key" → state.json has a stale key. Fix: overwrite with correct
agent_id/api_keyfromregistered_agentstable, thensystemctl restart jarvis-agent. - Metrics stored as JSON in
metric_datacolumn — useJSON_EXTRACT(metric_data,'$.cpu_percent'), no direct columns. - Set the container/VM's actual OS hostname correctly before first agent registration — a hostname typo becomes part of the generated
agent_idand creates a stale duplicate registration that needs manual DB cleanup later.
Groq AI
- Model name:
compound-beta-mini— NOTgroq/compound-beta-mini(that's OpenAI router syntax, 404s).
Proxmox
--nameservermust be space-separated:"8.8.8.8 1.1.1.1"(comma causes a netplan bug).- Run commands in a VM even when SSH/network is down:
qm guest exec <VMID> -- bash -c 'cmd'(needs guest agent; also needsexport HOME=/rootfor many CLI tools since guest-exec has no HOME env by default). - Run commands in an LXC:
pct exec <CTID> -- bash -c 'cmd'.
Deploy
- Repos with auto-deploy webhooks (JARVIS, web-dashboard, StreamHoard's compose isn't webhook-deployed — it's manual
git pull+docker compose up -d): alwaysgit add + commit + push— don't forget to also trigger the Gitea mirror-sync afterward (curl -X POST -u myron:Joker1974!!! https://gitea.orbishosting.com/api/v1/repos/myron/<repo>/mirror-sync). - The 7 DO-hosted sites have no auto-deploy — manual SSH + git pull only.
API Endpoint Auth (JARVIS)
- Netscan endpoint (
/api/netscan) bypasses main auth — usesX-Registration-Keyheader. - Admin portal uses a separate PHP session name (
jarvis_admin) — different from the main JARVIS session. - Cloudflare real IP: use
$_SERVER['HTTP_CF_CONNECTING_IP'](orHTTP_X_FORWARDED_FOR), notREMOTE_ADDR.
Network Scan
- The JARVIS "RUN NETWORK SCAN" button doesn't scan from wherever the browser is — it queues a shell command to the PVE1 agent, which runs nmap and pushes results to
/api/netscan. Results appear ~40s after clicking. - Chat "scan network" intent returns real DB data — never hallucinated.
FusionPBX / VoIP
See voip.md for the full reference — SignalWire has several non-obvious credential-type and API-endpoint gotchas that cost real debugging time in the past; don't re-derive them from scratch.
- SIP config changes need the sofia.conf Lua cache cleared, not just a service restart:
rm /var/cache/fusionpbx/<hostname>.configuration.sofia.conf
Git push confirmation
Pushing to a repo's default branch (master/main) needs an explicit, branch-named confirmation from the user — a general "yes" to "want me to push this?" isn't enough and will get blocked. Ask "confirm push directly to master?" up front to save a round-trip. If a chained git add && commit && push gets denied, nothing in the chain ran — re-check git status before retrying individual steps.
Live log popup convention (JARVIS admin)
Any server-side action triggered from JARVIS admin (setup, deploy, install, run backup) must show a live log popup — NOT a confirm()/toast(). Pattern: openModal() + scrollable dark log div + backend log-polling endpoint ({lines:[], next_line:N}) + color-coded lines (green=ok, red=error, yellow=warn) + auto-detect completion + CLOSE button that stops polling. Poll every 2s, snapshot log position before triggering the action to avoid replaying old output. runIntentGenerator() in the admin JS is the canonical reference implementation.