This colophon documents every infrastructure choice behind Build Sovereign. The blog writes about data sovereignty; its own infrastructure is the first argument it makes. Every choice below is verifiable by inspecting this site’s source on GitHub.
Static site generator
Hugo — a single signed Go binary with no runtime dependencies. No npm, no gem toolchain, no transitive dependency tree. The build is hugo --gc --minify and nothing else. A saved Hugo binary continues to produce the same HTML years from now even if upstream goes away — important for a blog whose archive is itself a sovereignty argument.
See ADR 0001.
Theme
PaperMod, forked and vendored. The theme files are committed directly into this repository under themes/PaperMod/. No git submodule, no Hugo module. Upstream updates are manual, diff-reviewed copies — we review every change before adopting it and never get surprised by an upstream commit. The fork is re-skinned with the Sovereign Editorial design system via project-layer template and CSS overrides.
Source host
GitHub — the canonical source repository. The choice of source host is independent of the build and serving layer; a future migration to a EU non-profit forge is reserved but not pursued now.
See ADR 0002.
Build
On the VPS, via the author’s existing deployment pattern (Ansible + make + compose). The blog is built on the same EU VPS that serves it, using the same deploy pattern as every other RightThing Studio project. Hugo is a single binary; the build step is hugo --gc --minify. No CI runner is required for the build to happen — the VPS itself runs the build. A proper CI/CD pipeline may follow later; for now, deploy is driven by the author’s existing infra codebase, which is out of scope for this repo.
Serving
Self-hosted EU VPS with nginx. Static HTML is served from a EU VPS under the author’s control, via nginx. TLS is handled by Let’s Encrypt (certbot or the author’s existing TLS automation). The VPS is the same box — and the same deploy pattern — that serves every other RightThing Studio project. One DNS boundary, one deploy pattern, one set of infrastructure to reason about.
Fonts
Bunny Fonts — EU-hosted, zero-logging, GDPR compliant. Source Serif 4 and Inter are loaded via a single <link> in the HTML head. No Google Fonts. Bunny Fonts does not log reader IPs, does not share data, and is the only external resource loaded by the browser.
Analytics
Self-hosted Umami in cookieless mode on a EU VPS. No third-party analytics SaaS processes reader data. Pageview events only — no user identifiers, no cross-site tracking, no cookies.
The Umami tracker is served same-origin via an nginx reverse proxy: the browser loads /stats.js and POSTs pageviews to /api/send, both on buildsovereign.xyz, and nginx forwards them to the self-hosted Umami instance on a separate EU VPS. This is Umami’s bypass-ad-blockers pattern: the reader’s browser never sees a third-party analytics domain in the page source, and the CSP does not need to allow one. data-do-not-track="true" honours the reader’s DNT signal; data-exclude-search="true" strips query strings from reported URLs.
See ADR 0003.
Charts
Chart.js v4.4.3 vendored into the repository and served first-party from the blog’s own origin (/js/chart.umd.min.js). No CDN. Used for Benchmark vein articles requiring interactive charts. A <noscript> fallback shows the data as a table for JS-disabled readers.
Syntax highlighting
Hugo Chroma — server-side syntax highlighting at build time. A light Chroma theme matching Sovereign Editorial (ink text on slightly-tinted background). One CSS file shipped; no client-side highlighter JavaScript.
Comments
None. No comments system is planned. If ever added, it would require a separate server-side component, which contradicts the static-hosting posture unless a VPS is spun up.
Third-party runtime dependencies
None on reader data. The only external resource loaded by the browser is Bunny Fonts (EU, zero-logging). The only scripts are first-party: vendored Chart.js (same-origin, loaded only on benchmark articles) and the self-hosted Umami analytics script (also same-origin, via the /stats.js reverse proxy). No Google Analytics, no Google Tag Manager, no Disqus, no comment SaaS, no CDN that logs reader IPs.
Content-Security-Policy
A strict Content-Security-Policy header is set via nginx — a capability available on a self-hosted VPS with full control over HTTP response headers. The header is:
default-src 'self';
base-uri 'self';
object-src 'none';
font-src https://fonts.bunny.net;
script-src 'self';
style-src 'self' https://fonts.bunny.net 'unsafe-inline';
img-src 'self' data:;
connect-src 'self';
Rationale per directive:
default-src 'self'— the baseline: everything defaults to the blog’s own origin. Any resource type not explicitly listed below inherits this restriction.base-uri 'self'— set explicitly becausedefault-srcdoes not cover<base>; prevents an injected<base>tag from hijacking relative URLs (script loads, link targets, form actions) to an attacker-controlled origin.object-src 'none'— forbids<object>/<embed>/<applet>plugins entirely. The site uses none; this is defence-in-depth against a future template change that introduced one.font-src https://fonts.bunny.net— fonts are the only external resource loaded by the browser. Bunny Fonts is EU-hosted and zero-logging (see Fonts above). This is the dogfooding line: one external dependency, named explicitly, justified.script-src 'self'— scripts may come only from the blog’s own origin: vendored Chart.js, the chart initialiser on benchmark articles, and the self-hosted Umami tracker served via the/stats.jsreverse proxy. No'unsafe-inline': chart data is passed via<script type="application/json">data blocks (non-executable, not governed byscript-src) and the initialiser lives in a same-origin/js/chart-init.jsfile. No cross-origin script source is permitted, so no third-party analytics SaaS, comment SaaS, or CDN can inject scripts even if a future template change tried to.style-src 'self' https://fonts.bunny.net 'unsafe-inline'— styles load from the blog’s own origin and from Bunny Fonts (the font CSS athttps://fonts.bunny.net/css?...is a stylesheet, governed bystyle-srcnotfont-src).'unsafe-inline'is required for the vein-labelstyle="--vein-color: ..."attributes emitted inline by the article-list and article-page templates; this is the only'unsafe-*'directive in the policy. No inline styles load third-party resources.img-src 'self' data:— images load from the blog’s own origin, withdata:URIs permitted for the occasional inlined SVG or small inline image. No third-party image hosts.connect-src 'self'— XHR/fetch endpoints are limited to the blog’s own origin. The Umami tracker POSTs pageviews to same-origin/api/send(which nginx proxies to the analytics VPS); the browser never opens a connection to a third-party analytics domain.
Content licensing
Content licensing terms for articles and the theme fork are not yet decided. This section will be updated when a license is chosen.