docs: nest 19 files into audit/ clients/ infrastructure/ monitoring/ projects/ super-search/

This commit is contained in:
root
2026-08-08 13:04:55 -04:00
parent 11a1110b81
commit a522d11c35
20 changed files with 927 additions and 0 deletions
@@ -0,0 +1,37 @@
# Cost Control Rollout — 2026-07-24
**Trigger:** $46 additional unexpected spend on top of $155.76/3-day burn.
**Root cause:** Unlimited LiteLLM key + GPT-5.6 Terra as default gateway model with no enforced budget, session-size, or model-allowlist guardrails.
## Changes Deployed
### 1. LiteLLM — New constrained team + key
- **Team `hermes-normal-ops`**: $3.33 rolling daily cap + $100 rolling 30-day cap, 30 RPM, 250K TPM, max 3 parallel requests.
- **Key `hermes-normal-ops-daily-capped`** (`...I3gQ`): Hard $3.33/day, model-restricted to approved list only.
- **Allowed models**: `claude-sonnet-5`, `deepseek-v4-pro`, `deepseek-v4-flash`, `glm-5.2`, `MiniMax-M3`, `qwen3.7-plus`.
- **Terra/GPT-5.6/Claude-Opus-4**: explicitly **excluded** from this key — LiteLLM returns HTTP 403.
- **Legacy key `sk-...itzA`**: blocked (blocked=t in DB).
### 2. Hermes config — Default routing
- **Conductor**: `claude-sonnet-5` (admin-ai/LiteLLM proxy).
- **Fallbacks**: `deepseek-v4-pro``deepseek-v4-flash` (admin-ai only).
- **Delegation/workers**: `deepseek-v4-pro`, fallback `deepseek-v4-flash`.
- **No automatic escalation to premium** — failure stops, not silently upgrades.
### 3. Session controls
- **Context length**: 128k tokens hard ceiling.
- **Compression**: enabled at 50% fill, targets 20% ratio.
- **Max turns**: 50 per session (prevents unbounded tool-call marathons).
### 4. Rate limits (on LiteLLM key)
- 30 RPM, 250K TPM, max 3 concurrent requests.
- 429 throttle-backoff confirmed working in live logs.
## Verification
- Sonnet makes calls through new key: HTTP 200.
- Terra through new key: HTTP 403 (blocked).
- Old key blocked in DB: `blocked = t`.
- Live gateway confirmed routing through `admin-ai` at `https://admin-ai.itpropartner.com/v1/`.
## What's still behavioral (not enforced)
- Model compliance is enforced at the proxy key layer. Cost caps are enforced at the key+team layer. Session size is a Hermes config setting — stickiness depends on the runtime respecting it.
+252
View File
@@ -0,0 +1,252 @@
# IT Pro Partner — Complete Key Inventory
**Generated:** 2026-07-23
**Sanitized:** 2026-07-23 (plaintext secrets replaced with storage references)
**Scope:** All SSH keys, API tokens, service credentials, device keys, and passwords across the infrastructure
**⚠️ SENSITIVE:** All credential values live in the listed storage locations. See Hudu for API keys (layout 49).
---
## 1. SSH Keys
| Key Name | File | Type | Fingerprint (SHA256) | Purpose | Deployed To |
|----------|------|------|-----------------------|---------|-------------|
| **itpp-infra** | `/root/.ssh/itpp-infra` | ED25519 | `Jxh0bbT9dUV3q1DYYB3hHyhy/1TDj7Q8U4xrVmB38uQ` | Universal server admin key | All servers (Core, app1, app2, app3, wphost02, app1-bu, home router) |
| **wisp_rsa** | `/root/.ssh/wisp_rsa` | ED25519 | `MxQw1oh90NibSgN2mDbKP+07/jE4FEUEBbFAzuk5DcI` | WISP MikroTik CCR router SSH | Home CCR router (10.77.0.2 via WireGuard) |
| **germaine-personal** | `/root/.ssh/germaine-personal` | ED25519 | `dDbLH+bdPFcGU0mm1DpGa43ec0nUZ88YnpCi4p63y3I` | Germaine's personal key (from his machines) | Germaine's devices → Core |
| **homelab** | `/root/.ssh/homelab` | ED25519 | `c1nts4wR9EU06/O/k895Pb2tGZublgnGWG6NoQrK/qs` | Homelab Proxmox/QNAP access | vm-host-01, vm-host-02, QNAP NAS |
| **siteground.key** | `/root/.ssh/siteground.key` | RSA (encrypted) | N/A (RSA, encrypted) | SiteGround SFTP backup (port 18765) | SiteGround shared hosting |
| **authorized_keys** | `/root/.ssh/authorized_keys` | — | — | Who can SSH into Core | Core (this server) |
### SSH Key Details
```
itpp-infra.pub: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII4dxTH11aJkBqCY8lXl1kTfZ8yXWhTcthHnt1MtAuIE itpp-infra
wisp_rsa.pub: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDnI4UwwPL8gJvtP/Jr7qiw0Qj/bQBwi2+f03p730xvn wisp-backup
germaine-personal.pub: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAID2H/2VMn8i7YSUUpcag6yXiI6nB3T99h7JIOs5/+73r germaine@itppartner
homelab.pub: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHT+727Cti4cZ2x6CiYDeDKZ9BhvCJCzTHlO9vMInHie homelab-itpp
```
---
## 2. Server Root Passwords
**Storage:** Hudu (Vaultwarden asset) + `/root/.hermes/.env` (netcup CCP section)
| Server | IP | Provider | Access | Notes |
|--------|-----|----------|--------|-------|
| **Core** | 152.53.192.33 | netcup RS 2000 | SSH key only | `itpp-infra` key, password auth disabled |
| **app1** | 152.53.36.131 | netcup RS 4000 | Via root or ippadmin+sudo | Root password in Vaultwarden |
| **app2** | 152.53.39.202 | netcup RS 4000 | Via root or ippadmin+sudo | Root password in Vaultwarden |
| **app3** | 152.53.241.111 | netcup RS 4000 | Via root or ippadmin+sudo | Root password in Vaultwarden |
| **app1-bu** | 5.161.225.131 | Hetzner CPX21 | itpp-infra SSH key | Warm standby (core-bu) |
### Admin Account (all servers)
- **Username:** `ippadmin`
- **Password:** → Vaultwarden entry "ippadmin"
- **Sudo:** Yes (full sudo access)
- **SSH:** Key-based only (`itpp-infra`)
---
## 3. Cloud & Infrastructure API Keys
**Storage:** All in `~/.hermes/.env` + Hudu API assets (layout 49)
| Service | Hudu Asset | Storage Location | Status |
|---------|-----------|------------------|--------|
| **Hetzner Cloud** | [177] | `/root/.hermes/scripts/.hetzner_token` + `/root/.hermes/.env` | ✅ Verified Jul 22 |
| **Cloudflare DNS** | [165] | `~/.hermes/.env``CLOUDFLARE_API_TOKEN` | ✅ Active (verified by health check) |
| **Wasabi S3** | [176] | `/root/.aws/credentials` | ✅ Active |
| **netcup API** | [166] | `~/.hermes/.env``NETCUP_API_KEY` | ✅ Active |
| **netcup CCP** | [167] | `~/.hermes/.env``NETCUP_CUSTOMER_NUMBER` + `NETCUP_CCP_PASSWORD` | ✅ Active |
| **Gitea (OLD/DEAD)** | — | ⚠️ **EXPIRED** — still in homelab + itpp-infrastructure remotes | ❌ INVALID (verified Jul 23) |
| **Gitea (ACTIVE)** | — | All other repos + `gitea-backup.sh` — ippadmin | ✅ Active (verified Jul 23) |
---
## 4. AI Provider API Keys
All stored in `/root/.hermes/.env` and Hudu API assets (layout 49).
| Provider | Hudu Asset | Purpose | Status |
|----------|-----------|---------|--------|
| **admin-ai** (LiteLLM) | [126] Hermes Primary Key | Primary model gateway (all models) | ✅ Active |
| **Anthropic** | [150] | Claude models | ✅ Active |
| **OpenAI** | [149] | GPT models | ✅ Active |
| **DeepSeek** | [152] | DeepSeek models | ✅ Active |
| **Google Gemini** | [161] / [151] | Gemini models | ✅ Active |
| **xAI (Grok)** | [154] | Grok models | ✅ Active |
| **OpenRouter** | [153] | Multi-provider routing | ✅ Active |
| **Mistral** | [155] | Mistral models | ✅ Active |
| **Groq** | [157] | Fast inference | ✅ Active |
| **Fireworks AI** | [156] | Serverless inference | ✅ Active |
| **Perplexity** | [159] | Search-augmented LLM | ✅ Active |
| **Cohere** | [158] | Cohere models | ✅ Active |
| **AI21 Labs** | [160] | Jurassic models | ✅ Active |
| **MiniMax** | [187] | MiniMax M3 | ✅ Active |
| **Z.ai (GLM)** | [188] | GLM models | ✅ Active |
| **Alibaba Qwen** | [189] Alibaba Qwen (DashScope) | Qwen models | ✅ Active |
| **Deepgram** | [162] | STT (voice transcription) | ✅ Active |
---
## 5. Communication APIs
**Storage:** All in `~/.hermes/.env` + Hudu API assets (layout 49)
| Service | Hudu Asset | Storage | Status |
|---------|-----------|---------|--------|
| **Telegram Bot** | [170] | `~/.hermes/.env``TELEGRAM_BOT_TOKEN` | ✅ Active |
| **Twilio (Live)** | [184] Twilio Live | `~/.hermes/.env``TWILIO_ACCOUNT_SID` + `TWILIO_AUTH_TOKEN` | ✅ Active |
| **Twilio (Test)** | [185] Twilio Test | `~/.hermes/.env``TWILIO_TEST_ACCOUNT_SID` + `TWILIO_TEST_AUTH_TOKEN` | ✅ Active |
| **Twilio API Key** | [186] Twilio API Key | `~/.hermes/.env``TWILIO_API_KEY_SID` + `TWILIO_API_KEY_SECRET` | ✅ Active |
| **ElevenLabs** | [148] | `~/.hermes/config.yaml` (auxiliary vision / TTS) | ✅ Active |
| **Email SMTP/IMAP** | — | `/root/.config/himalaya/shonuff.pass` | ✅ Active |
| **Email account** | — | `shonuff@germainebrown.com` — MXroute via mail.germainebrown.com:2525 (SMTP) / :993 (IMAP) | ✅ Active |
---
## 6. VoIP / RingLogix
**Storage:** `~/.hermes/.env` + Hudu API assets
| Credential | Hudu Asset | Storage |
|-----------|-----------|---------|
| **RingLogix Client ID** | [174] | `~/.hermes/.env``RINGLOGIX_CLIENT_ID` |
| **RingLogix Client Secret** | [175] | `~/.hermes/.env``RINGLOGIX_CLIENT_SECRET` |
| **RingLogix Username** | — | `~/.hermes/.env``RINGLOGIX_USERNAME` |
| **RingLogix Password** | — | `~/.hermes/.env``RINGLOGIX_PASSWORD` |
| **RingLogix Domain** | — | `~/.hermes/.env``RINGLOGIX_DOMAIN` |
---
## 7. MSP / RMM / Security APIs
**Storage:** All in `~/.hermes/.env` + Hudu API assets
| Service | Hudu Asset | Storage | Status |
|---------|-----------|---------|--------|
| **SyncroMSP** | [168] Token + [169] API Key | `~/.hermes/.env``SYNCROMSP_API_TOKEN` + `SYNCROMSP_API_KEY` | ✅ Active |
| **Bitdefender GZ** | [172] | `~/.hermes/.env``BITDEFENDER_API_KEY` | ✅ Active |
| **VirusTotal** | [171] | `~/.hermes/.env``VIRUSTOTAL_API_KEY` | ✅ Active |
| **UISP/UNMS** | [173] | `~/.hermes/.env``UISP_API_KEY` | ✅ Active |
---
## 8. Search & Data APIs
| Service | Hudu Asset | Storage | Status |
|---------|-----------|---------|--------|
| **Firecrawl** | [164] | `~/.hermes/.env``FIRECRAWL_API_KEY` | ✅ Active |
| **Exa AI Search** | [163] | `~/.hermes/.env``EXA_API_KEY` | ✅ Active |
---
## 9. Database Credentials
| Database | Host | User | Password Location | Purpose |
|----------|------|------|-------------------|---------|
| **MySQL (apex track)** | 127.0.0.1:33060 (SSH tunnel from wphost02) | `apextrackexperience_1781549652` | `wp-config.php` on wphost02 | Apex Track Experience WordPress |
| **MySQL (CloudPanel)** | app3:3306 | `root` | `/root/.my.cnf` on app3 (also in Vaultwarden) | CloudPanel WordPress hosting |
| **LiteLLM Postgres** | app1 (Docker) | (in docker-compose) | `/root/docker/litellm/docker-compose.yml` on app1 | LiteLLM operational DB |
---
## 10. Docker Services
| Service | URL | Credential Location | Storage |
|---------|-----|--------------------|---------|
| **Vaultwarden** | vault.itpropartner.com / vault.iamgmb.com | Admin Token → `/root/docker/vaultwarden/.env` on Core | Docker env file |
| **DRE Portal** | portal.debtrecoveryexperts.com | Basic Auth (htpasswd) | `/etc/caddy/dre-passwd` |
| **SearXNG** | (internal, no public endpoint) | (none) | — |
| **DocuSeal** | sign.core.itpropartner.com / sign.iamgmb.com | (none / app-managed) | — |
| **Uptime Kuma** | uptimekuma.itpropartner.com | (app-managed) | — |
| **Open WebUI** | admin-ai.itpropartner.com | `admin@itpropartner.com` (password: ask Sho'Nuff) | Not in .env |
| **Mealie** | recipe.iamgmb.com | `G@germainebrown.com` (password → Vaultwarden) | Vaultwarden |
| **Ops Portal** | ops.itpropartner.com | `ippadmin` (password → `~/.hermes/.env`) | `~/.hermes/.env` |
---
## 11. VPN & Network Keys
### WireGuard (Core)
| Item | Value |
|------|-------|
| **Interface** | `wg0` |
| **Core Private Key** | → `/etc/wireguard/wg0.conf` on Core |
| **Core IP** | `10.77.0.1/24` |
| **Listen Port** | `51821` |
| **Home Peer Public Key** | `1fPwdGQ20CxlZCQZQV134olDcE91hfp78yNDeaKJZzg=` |
| **Home Peer Endpoint** | `76.195.7.60:13231` |
| **Routed Networks** | `10.1.0.0/16`, `10.2.0.0/16`, `172.16.1.0/24`, `172.18.18.0/24` |
### Tailscale
| Node | IP | Type | Status |
|------|-----|------|--------|
| core | 100.71.155.7 | Linux | ✅ Online |
| app1 | 100.90.186.109 | Linux | ✅ Online |
| app2 | 100.117.164.66 | Linux | ✅ Online |
| app3 | 100.72.15.12 | Linux | ✅ Online |
| app1-bu | 100.112.23.21 | Linux | ⚠️ Offline (7d) |
| iphone-15-pro-max | 100.106.231.86 | iOS | ✅ Online |
| ipp-g-lap | 100.120.64.120 | macOS | ✅ Online |
| m4-mac-mini | 100.116.232.65 | macOS | ✅ Online |
---
## 12. UniFi / UDM Pro Device Keys
| Site | Key Location | Type | Status |
|------|-------------|------|--------|
| **Grand Lake Club** | UniFi Network Controller → Settings → API | Local Network API Key | ✅ Stored, pending direct verification |
| **Liberty Tire** | UniFi Network Controller → Settings → API | Local Network API Key | ✅ Stored, pending direct verification |
---
## 13. Unknown / Not Found
The following credentials are known to exist but were not found in the standard locations:
| Item | Notes |
|------|-------|
| **Open WebUI admin password** | Recovery manual says "in .env or ask Sho'Nuff" — NOT in current .env. Must ask Germaine. |
| **Hudu API key** | In skill docs (`hudu-management`) — used programmatically, not in .env. |
| **Traccar/FleetTracker360 admin** | Not in .env. May be Docker env or app-managed. |
| **Twenty CRM credentials** | Docker on Core, env at `/root/docker/twenty/.env` (not read). |
| **WordPress site DB passwords** | Various sites, typically in `wp-config.php` on wphost02 or app3. |
| **app1-bu root password** | Hetzner CPX11 — accessed via itpp-infra SSH key only. |
| **ComfyUI / Z4** | GPU server allocated for TripFlow — credentials not yet documented. |
| **Home MikroTik admin** | SSH via `admin@10.77.0.2` with `wisp_rsa` key. RouterOS password in router config (not extracted). |
---
## 14. Key Rotation & Audit Notes
- **Last full audit:** 2026-07-23
- **Last sanitization:** 2026-07-23 — all plaintext secrets removed; use Hudu + file paths for values
- **Hetzner token:** Rotated Jul 22 (old tokens in Hudu were invalid)
- **Twilio:** Live + test credentials both present in Hudu [184]/[185]/[186]
- **OpenRouter:** Fallback routing key — keep active even if not primary
- **admin-ai:** Primary gateway — all model calls route through this
- **Backups:** All .env + config files included in daily Hermes backup to S3
### Recovery Priority
If Core is lost, you need these to rebuild (in order):
1. `/root/.ssh/itpp-infra` — SSH to all servers
2. `/root/.hermes/.env` — All API keys and secrets
3. `/root/.aws/credentials` — S3 access for backups
4. `/root/.hermes/config.yaml` — Full Hermes config
5. `/root/.config/himalaya/shonuff.pass` — Email access
### Hudu API Assets (layout 49)
All API keys are documented as Hudu assets. List them via:
```
GET https://hudu.itpropartner.com/api/v1/companies/1/assets?page=1&per_page=25
```
Filter by `asset_layout_id == 49` to see all API keys with their Hudu asset IDs and storage locations.
+79
View File
@@ -0,0 +1,79 @@
# AI Model Architecture — IT Pro Partner
**Updated:** August 6, 2026
Two separate concepts: **fallback chain** (survival — direct API keys) and **operational chain** (daily toolbox — admin-ai only). The two-key strategy means operational keys run through admin-ai/LiteLLM; fallback keys are direct provider API keys with daily limits.
---
## Fallback Chain *(auto-failover — direct API keys)*
Survives admin-ai outage. All direct provider keys have daily caps. Fires in order — only when the model above is unreachable.
| Tier | Model | Provider | Key type | Daily cap |
|---|---|---|---|---|
| **Primary** | `deepseek-v4-pro` | `admin-ai` | operational | $30/mo budget |
| **F1** | `deepseek-v4-flash` | `deepseek` (direct) | fallback | $3 |
| **F2** | `gemini-3.6-flash` | `google` (direct) | fallback | $2 |
| **F3** | `grok-4.5` | `xai` (direct) | fallback | $2 |
| **F4** | `claude-sonnet-5` | `anthropic` (direct) | fallback | $5 |
| **F5** | `gpt-4.1-nano` | `openai` (direct) | fallback | $2 |
Total emergency budget: **$14/day** — down from $45 single-leg burn on Aug 5.
---
## Operational Models *(daily toolbox — admin-ai only)*
All route through admin-ai. Shared budget via `hermes-agent-v5` key.
| Role | Model | Provider | Use When |
|---|---|---|---|
| **Conductor** | `deepseek-v4-pro` | admin-ai (DeepSeek) | All standard work — orchestration, delegation, coding |
| **Workhorse** | `deepseek-v4-pro` | admin-ai (DeepSeek) | Delegated tasks, scripts, infra code |
| **Batch Workhorse** | `deepseek-v4-flash` | admin-ai (DeepSeek) | Bulk scripts, log parsing, repetitive tasks |
| **Lightweight** | `claude-haiku-4-5` | admin-ai (Anthropic) | Email triage, classification, simple tasks |
| **Simple Workhorse** | `gpt-5.6-luna` | admin-ai (OpenAI) | Lightweight tasks under 128K context |
| **Auditor** | `gpt-5.6-luna` | admin-ai (OpenAI) | Code review, QA (primary auditor) |
| **Auditor 2** | `xai/grok-4.5` | admin-ai (xAI) | Second-opinion code review (different provider) |
| **Critical** | `claude-sonnet-5` | admin-ai (Anthropic) | Client comms, legal docs, architecture (explicit) |
| **Professional Comms** | `gemini-3.6-flash` | admin-ai (Google) | Client emails, professional messaging |
---
## Admin-AI Virtual Keys
### hermes-agent-v5 (Main — Sho'Nuff)
- **Created:** Jul 31, 2026
- **Budget:** $30/day
- **Spend:** $20.36 (as of Aug 6)
- **Models (7):** deepseek-v4-pro, deepseek-v4-flash, gemini-3.6-flash, claude-sonnet-5, claude-haiku-4-5, gpt-5.6-luna, xai/grok-4.5
### Anita's Hermes Key
- **Budget:** $10/day
- **Spend:** $0.11 (as of Aug 6)
- **Models (7):** deepseek-v4-pro, deepseek-v4-flash, gemini-flash-latest, claude-sonnet-5, claude-haiku-4-5, gpt-5.6-luna, xai/grok-4.5
---
## Budget Targets
| Component | Daily est. |
|---|---|
| Conductor + Workhorse (ds-v4-pro) | ~$3.00 |
| Batch Workhorse (ds-v4-flash) | ~$0.50 |
| Lightweight (haiku-4-5) | ~$0.30 |
| Simple Workhorse (luna) | ~$0.50 |
| Auditors (luna + grok-4.5) | ~$0.80 |
| Critical (sonnet-5, sparingly) | ~$2.00 |
| **Total** | **~$7/day** |
---
## Key Decisions
- **Jul 29, 2026:** DeepSeek V4 Flash demoted from conductor to F1 fallback. Was hallucinating tool calls. V4 Pro promoted to primary conductor.
- **Jul 30, 2026:** LiteLLM key regenerated — hermes-agent-v3 created but config.yaml NOT updated. Hermes fell back to DeepSeek direct since Jul 30 19:25 UTC.
- **Jul 31, 2026:** Discovered stale key in config.yaml. Generated hermes-agent-v5 with same model list. Verified chat OK. Cleaned up stale keys (v3, v4, v4b).
- **Aug 5, 2026:** Admin-ai budget cap hit (~$20). Fallback chain exhausted 4 dead legs, landed on Anthropic direct. Burned $45 in 10 hours on claude-sonnet-5 via direct key. Anthropic key capped until Sep 1.
- **Aug 6, 2026:** Root cause of Aug 5 outage: 4 fallback legs dead simultaneously (admin-ai budget, DeepSeek balance $0, grok-4.6 404, Anthropic capped). Implemented two-key strategy (operational vs fallback). Rotated all 5 fallback keys. Added F5 (gpt-4.1-nano via OpenAI). Added haiku-4-5 and grok-4.5 to operational chain. Fixed grok-4.6 → grok-4.5. Synced Anita profile identically. Budget raised to $30.
+53
View File
@@ -0,0 +1,53 @@
# Ops v1 Retirement -- August 2026
**Created:** 2026-08-08
**Status:** Complete
---
## Summary
Ops v1 (legacy HTML pages in `/var/www/ops/`) was retired and replaced by Ops v2 (SPA at `/var/www/ops-v2/`). All orphaned HTML, CSS, and JS files were removed. Data files were migrated. Caddy and 8 Python scripts were updated. Root redirect added: `ops.itpropartner.com``ops.itpropartner.com/v2`.
## Changes
### Files Removed
- `/var/www/ops/*.html` — all legacy dashboard pages
- `/var/www/ops/css/` — legacy stylesheets
- `/var/www/ops/js/` — legacy scripts
### Files Migrated
- `/var/www/ops/data/``/var/www/ops-v2/data/`
- `ft360-devices.json`, `ft360-geocode-cache.json`, `ops-status.json`, `reolink-status.json`, `script-contents.json`
### Caddy Config
```caddy
ops.itpropartner.com {
redir / /v2/ 301
redir /v2 /v2/ 301
handle_path /v2/* {
root * /var/www/ops-v2/
file_server
}
reverse_proxy 127.0.0.1:8090
...
}
```
### Script Updates
8 Python scripts referencing `/var/www/ops/` paths were updated to use `/var/www/ops-v2/`.
## Current State
- Ops v2 SPA: `/var/www/ops-v2/index.html`
- Backend API: `127.0.0.1:8090` (ops-portal systemd service)
- Data directory: `/var/www/ops-v2/data/`
- Root redirect: `ops.itpropartner.com``/v2/` (301)
## Verification
```
ls /var/www/ops/ -> data/ (only)
ls /var/www/ops-v2/ -> index.html, data/, ...
curl -I ops.itpropartner.com -> 301 -> /v2/
```