12 KiB
Launch Checklist — Post-Cutover Status
www.bluecapstrategies.com went live on the Astro rebuild on 2026-10-23. This file is now the
single source of truth for what is running, how it is wired, and what is left. The pre-launch
runbook it replaced is in git history (git log -- docs/launch-checklist.md, before 2026-10-23).
Status legend: [ ] open · [x] done · [?] needs verification · 🛑 owner decision
0. As-built state (2026-10-23)
| Thing | State |
|---|---|
| Public site | https://www.bluecapstrategies.com — canonical. Apex 301s to www, path preserved |
| Old WordPress / Bluehost | Gone. Access lost and it was returning 404 before cutover; nothing to roll back to |
| DNS | Cloudflare, DNS-only (grey cloud) for apex, www, stats → 23.94.111.133 |
| Edge | Pangolin VPS 23.94.111.133 (Traefik + CrowdSec), org rhh-homelab, site 7tl_lab |
| Pangolin resources | Bluecap-www, Bluecap-base, stats — 3 https targets 10.66.15.30/.31/.32:443 each |
| Edge certs | Let's Encrypt HTTP-01 via Pangolin's letsencrypt resolver, issued 2026-10-23 |
| Cluster certs | cert-manager letsencrypt-prod DNS-01: bluecap-website-tls (www + apex), bcs-int-tls |
| ArgoCD | bcs-website and umami — Synced / Healthy |
| Deployed image | tracks main via CI tag-bump (ci: deploy <sha> commits) |
| Staging | https://bcs.int.7tl-homelab.com — LAN only |
| Contact form | Formspree, verified end to end 2026-10-09 |
| Analytics | Umami (self-hosted, stats.bluecapstrategies.com) + GA4 G-Z273QL1F0N, both verified recording 2026-10-23 |
| Monitoring | monylog blackbox probes on www + apex → Alertmanager → Pushover; UptimeRobot (external) → Pushover |
| Search | Google Search Console domain property verified; sitemap submitted and fetched by Googlebot |
MXroute. SPF pass, DKIM pass (selector x), DMARC p=none — mail-tester 9.5/10 |
|
npm run build / typecheck / seo:lint |
green, 21 pages |
npm run test:e2e |
48/48 green |
Traffic path
visitor → Cloudflare DNS (DNS-only) → Pangolin VPS 23.94.111.133 (TLS #1, CrowdSec)
→ gerbil/newt tunnel → k3s traefik 10.66.15.30/.31/.32 :443 (TLS #2)
→ bluecap-website (nginx, 2 replicas) ns bluecap-strategies
→ umami (+ umami-postgres) ns umami
1. Open — do soon
1.1 External uptime check ✅ 2026-10-23
monylog runs inside the homelab, so a homelab power or internet outage takes the site and its monitor down together, and nothing pages. Needs a vantage point outside the homelab.
- UptimeRobot (free tier, 5-min interval) probes
https://www.bluecapstrategies.com/. - Alerts go to Pushover via a separate email alert contact (the
@pomail.netgateway address), not the account email, so password resets etc. stay in the normal inbox. - Reading alerts: UptimeRobot and monylog both firing = site/VPS problem; UptimeRobot alone (monylog silent) usually means the homelab itself is down.
1.2 Homelab intercepts port-53 DNS
Found 2026-10-23. Queries from the homelab — including k3s nodes — to any DNS server, even
Cloudflare's authoritative NS, are answered by a local recursive resolver (dig @arely.ns.cloudflare.com
returns rd ra with no aa). A name looked up before its record exists gets NXDOMAIN cached for
30 minutes (the zone's SOA negative TTL).
This, not Cloudflare, explains the 4-hour cert-manager DNS-01 stall of 2026-10-09 and the
stats NXDOMAIN at launch. Consequences:
-
Pointing cert-manager at
1.1.1.1/8.8.8.8(the fix previously suggested here) will not help while port 53 is intercepted. -
To see true public DNS, query from the VPS or via DoH:
curl -H 'accept: application/dns-json' 'https://cloudflare-dns.com/dns-query?name=<name>&type=A' -
Create DNS records before anything in the homelab (cert-manager included) looks the name up.
-
🛑 Owner decision: leave as is, or exempt the k3s nodes from the redirect. The redirect rule is not in
~/Homelab/mikrotik/*.rsc; find it on the router (or Pi-hole/AdGuard, if any). -
umami-stats-tls(internal hop forstats) stalled on the stale NXDOMAIN at launch and issued by itself once the cache expired (~18:35 UTC, 2026-10-23) — the expected pattern.
1.3 Gitea runner loses Docker after a dockerd restart
dockerd on gitea-1 runs with live-restore=true. When it restarts, containers keep running
but act_runner's bind mount of /var/run/docker.sock points at the dead socket, so every CI
job fails in its first second with Cannot connect to the Docker daemon. Happened 2026-10-21 →
discovered 2026-10-23.
- Workaround:
sudo docker restart act_runneron gitea-1. - Durable fix in the
giteaansible role (2026-10-23): adocker.servicedrop-in (/etc/systemd/system/docker.service.d/restart-act-runner.conf, templatedocker-restart-act-runner.conf.j2) whoseExecStartPostrestartsact_runnerwhenever dockerd starts. Live-restore stays on, so Gitea itself keeps running through dockerd restarts. - Apply it: run
gitea-deploy.yml(daemon-reload only, nothing restarts), then confirm withsystemctl show docker -p DropInPathson gitea-1. Optional proof, when no CI job is running:sudo systemctl restart dockerand checkdocker inspect -f '{{.State.StartedAt}}' act_runnermoved forward.
1.4 /insights/ ✅ 2026-10-23
Now a reader-facing "Coming soon" page (hero + contact CTA); the developer-facing cards are gone. It stays in the nav. When the first real article lands, restore a listing on this page.
1.5 Privacy policy ✅ 2026-10-23
/privacy/ reviewed and accepted by the owner. No consent banner (owner's call).
Anything added to src/components/Analytics.astro must be disclosed on /privacy/.
2. Should fix
2.1 e2e suite ✅ green 2026-10-23 — 48/48
The stale assertions (invented copy removed by the exact-copy work) now check the real headings
and use the header Services link; the homepage body has no direct /services/ link.
2.2 Repo hygiene ✅ 2026-10-23
Commit 9f1cbca had committed 51 .playwright-mcp/ screenshots/snapshots plus a 2.8 MB
home-full.png at the repo root. Now untracked (files kept on disk) and ignored:
.gitignore has .playwright-mcp/ and /*.png; .dockerignore also drops them plus
planning/ and tests/ from the build context. History was not rewritten (.git is 17 MB —
not worth a force-push).
2.3 DMARC tightening
- Tighten DMARC from
p=nonetop=quarantineafter a few weeks of clean reports to info@bluecapstrategies.com.
3. Owner decisions (Brad)
- Canonical host —
www(2026-10-23). Apex 301s via Traefik middleware ink8s/ingress.yaml. - Analytics — Umami + GA4 side by side (2026-10-23).
- 🛑 Contact details — confirm
804-332-6618/info@bluecapstrategies.comare final. - AI training-bot policy — training crawlers blocked (2026-10-23): GPTBot, ClaudeBot, Google-Extended, CCBot, Applebot-Extended, meta-externalagent, Bytespider. Search and AI answer/search crawlers (Googlebot, Bingbot, OAI-SearchBot, Claude-SearchBot, …) stay allowed.
- 🛑 Brad Rodgers bio + credentials + portrait — gates
Personschema, the About buildout, and principal-led E-E-A-T/GEO positioning. - 🛑 Real insights articles — no fabricated or unreviewed AI content.
/insights/is "Coming soon" until the first one exists (§1.4). - 🛑 Social profiles — provide real profiles or omit the footer block.
- 🛑 Proof modules / representative engagements — no fabricated client work.
4. Post-launch improvements (not blocking)
- Bing Webmaster Tools — import from Search Console (covers Bing, DuckDuckGo, ChatGPT search).
- Check Search Console in ~1 week: sitemap "Success", pages indexed, no 5xx in Coverage.
- Per-page 1200×630 OG images;
BaseLayout.astroemits one shared fallbackog:image. robotsmeta wired to anoindexfrontmatter flag./thank-you/is excluded from the sitemap but emits nonoindexmeta tag.article:published_time/article:modified_timeOG tags on insights posts.lastmodin the sitemap from content dates.- Lighthouse ≥ 95 on SEO / Perf / Best-Practices / Accessibility.
- Umami/GA custom event for contact-form submits (today the
/thank-you/pageview is the conversion signal). - Optional: move
bluecapstrategies.cominto Pangolin'sconfig.ymldomains:so it shows "Config Managed" like the other three (needs a Pangolin restart; purely cosmetic). - Deferred: VPS static failover for homelab outages (see memory note / earlier discussion).
5. Launch-day record (2026-10-23)
What happened, so it does not have to be rediscovered.
- Pangolin certs need a real config change to retry. HTTP-01 failed while
wwwwas still proxied (Let's Encrypt reached Cloudflare's IPv6, got 404) and hit the 5-failures/hour limit. Clicking Save with no changes does nothing; toggling Enable Resource off/on (saving between) re-adds the router and triggers issuance. - Pangolin health checks probe the target IP with no hostname, which k3s traefik answers with
404. Set the health check's Host header and TLS server name to the resource's hostname, path
/(or/api/heartbeatfor Umami), expect 200. - nginx 404 loop —
error_pagepointed at/404/index.htmlbut Astro emits404.html, so every unknown URL returned 500. Fixed ind1c1726; unknown URLs now return a real 404. - CI tag-bump push rejected when
mainmoved during a build (or on a re-run of an older commit). The step now rebases ontoorigin/mainand retries (93415c6). Do not "re-run" old runs to deploy — push instead. - Cloudflare cleanup — removed all Bluehost/cPanel leftovers (autoconfig/autodiscover,
cpanel/whm/webdisk/ftp, cal/carddav SRV,
localhost), replaced Bluehost'sdefault._domainkeywith MXroute'sx._domainkey, added_dmarc. - Monitoring safety — the monylog playbook only renders Pushover routing when
VAULT_TOKENis set; without it Alertmanager silently falls back to ntfy. Always run it with the token. - Umami ships with
admin/umami. It was brought up LAN-only (umami.int.7tl-homelab.com), the password changed, and only then exposed via Pangolin. Manifests live inhomelab-gitops(apps/umami.yaml,analytics/umami/); credentials in OpenBaocluster/umami.
6. Already done — do not redo
- Full copy parity with the WordPress site, verbatim in content collections (ADR-0002).
- Real imagery in
public/assets/live-site/; placeholders deleted. - Zod
seoSchema;scripts/seo-lint.mjs(npm run seo:lint). BreadcrumbListschema across detail pages.- Per-agent
public/robots.txt;@astrojs/sitemapexcluding/thank-you/. - Draft insights excluded from routes and sitemap.
- Contact form: build-time Formspree endpoint, background submit, honeypot, failure fallback.
- GitOps: Gitea Actions CI → Gitea Packages → tag-bump commit → ArgoCD (ADR-0007, ADR-0008).
- CI job image
node:22-bookworm; docker CLI + kustomize as pinned static binaries. - Production TLS in-cluster (DNS-01) and at the edge (HTTP-01).
- Canonical www + apex 301; real 404s.
- Monitoring: blackbox probes +
WebsiteDown/WebsiteCertExpiringSoon/WebsiteSlow/BlackboxExporterDownrules in the monylog role (ADR-0004: monylog, not Uptime Kuma). - Analytics: Umami + GA4, production-host only;
/privacy/page. - Search Console verified; sitemap submitted.
- Mail authentication: SPF, DKIM, DMARC passing.