This site runs on Hugo, deployed to GitHub Pages a self-hosted Hetzner box with Cloudflare CDN. Images are hosted on R2 (static.philippdubach.com) with automatic resizing and WebP conversion.
Analytics run on a privacy-friendly, self-hosted GoatCounter instance, no cookies, no fingerprinting. The newsletter is delivered through a self-hosted Listmonk. Source code lives on a self-hosted Forgejo git remote. Outbound mail flows through Resend over standard SMTP.
Updates
May 2026
Hetzner Cutover. Apex DNS moved from GitHub Pages to a self-hosted box after a full restore-from-backup drill on a parallel staging instance. Hugo now builds on the host itself, triggered by a push webhook on the internal git remote.
Self-Hosted Stack. Reverse proxy with automated TLS, managed databases for the supporting services, nightly off-site backups to object storage with monthly integrity checks and alerts on failure. The newsletter system runs on the same box; signups dual-write so an outage on any single component doesn’t drop them.
Edge Hardening. Added Cloudflare Cache Rules for HTML, feeds, and static assets, plus rate limiting on admin login paths. The security-headers Worker was updated so origin redirects propagate cleanly through the edge instead of being silently flattened.
Cron Reliability. Scheduled rebuilds moved off GitHub Actions cron (drifts 30+ min, occasionally skips during platform incidents) onto a Cloudflare Worker that fires workflow_dispatch on a deterministic schedule. Builds still run on Actions; only the trigger moved. Cadence increased from 3× daily to every 3 hours, so max publish delay for future-dated posts dropped from ~7h to ~3h.
Hugo 0.161.1 Upgrade. Bumped from 0.157.0. Byte-identical output, zero deprecation warnings. Added a local diff harness that builds with two Hugo versions and diffs the output, used to validate the bump as a no-op. Newer Hugo internals let 8 of 9 post-render regex passes in the markdown variant template go away, one of them was actively harmful, corrupting Wikipedia URLs like Universal_Serial_Bus_\(USB\) into garbled text.
Index Redesign. Articles and projects now share the same structure: hero dropped, the featured row is the masthead (red overline, thin red rule, large headline), hairline divider, filter chips reframed as “browse the archive” rather than page nav. Featured card image now requests a 1200×630 landscape source matching the CSS aspect ratio (was getting a portrait stretched sideways, which clipped faces).
Markdown Variant Maturity. Markdown alternates now emit clean output via output-format-aware sibling shortcodes. HTML pollution never enters the markdown stream. YAML preamble parseable by every major LLM tooling SDK. Section gate dropped so /about/, /research/, /subscribe/ ship real markdown content too.
Worker Audit. Three parallel reviews (perf, reliability, security) of the Hugo site and Cloudflare Workers shipped fixes for several social-automation bugs: Bluesky’s 300-char post limit was being silently exceeded when an appended URL pushed length over budget, leaving stuck-loop posts; cron ticks could race the same article; the bluesky worker was fetching each article URL twice per post. Added a sanitizer at a Worker boundary so a downstream consumer using innerHTML can’t execute script regardless of how the rendering side is written.
Template Hardening. readnext shortcode now warns at build time when the slug doesn’t match a post, instead of silently rendering nothing. FAQ aggregation extracted to a cached partial. Homepage and projects ItemList JSON-LD capped at 20 entries (Google rich-result band). posts.json prefers .Description over .Summary to skip 86 of 87 markdown renders at build time.
Decommissioning. Removed two unused projects (a post composer and a URL shortener). Deleted source from the repo, then deleted the corresponding Pages projects and KV namespaces.
Accessibility. Sidebar wordmark aria-label now starts with the visible text per WCAG 2.5.3 (voice-control users saying “click philippdubach” can now activate it). Newsletter card meta switched to a secondary text token for 7.0:1 contrast on the pink tint (was 3.91:1, below AA).
April 2026
Agent Readiness. Shipped three coordinated changes so AI agents and content-aware crawlers can discover and consume the site through standardized protocols. Every response now carries a Link: header (RFC 8288) advertising machine-readable resources. A new /.well-known/api-catalog endpoint returns an RFC 9264 Linkset enumerating those endpoints (RFC 9727). Content negotiation works: requesting any page with Accept: text/markdown returns a markdown variant with the right Content-Type and a token-count header for LLM context-window planning. The robots.txt declares Content-Signal directives per draft-romm-aipref-contentsignals.
Worker Refactor. The security-headers Worker grew from one file into a handful of focused modules with unit-test coverage. The cache module is the interesting bit: Cloudflare’s edge cache doesn’t honor Vary: Accept by default, so the Worker uses the Cache API to keep HTML and Markdown variants isolated under the same URL. Origin fetches HTML or rewrites to a markdown variant based on the client’s Accept header.
March 2026
Hugo Upgrade. Upgraded from Hugo v0.128.0 to v0.157.0. Migrated deprecated .Site.AllPages to .Site.Pages in the sitemap template and .Site.Data to site.Data across navigation, structured data, and research templates. Removed a dead readFile security config key from hugo.toml. No breaking changes, zero deprecation warnings.
February 2026
Frontmatter Unification. Converted all 70 YAML frontmatter posts to TOML and added Key Takeaways to all 73 posts. Takeaways render as a visible summary box between the post header and content body, optimized for Generative Engine Optimization (GEO) so AI search engines can extract citation-ready passages.
Design Streamlining. Unified left-bordered aside components (key takeaways, newsletter CTA, disclaimer) to consistent 3px borders and aligned padding. Established a vertical spacing rhythm across post zones: key takeaways, content body, newsletter CTA, footer divider, related posts. Added breathing room around images (1.5rem padding). Refined key takeaways heading to 0.85rem uppercase label with square bullets.
Homepage Redesign. Rebuilt the homepage with a tabbed layout (Articles/Projects), year dividers, and thumbnail images served via Cloudflare Image Resizing. Consolidated navigation into a unified sidebar.
Security Headers Worker. Deployed a dedicated Cloudflare Worker on philippdubach.com/* that injects HSTS, CSP with frame-ancestors, COEP, COOP, and Permissions-Policy headers. GitHub Pages doesn’t process _headers files, so the Worker fills that gap. SHA-pinned all GitHub Actions and added Hugo binary checksum verification in CI.
Machine-Readable Feeds. Added JSON Feed 1.1 alongside RSS, a Posts API for programmatic access, and llms.txt/llms-full.txt for AI crawler discovery. All output formats configured in hugo.toml.
GoatCounter “Most Read” API. Built a Cloudflare Worker proxy that queries the GoatCounter API for the top 10 posts over the past 7 days. The footer’s “Most Read” section now fetches live data from this worker instead of a static list.
FAQ Section. New /faq/ section with per-category pages (Finance, AI, Tech, Economics, Medicine). Each post can define faq entries in frontmatter; Hugo aggregates them into browsable FAQ pages with FAQPage structured data for search engines.
Readnext Shortcode. Inline “Related” link to another post: {{< readnext slug="post-slug" >}}. Links are validated against live permalinks at build time.
RSS Feed Fixes. Stripped lightbox overlay elements from full-content RSS to prevent images appearing twice in feed readers. Added XSLT stylesheet for browser-friendly RSS rendering.
Cloudflare Cache Purge. GitHub Actions deployment now automatically purges the Cloudflare cache after each build.
Research Page. Dynamic /research/ page pulling publication data from data/research.yaml with SSRN links, DOIs, and structured data.
January 2026
Social Automation & AI Model Upgrade. Upgraded Workers AI model from Llama 3.1 8B to Llama 4 Scout 17B for better post generation. Added Twitter/X automation worker alongside Bluesky. AI generates neutral, non-clickbait posts with extensive banned word filtering.
UI/UX Polish. Fixed mobile footer spacing consistency. Increased homepage post spacing (3.75rem). Disclaimers now only display on individual posts, hidden on homepage. Centered related posts heading.
Content Organization. Taxonomy system with categories (Finance, AI, Medicine, Tech, Economics) and types (Project, Commentary, Essay, Review). Hugo generates browsable /categories/ and /types/ pages.
Disclaimer Shortcode. Six types: finance, medical, general, AI, research, gambling. Syntax: {{< disclaimer type="finance" >}}.
IndexNow Integration. Automated submissions via GitHub Actions for faster search engine discovery. Only pings recently changed URLs based on lastmod.
December 2025
Code Blocks. Syntax highlighting via Chroma with line numbers in table layout. GitHub-inspired color theme.
Newsletter System. Integrated email subscriptions via Cloudflare Workers + KV. Welcome emails via Resend.
Security & Performance Audit. Fixed multiple H1 tags per page. Hardened CSP with frame-ancestors. Added preconnect hints for external domains. Added seoTitle frontmatter for long titles.
November 2025
Shortcodes. HTML table shortcode. Lightbox support on images.
June 2025
SEO & Math. Open Graph integration for social previews. Per-post keyword management. LaTeX rendering via MathJax 3 (conditional loading).
May 2025
Full Rebuild. Migrated from hugo-blog-awesome fork to fully custom Hugo build.