← Back to Blog

"This Site Runs on a Bash Web Framework"

Yes, really: the site you're reading was built with bash-stack, an HTTP server and web framework written entirely in Bash. It's the kind of thing you build because it's fun and because it forces you to think about what a web framework actually needs. This post explains how it works, and what I fixed to make the blog functional.

How it works

  • File-based routing. Every route is a `.sh` file in `pages/`, `pages/index.sh` is `/`, `pages/blog.sh` is `/blog`, and `pages/blog/[slug].sh` renders individual posts. bash-stack's core (`core.sh`) parses HTTP requests in pure Bash and executes the matching page script.
  • Components. Shared bits, header, footer, intro, recent posts, projects, live in `components/` and are `source`d by the pages.
  • Markdown posts. Each blog post is a markdown file in `blog/` with YAML-ish frontmatter (`title`, `date`, `excerpt`). The page script pulls the frontmatter with `awk` and converts the body to HTML with `sed`. It's a miniature markdown engine, and it's about fifty lines.
  • Static output. A real site needs to survive GitHub Pages, so `build.sh` starts the server locally, `curl`s each route into `dist/`, copies the assets, and touches `.nojekyll`. The GitHub Actions workflow in `.github/workflows/deploy.yml` does the same thing on every push to `main`, installs `ucspi-tcp` (for `tcpserver`), runs the build, publishes `dist/` to the `gh-pages` branch.
  • The bug that had to be fixed

    The original build only pre-rendered two pages: `/` and `/blog`. Every post link pointed at `/blog/`, but no post page was ever generated, so every individual blog post 404'd. Classic.

    The fix was small: have `build.sh` discover the markdown files and pre-render each one into `dist/blog/.html`. There's also a date-sorting fix in the "recent posts" component so the list actually orders newest-first and shows real dates.

    Why bash?

    Honestly? Because it's a fun constraint, and because a framework that can't afford to be complex is a nice reminder that most of "web development" is convention, not machinery. The components, the frontmatter, the static export: it all maps 1:1 to what Jekyll or Hugo does, just with fewer moving parts.

    The framework is [cgsdev0/bash-stack](https://github.com/cgsdev0/bash-stack), give it a try if you like seeing how far shell can go.