2026-05-20 · writing

Running 100 sites alone

A CLI grew out of necessity. Most of it isn't clever. All of it is automation I'd otherwise be doing in my head.

About 103 domains. Most are affiliate or content sites I built to test SEO ideas. A few are real products. The rest are music or vanity or projects-in-waiting. Some get a few hundred impressions a month, most get zero, four or five do real work. The whole portfolio is one person, me.

First 20 sites were manageable. I could remember which domain was on which Cloudflare zone, which had ads.txt configured, which Search Console properties I’d verified, which hadn’t been crawled in a month. Around 30 I started losing the thread. Around 50 my spreadsheet was lying to me because I’d stopped updating it. Around 70 I gave up on the spreadsheet and started missing things. One site’s sitemap.xml was 404ing for six months before I noticed it had zero impressions for the same period.

The pattern I kept hitting: every operation I needed to do (verify ownership, submit sitemap, audit SEO, check AI-crawler hits, reprice a domain for sale, deploy a fix) was a five-step process I had to remember the right way to do. Each step a different surface. Cloudflare API for DNS, GSC API for sitemaps, Sedo SOAP for marketplace, wrangler for deploys. Each with its own auth, its own quirks, its own way of failing silently.

So I built SiteForge. Node CLI. One binary wraps the dozen-ish operations I do across the portfolio. siteforge audit runs an SEO scan across every registered site. siteforge gsc audit pulls a 28-day Search Console summary for everything I own. siteforge sedo insert example.com 4999 lists a domain for sale and auto-adds the verification TXT record via Cloudflare DNS so I don’t have to log into two dashboards. siteforge status prints a one-screen portfolio health snapshot.

None of it is clever. Thin wrappers around APIs I already know how to call. What it buys me is reliability. I never forget the verification TXT record because the insert command always does it. I never miss a broken sitemap because the audit reports it. I never check the same site twice because the registry is the source of truth.

The boring part is the registry. A JSON file at ~/.config/siteforge/sites.json that lists every site with its category, type, niche, and project directory. Boring, and the most important part of the whole thing. Without it the rest of the CLI has nothing to iterate over. I add a site once by hand, and from that point everything else runs against the list.

About three months in evenings and weekends. Month one was scaffolding the command structure and getting the GSC and Sedo integrations working. Month two was SEO tooling (audit, optimize, keyword research, competitor analysis). Month three has been operations: portfolio snapshots, daily error capture, cron-watchdog for the scheduled jobs, AI-crawler tracking, a Cloudflare log explorer.

The result is I run more sites than I did six months ago with less daily effort. Most days I look at one report (the portfolio digest) and react to whatever’s flagged. The CLI does the rest. When something new comes up (Bing Webmaster integration, a new analytics endpoint, Amazon Associates compliance) I add a command for it instead of doing it by hand.

A hundred sites is not a lot if you have automation. A hundred sites is impossible if you don’t. The lesson, repeated, is that the tools are the multiplier.