License: CC-BY-NC-SA-4.0Status: DraftLast edit: 2026-02-05

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 env builds a Guix containerised development environment.
  • make start launches the server locally (default port 3000).

Production:

  • make dist produces a single self-contained executable _dist/website that embeds all publications and runs in a minimal Guix environment.
  • make deploy builds 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.

Bibliography

[1]
The GNU Project, Gnu guix. (2025). Available: https://guix.gnu.org/
NO_ITEM_DATA:guix_8fb8
NO_ITEM_DATA:guile
NO_ITEM_DATA:sussman_flexible
NO_ITEM_DATA:graydon_text