How This Site Works
I figured the site itself deserves a post. Here’s how it all fits together.
The stack
- Framework: Astro — static site generator that ships zero JavaScript by default
- Theme: Spectre — a terminal-inspired dark theme with that nice glow effect
- Content: MDX files for posts, projects, resume, and about page
- Search: Pagefind — runs at build time, generates a static search index
- Code blocks: Expressive Code with a custom dark theme
- Hosting: Cloudflare Pages — free, fast, auto-deploys from GitHub
- Domain:
me.ashnet.onlinevia Cloudflare DNS (managed with Terraform, naturally)
Why Astro?
I wanted something that spits out static HTML with no client-side framework bloat. Astro does exactly that. Content lives in MDX files with frontmatter, the build step handles all the image optimisation and sitemap generation, and what you get is a fast, lightweight site.
No React runtime. No hydration. Just HTML and CSS with some sharp image processing courtesy of Sharp.
Content structure
Everything lives under src/content/:
src/content/├── posts/ # Blog posts (MDX)├── projects/ # Project writeups (MDX)├── other/ # About page, resume├── assets/ # Images for posts├── info.json # Quick info sidebar items├── socials.json # Social links├── work.json # Work experience entries└── tags.json # Tag definitionsPosts and projects use Astro’s content collections — type-safe frontmatter, automatic slug generation, the works. Adding a new blog post is just creating an MDX file with the right frontmatter and pushing to master.
The homepage
The homepage pulls everything together in a two-column layout:
Left sidebar:
- Profile picture with a glow effect
- Quick info (role, location)
- Social links
- A random GitHub starred repo (fetched at build time from the GitHub API)
Main content:
- About section
- Latest blog posts
- Recently starred GitHub repos (top 10)
- Latest projects
- Work experience timeline
The starred repos section hits the GitHub API at build time — no API keys needed for public data. Every deploy picks up whatever I’ve starred recently, so it stays current without me touching it.
Deployment pipeline
The deploy process is dead simple:
- Push to
masteron GitHub - Cloudflare Pages detects the push
- Runs
astro buildfollowed bypagefind --site dist - Deploys to the edge
No CI/CD config to maintain. No build servers. Cloudflare handles it all. Typical build-to-live time is under two minutes.
The site sits behind Cloudflare’s CDN, so it’s cached at edge nodes globally. For a static site with no server-side logic, this is basically free hosting with great performance.
Image handling
Astro’s built-in image optimisation is genuinely good. Drop a PNG into the assets folder, reference it in frontmatter, and the build pipeline:
- Converts to WebP
- Generates responsive sizes
- Adds proper
srcsetattributes - Handles lazy loading
The Spectre theme adds a glow effect on hero images that gives everything that nice terminal-aesthetic vibe.
One gotcha: blog images go in src/content/assets/, not src/assets/. The frontmatter path ../assets/image.png resolves relative to the post file in src/content/posts/. I’ve made this mistake more than once.
Search
Pagefind runs as a post-build step, indexing the entire dist/ output. It generates a static search index that loads on demand — no server required. Hit Ctrl+K on any page to try it.
For a static site, this is the best search solution I’ve found. Zero ongoing cost, works offline, and the index is tiny.
What’s next
A few things I want to add:
- RSS feed — so people can subscribe
- Dark/light toggle — though honestly, dark mode is the only mode
- More blog posts — documenting homelab projects as I go
- Resume PDF generation — currently manual, want to automate it from the MDX source
The source is public on GitHub if you want to poke around.
← Back to blog