aboutsummaryrefslogtreecommitdiff
path: root/blog/content/notes
diff options
context:
space:
mode:
authoralex <alex@pdp7.net>2026-09-16 13:52:25 +0200
committeralex <alex@pdp7.net>2026-09-16 13:55:38 +0200
commit790757eb1a8e6db409f7bd5b9cf543fbfb51eb37 (patch)
tree47e0ebb73ac1c29fd8d66b548ea46d367c6d16a2 /blog/content/notes
parent54e4f3dae54ee1276a9c8a9a3598ea2b51bb0894 (diff)
Add notes/tech/how-this-site-works
Diffstat (limited to 'blog/content/notes')
-rw-r--r--blog/content/notes/index.gmi2
-rw-r--r--blog/content/notes/tech/how-this-site-works.gmi60
2 files changed, 62 insertions, 0 deletions
diff --git a/blog/content/notes/index.gmi b/blog/content/notes/index.gmi
index c2090865..95933044 100644
--- a/blog/content/notes/index.gmi
+++ b/blog/content/notes/index.gmi
@@ -15,6 +15,8 @@ Notes about some books and long articles I like:
## Tech
+=> tech/how-this-site-works How this site works
+
=> tech/misc-linux-stuff Misc Linux stuff
=> tech/running-commands-in-linux Running commands in Linux
=> tech/ssh-for-beginners SSH for beginners
diff --git a/blog/content/notes/tech/how-this-site-works.gmi b/blog/content/notes/tech/how-this-site-works.gmi
new file mode 100644
index 00000000..9d99b96e
--- /dev/null
+++ b/blog/content/notes/tech/how-this-site-works.gmi
@@ -0,0 +1,60 @@
+# How this site works
+
+## The use of gemtext
+
+This site is composed of many gemtext files following the structure of the site.
+
+Gemtext is the native response format of the Gemini protocol. Gemtext is much simpler and constrained than Markdown. Gemtext has only:
+
+* Three levels of headers
+* Links as full lines, no inline links
+* Single-level lists and quotes
+* Preformatted blocks
+
+Gemtext can be parsed with only a single state flag (whether you are in preformatted block or not) and use only simple text parsing operations.
+
+This means that a full correct gemtext parser can be code in a few hundred lines in code in a few hours. Additionally, gemtext constraints your content to the bare minimum. Additionally, unlike HTML files that have a complex hierarchical structure, gemtext files can for example be combined by plain text file concatenation; for example you can concatenate a header, body, and footer with the cat command.
+
+The Gemini protocol suite of protocols also describes a way to derive a feed from a gemtext page. Links in a gemtext page whose link text starts with a YYYY-MM-DD timestamp form an implicit feed. Contrary to traditional feed formats like RSS and Atom, gemtext implicit feeds are easy to create with a plain text editor.
+
+## Static site generation
+
+As a first step, a process converts every foo/bar.gmi file to a foo/bar.html HTML file.
+
+=> https://github.com/alexpdp7/coppewebite/tree/main/gemini-to-web This is done with the coppewebite-to-html command part of my coppewebite suite of Gemini tools.
+
+Then, the root index.gmi is generated. The header is a static gemtext snippet. Then, coppewebite-indexer generates a series of links in chronological order to the articles in YYYY/MM/article.gmi files that follows the header.
+
+The series of links is an implicit gemtext feed, that the coppewebite-to-rss tool converts to RSS. index.gmi and index.rss both have an implicit gemtext feed and an RSS feed. Using coppewebite-to-html again, index.gmi is converted to index.html, that contains metadata pointing to index.rss.
+
+The result is a directory with .html, .gmi, and .rss files, including index.html, index.rss, index.gmi, but also notes/tech/how-this-site.works.html and .gmi.
+
+## Serving the static site
+
+Apache httpd is the main web server for this site.
+
+The directory that contains the static site has the MultiViews option enabled. This means that when serving foo/bar, Apache serves foo/bar.html or foo/bar.gmi depending on the Accept header of the request.
+
+For web browsers, which send text/html as their Accept header, the .html file is served. However, you can append .gmi to the URL to request the gemtext version.
+
+Interestingly, when the request does not have an Accept header that selects a unique file, Apache replies with the smallest file, which frequently is the gemtext version. When using curl in a terminal, Apache replies with the gemtext version, which is nicer to read on a terminal.
+
+=> https://github.com/alexpdp7/coppewebite/tree/main/gemini-from-http gemini-from-http from my coppewebite suite is the Gemini server.
+
+gemini-to-http serves all Gemini requests by making an equivalent HTTP request to a web server running on the same host with a text/gemini Accept header. Therefore, when requesting gemini://alex.corcoles.net/foo this queries Apache for https://alex.corcoles.net/foo who returns foo.gmi that is proxied back to the Gemini client.
+
+## Publishing the site
+
+The site is part of a Git repository. The server hosting this site has this Git repository.
+
+=> https://github.com/alexpdp7/alexpdp7/blob/master/blog/post-receive The Git repository on the server has a post-receive hook that runs the site build script and stores the result in the Apache document root for the site.
+
+## Observations
+
+I think this is a pretty optimal system to host a dual HTTP/HTML + Gemini/gemtext site. The coppewebite suite is less than 700 lines of Python code that only depends on two HTML libraries and an RSS library. The site-specific code are two shell scripts totalling less than 100 lines of shell script.
+
+(And if instead of using the indexer to generate the list of blog entries in the front page you maintain such list by hand, you can eliminate a significant amount of code.)
+
+I believe the tools I use enable anyone to publish a site by using only a plain text editor and requiring much less knowledge about web technologies than using regular HTML (especially for the feeds).
+
+I would like to package all of this in a way that enables anyone to create sites with little effort.