Designing This Website
Introduction
The Guix package manager[1] is a handy tool for building reproducible development environments. It allows team members to work within the same context, avoiding inconsistencies. As a deployment tool, it ensures that exactly what is shipped is known, reducing security risksNO_ITEM_DATA:guix_8fb8. To use Guix effectively, one must understand some Guile SchemeNO_ITEM_DATA:guile. This article documents the design and implementation of a simple personal website written entirely in Guile Scheme.
Objective
The software is considered successful if:
- It is written in Guile Scheme.
- Writing and publishing content is efficient.
- Some content is protected by authentication.
- Content is legible on desktop and mobile.
- The software is flexibleNO_ITEM_DATA:sussman_flexible.
Software
The implementation is available at: https://github.com/phf-1/website/tree/master
Writing Content Efficiently
Website content consists of publications, each identified by a UUID. A publication comprises Org Mode source files, a layout template, optional custom CSS and JavaScript, and associated resources (images, fonts, PDFs, etc.). To create a publication, just copy/paste an existing publication and update its identifier. Most of the content creation happens in the org file i.e. it is like writing an email. For completeness, here is a publication structure:
library/<uuid>/
├── layout.html
├── org/
│ ├── 1.org
│ └── 2.org ; optional additional parts
├── css/ ; optional
│ └── 1.css
├── js/ ; optional
│ └── 1.js
└── data/ ; optional resources
├── portrait.jpeg
└── source-sans-3-regular.woff2
Org Mode source is exported to HTML body content via Emacs batch mode. The body is
inserted into the publication’s layout template, with optional CSS and JS injected.
This workflow makes content creation extremely efficient. As others have said:
“always bet on text.”NO_ITEM_DATA:graydon_text. An index publication listing all articles
is generated automatically. The home page (UUID 00000000-0000-0000-0000-000000000000)
contains shared fonts and styles.
Publishing Content Efficiently
Development:
make envbuilds a Guix containerised development environment.make startlaunches the server locally (default port 3000).
Production:
make distproduces a single self-contained executable_dist/websitethat embeds all publications and runs in a minimal Guix environment.make deploybuilds the executable, copies it to the VPS via rsync, and installs a systemd service. Deployment completes in seconds.
Legibility on Desktop and Mobile
The design is intentionally minimal. If you have suggestions to improve legibility, feel free to contact me.
Private and Public Content
The original objective included lightweight Basic Authentication for some content. This feature is not yet implemented; currently all publications are public. Authentication remains a planned improvement.
Software Flexibility
As stated in Software Design for FlexibilityNO_ITEM_DATA:sussman_flexible:
A software system is flexible if it can be easily adapted to new requirements.
A proven approach is:
Mix and match parts that can be combined with combinators and generalized with wrappers.
The implementation uses message-passing procedures (an actor-like model, see: Toward an actor implementation). Each major component — Parser, Publication, Library, Server — is a procedure that accepts keyword-led messages and returns results or new behaviour. When requirements change, we can:
- Rewire the composition of components,
- Teach components new messages,
- Add new components,
- Or combine the above.
The program flow today:
1) NGINX (on the VPS) terminates TLS and forwards to the Guile server on localhost.
2) Browser sends HTTP request.
3) Guile web server receives request.
4) Server component parses the URI path.
5) Special cases:
- / → redirect to home publication
- /articles → redirect to auto-generated index
- /health → return JSON {"health":"ok"}
6) For /<uuid>/html → export Org → compose with layout → return HTML
7) For /<uuid>/<filename> → serve binary resource from data/
8) Otherwise → 404
Early in development, adding a status field to publications required only a few lines of change and minutes of work. Subsequent evolutions — multiple Org files per publication, embedded fonts, self-contained distribution, automated index — were all accommodated with localised modifications, confirming the flexibility objective so far.
Result
The implementation meets most objectives:
- Pure Guile Scheme
- Efficient writing (Org Mode) and publishing (single-command deploy)
- Legible minimal design
- Demonstrated flexibility via the message-passing architecture
Authentication remains pending. The self-contained executable and streamlined deployment make the site practical for real use.
Conclusion
We have a functional personal website written in Guile Scheme, leveraging Guix for reproducibility, Org Mode and Emacs for efficient authoring, and a lightweight message-passing design for flexibility. Further refinements are planned, particularly authentication and aesthetic improvements, but the core objectives have been achieved.