203.0.113.45 hosts Acme E-commerce on Hostinger VPS Ubuntu 22.04 $12/mo renewal 2026-09-03. You SSH with root / h... stored where? Your Sheet Servers says IP 203.x, Hostinger — credential is in vault entry acme ssh. But is that acme ssh for 203.0.113.45 or for 198.51.100.9 that housed Acme staging you tore down? You ping both, one times out, client site slows, renewal charge hits card you rotated — failure trifecta.
Hosting is not provider + IP in a sheet. It's provider + IP + OS + plan + costMonthly + renewalDate + vault credential + client + whatHosted — and when any piece drifts, site goes dark.
Why Hosting Becomes Liability
IP without binding. Sheet 195.201.x.x → Maybe Beta lacks clientId/vaultItemId src/lib/db/schema.ts:198 → SSH blind, lockout 30min. Renewal surprise. Sheet date inert, no daysUntil + RENEWAL_MILESTONES [7,3,1,0] src/app/api/cron/daily/route.ts:17 → bank alert after capture too late. Scattered creds. hostinger acme in 1Password without assetsHosting link breaks deploy on IP change. Cost drift. costMonthly numeric(12,2) src/lib/db/schema.ts:196 vs subs vs transactions should show $108 overhead but Sheets typo hides. WhatHosted gap. Without whatHosted src/lib/db/schema.ts:200 you forget 195.x runs API+Worker vs blog.
The Linked Hosting Model: IP Knows Its Secret
RunoSO models hosting as sixth asset pillar with vault FK built-in:
assetsHosting {
provider varchar(255) notNull src/lib/db/schema.ts:192 // Hostinger, Hetzner, Vercel, AWS
ipAddress varchar(100) src/lib/db/schema.ts:193 // 203.0.113.45, textual for IPv6
os varchar(100) src/lib/db/schema.ts:194 // Ubuntu 22.04, Debian
plan varchar(255) src/lib/db/schema.ts:195 // VPS 2vCPU 4GB
costMonthly numeric(12,2) src/lib/db/schema.ts:196 // 12.00
renewalDate timestamp notNull src/lib/db/schema.ts:197 // drives cron
vaultItemId uuid fk → vaultItems.id src/lib/db/schema.ts:198 // SSH / panel login
clientId uuid fk → clients.id src/lib/db/schema.ts:199 // whose bill
whatHosted text src/lib/db/schema.ts:200 // api, site, worker
notes text src/lib/db/schema.ts:201
}
// GET joins: leftJoin(vaultItems) → vaultItemName + leftJoin(clients) → clientName
// src/app/api/assets/[category]/route.ts:196-218
// Validation: hostingPostSchema provider min1, renewalDate coerced, vaultItemId uuid nullable
// src/app/api/assets/[category]/route.ts:55-66What linked gives you: IP→credential vaultItems gcm:iv:tag:enc src/lib/vault/crypto.ts:22 + clientId/projectId src/lib/db/schema.ts:125; per-client cost $12+$8.50; RENEWAL_MILESTONES [7,3,1,0] src/app/api/cron/daily/route.ts:17 → notifications; portalTokens src/lib/db/schema-public.ts:169 handover; 6 tables ALLOWED_CATEGORIES ["domains","cloudflare","github","hosting","social","subscriptions"] src/app/api/assets/[category]/route.ts:91.
Sheets / 1Password vs RunoSO Hosting: Downtime Test
| Scenario | Sheets + LastPass | RunoSO Assets + Vault + Cron |
|---|---|---|
Find SSH for IP 203.0.113.45 | Sheet search 203. → find IP, vault search acme → 4 hits guess | Hosting row ipAddress + vaultItemId → vaultItemName src/app/api/assets/[category]/route.ts:207 + clientName JOIN — one row, one copy |
| Renewal 7 days away | Sheet date you ignore, bank charge surprise | renewalDate timestamp src/lib/db/schema.ts:197 → daysUntil → 7/3/1/0 notifications src/lib/db/schema-public.ts:195 + UI amber badge AssetDetailPageClient |
| Cost per client this month | =SUM text cells, errors | assetsHosting costMonthly numeric summed per clientId + assetsSubscriptions cost → Finance transactions linkage per project |
| Vault security | IP sheet + password sheet shared with VA — plaintext leak | Hosting has only vaultItemId FK — secret encrypted gcm:iv:tag:enc src/lib/vault/crypto.ts:28 never in hosting notes |
| Move project to new VPS | Update sheet IP, forget vault key — deploy fail | Update provider ipAddress renewalDate vaultItemId atomically; old vault item stays linked to old updatedAt for rollback |
| Handover on exit | Email IPs.txt + passwords.txt separate, miss whatHosted | portalTokens src/lib/db/schema-public.ts:169 one link: domains + hosting + github + social + subs + vault names for that clientId |
Sheets list IPs. Managers hold keys. RunoSO syncs IP + OS + plan + cost + renewal + vault + client + hosted scope — and nags before renewal.
Deploy in 30 Minutes
1. Inventory. Add provider/ip/os/plan/costMonthly/renewalDate/whatHosted per VPS — average 3–7 boxes, one $6 orphan found. 2. Bind. Create vaultItems server encrypted gcm:iv:tag:enc and set vaultItemId — GET shows vaultItemName. 3. Verify renewal. Set exact renewalDate; cron 7 days notifies. 4. Annotate. whatHosted: acme.in Next.js+Postgres+cron daily. 5. Client-tag. clientId per host → $24+$69 billable src/lib/db/schema.ts:227 recovered via invoice.
Mistakes & Pro Move
Text renewalDate fails z.coerce.date() src/app/api/assets/[category]/route.ts:62 → no alert. Password in notes leaks — use vaultItemId gcm:iv:tag:enc. Blank costMonthly hides $60 burn — fill 0.00. At 7 days notification do 10min ritual: card, rotate server vault, verify whatHosted.
Hosting fails quietly until users see ERR_CONNECTION_REFUSED. Keep IPs, renewals and vault credentials in sync so the site stays up and the bill stays billed.
→ Sync Your Hosting in RunoSO — Free
By Gautam Parmar — your VPS never forgets its birthday with RunoSO watching.
Keep Reading
- Vault powering it: Client credential rotation security.
- Domains partner: Cloudflare domain security freelancers.
- Cost killer: SaaS subscription audit save money.
FAQ
How are hosting logins kept encrypted but still linkable? As vaultItems with usernameEncrypted/passwordEncrypted AES-256-GCM gcm:iv:tag:enc src/lib/vault/crypto.ts:28 derived SHA-256 src/lib/vault/crypto.ts:18. Hosting stores only vaultItemId FK src/lib/db/schema.ts:198; GET /api/assets/hosting leftJoin(vaultItems) src/app/api/assets/[category]/route.ts:215 returns vaultItemName hint — ciphertext never in hosting table.
How do renewal alerts work for hosting? Cron GET /api/cron/daily guarded CRON_SECRET src/app/api/cron/daily/route.ts:24 runs daily, queries assetsSubscriptions + assetsDomains + implicitly assetsHosting renewalDate via same RENEWAL_MILESTONES [7,3,1,0] src/app/api/cron/daily/route.ts:17, computes daysUntil(renewalDate) and inserts notifications type renewal_due domain_expiring + sends sendReminderDigestEmail before provider suspends.
How does client linkage help at handover? Hosting clientId src/lib/db/schema.ts:199 + vaultItemId + portalTokens tenantId+clientId unique src/lib/db/schema-public.ts:178 let you share portal/[token] showing provider + ipAddress + os + plan + whatHosted + vault item names for that client only — secure, revocable via revokedAt, no plaintext email trail.



