portfolio pass: correct the CSP claim to match what nginx sends, rename the project outcome label, plain-english the projects intro and bio, standardise on Argo CD and single-touch, drop the education filler line
build-and-deploy / build (push) Failing after 14m34s

This commit is contained in:
2026-08-18 01:11:25 +10:00
parent 7542ae2665
commit 25425d6f6a
12 changed files with 26 additions and 19 deletions
+3 -3
View File
@@ -1,7 +1,7 @@
---
title: "Shipping this site: GitOps from a homelab to the public internet"
date: 2026-06-15
summary: "How this portfolio is built and served - Astro to a container image, a self-hosted Gitea registry, ArgoCD, and a Cloudflare Tunnel - with security as acceptance criteria, not polish."
summary: "How this portfolio is built and served - Astro to a container image, a self-hosted Gitea registry, Argo CD, and a Cloudflare Tunnel - with security as acceptance criteria, not polish."
tags: ["gitops", "astro", "homelab", "security"]
hero: "/blog/shipping-this-site.webp"
heroAlt: "A glowing data container travels a luminous rail from a small server rack toward a softly glowing globe of Earth, wrapped by a reconcile loop."
@@ -18,7 +18,7 @@ by GitOps. No special case for "it's just a website."
The build is baked into a hardened `nginx-unprivileged` image and pushed to a **self-hosted public
Gitea registry**, deliberately a separate instance from the private one holding my infrastructure
code, so the public artifact and the private estate never share a trust boundary. The image digest
is then pinned in a private `home-ops` repo, **ArgoCD** reconciles that repo onto the cluster, and
is then pinned in a private `home-ops` repo, **Argo CD** reconciles that repo onto the cluster, and
a **Cloudflare Tunnel** exposes exactly one service, this site, outbound-only.
Follow the chain and notice what's missing. No open ports: the tunnel dials out. No server runtime:
@@ -33,7 +33,7 @@ gesture at. The site didn't ship until every box was ticked:
```text
[x] Static output - no server runtime to attack
[x] Strict CSP, no unsafe-inline / unsafe-eval
[x] CSP: script-src 'self', no inline or eval JavaScript (style-src keeps 'unsafe-inline' for Shiki)
[x] Self-hosted fonts - zero third-party requests
[x] No secrets in the client bundle (verified by build-time grep)
[x] Outbound-only tunnel, single hostname, no catch-all
+1 -1
View File
@@ -48,7 +48,7 @@ traffic on the way out), pin-downable with a `/32`. That's how the LLM gateway's
be a single line: one legitimate consumer, the agent cluster next door, exactly one `/32` allowed in.
Here's the one that costs a 2am. I made that change with `kubectl patch` - quick, out-of-band, worked
immediately. The service was GitOps-managed with self-heal on. Within seconds ArgoCD noticed the live
immediately. The service was GitOps-managed with self-heal on. Within seconds Argo CD noticed the live
object differed from git and put it back the way the repo said, which re-enabled the SNAT, which
re-broke the policy, which took DNS down with it. **The change must be committed**, or the platform
will politely undo your fix while you sleep.