VPS Infrastructure Audit & Cleanup Log

Date: 2026-08-15 | Host: srv1163725 (168.231.110.80) | Performed via: growit_agent (sudo)
Status: Audit complete, all findings closed except rotating a leaked Anthropic API key.

Verdict

This was a shared VPS carrying several products stacked over time with little isolation (shared Nginx, shared package manager, two DB engines, one Docker daemon). “Duplicated” resources turned out mostly to be naming collisions and dead leftovers. “Undocumented mystery apps” (cropleads, nexora, Odoo) turned out to be well-documented — just not in the architecture docs; the real record was in Claude-Code-Session-History and confirmed by Azzam.

The biggest gap — CRM and cropleads running as plain PM2 processes sharing the host filesystem, localhost services, and the same Jitsi JWT secret — was closed by containerizing both apps plus n8n into isolated Docker networks, with a fully separate Jitsi stack for cropleads. Full detail: Containerization-Migration.

System

Ubuntu 25.10 (Questing), kernel 6.17, 4 vCPU, 16GB RAM, 193GB disk (17% used, 162GB free).

Running services (post-containerization)

Grow It (the product):

  • growit-crm-api — Docker container on growit-net, published 127.0.0.1:3000. DB GROWIT, role crm_app.
  • growit-cropleads — Docker container on cropleads-net, published 127.0.0.1:4001. Real client deployment — “Crop Leads For Real Estate & Investment,” Heliopolis Cairo, live since 2026-04-15. DB growit_cropleads, role cropleads_app.
  • n8n — Docker container (official image), dual-homed on both networks as the shared automation hub.

Other products on the same box:

  • Jitsi Meet — two fully independent stacks: CRM’s at /opt/jitsi (meet.grow-it-ai.com), cropleads’ new one at /opt/jitsi-cropleads (meet.cropleads.site) — separate secrets, separate ports.
  • Nextcloud — Grow It’s own internal tool (cloud.grow-it-ai.com), not customer-facing.
  • Ollama — local LLM runtime, port 11434, purpose unclear, nothing currently calls it.
  • OpenClaw — agent/automation gateway container; public exposure fixed this audit.
  • nexora.grow-it-ai.com — confirmed a static prospect pitch demo, no backend.

Removed: abandoned WordPress, empty NocoDB, orphaned Nextcloud MariaDB DB, Odoo 19 ERP (fully decommissioned — was the platform’s original CRM structure before the custom Grow It CRM was built), old shared growit Postgres role, unused /root/.n8n.

Shared infra: Nginx, PostgreSQL 17, MariaDB 11.8, Redis, Docker/containerd, fail2ban, chrony. Docker hosts 7+ containers.

Domains live

grow-it-ai.com/www, crm.grow-it-ai.com, api.grow-it-ai.com, n8n.grow-it-ai.com, demo.grow-it-ai.com, intake.grow-it-ai.com, proposals.grow-it-ai.com, nexora.grow-it-ai.com, cloud.grow-it-ai.com, meet.grow-it-ai.com, crm.cropleads.site + cropleads.site, meet.cropleads.site. odoo.grow-it-ai.com fully retired and confirmed no longer resolving.

Security findings (all fixed except #4)

  1. OpenClaw open to internet with no proxy/TLS/auth — fixed.
  2. Leftover RSA key in root’s authorized_keys — removed.
  3. PasswordAuthentication yes in two sshd config files — fixed, see VPS-SSH-Access-Investigation.
  4. Two DB engines (Postgres + MariaDB) — still open, architectural, not urgent.
  5. Shared Postgres superuser role across 3 apps — split into least-privilege roles crm_app/odoo_app(dropped)/cropleads_app.
  6. CRM and cropleads shared JITSI_JWT_SECRET — fixed via separate Jitsi stacks, see Containerization-Migration.
  7. No real isolation between CRM/cropleads (plain PM2, shared filesystem/localhost) — fixed via Docker networks.

Key action log highlights

  • Postgres role split into crm_app/odoo_app/cropleads_app, each least-privilege, old growit role eventually dropped outright.
  • Odoo confirmed retired (was the original CRM structure before the custom build) and fully decommissioned: service stopped, nginx site retired, DB dropped, /opt/odoo19 (1.6GB) deleted, dedicated Linux user removed — after a verified backup (odoo19_archive_20260815.zip, 640MB, integrity-tested) landed in Nextcloud.
  • growit_admin and ahmed re-keyed with fresh ed25519 keypairs after unresolved key-custody investigation (see VPS-SSH-Access-Investigation); PasswordAuthentication disabled server-wide afterward.
  • Full Claude Code session history (11 sessions, 32 memory files) exported into this project — see Claude-Code-Session-History.
  • Containerization of n8n/CRM/cropleads + cropleads’ own Jitsi stack — see Containerization-Migration for the full 5-phase record.
  • Old PM2 process definitions deleted outright (final cleanup) once containers were confirmed stable.
  • Retired odoo.grow-it-ai.com DNS A record removed by the user directly at Hostinger, confirmed via two public resolvers.

Every irreversible step (DB drop, file deletion, user removal, disabling password auth, container cutover, PM2 deletion) only happened after a backup or fallback was independently verified.

Final verification: all services active; all 3 containerized apps healthy with RestartCount: 0; all 9 live domains HTTP 200; disk 17% used, 162GB free.

Open items

  1. Rotate the Anthropic API key found in plaintext in root’s .bash_history, n8n’s ecosystem.config.js, and CRM’s .env.

See also