]> zackmdavis.net Git - An_Algorithmic_Lucidity.git/commitdiff
support Markdown content negotiation (and consolidate conf.d file convention)
authorZack M. Davis <code@zackmdavis.net>
Wed, 22 Jul 2026 03:26:50 +0000 (20:26 -0700)
committerZack M. Davis <code@zackmdavis.net>
Wed, 22 Jul 2026 03:26:50 +0000 (20:26 -0700)
provisioning/conf.d/aal_month_map.conf [new file with mode: 0644]
provisioning/conf.d/common_expires_map.conf [new file with mode: 0644]
provisioning/conf.d/markdown_negotiation_map.conf [new file with mode: 0644]
provisioning/nginx_aal_month_map.conf [deleted file]
provisioning/nginx_common_expires_map.conf [deleted file]
provisioning/nginx_siteconf

diff --git a/provisioning/conf.d/aal_month_map.conf b/provisioning/conf.d/aal_month_map.conf
new file mode 100644 (file)
index 0000000..6ce64ae
--- /dev/null
@@ -0,0 +1,40 @@
+# Translates the old WordPress site's two-digit month URLs
+# (/blog/2011/12/some-post/) onto Pelican's %b abbreviation
+# (/blog/2011/Dec/some-post/), matching ARTICLE_URL / MONTH_ARCHIVE_SAVE_AS
+# in pelicanconf.py. Referenced from the "location ~ ^/blog/..." redirect
+# block in nginx_siteconf.
+#
+# This is an aAL-specific legacy-URL concern (WordPress's permalink
+# structure), not a generally-shared one like common_expires_map.conf,
+# so the map name is namespaced ($aal_month_abbrev) rather than generic --
+# no reason another blog sharing this server would need an identically-named
+# map, but no reason to risk a collision either.
+#
+# Included once from nginx.conf's http{} block (map directives can't live
+# inside a server{} block).
+#
+# Keyed on $2 (the location regex's second capture group in nginx_siteconf),
+# not a named capture -- conf.d/*.conf loads before sites-enabled/* in
+# nginx.conf, so at the point this map is parsed, nginx doesn't yet know
+# about a named capture a later location block would define. $1-$9 are
+# built-in nginx variables, always predeclared, so they don't have that
+# ordering problem.
+map $2 $aal_month_abbrev {
+    # Passes unrecognized input through unchanged, so a URL with a
+    # malformed month degrades to an ordinary 404 rather than a redirect to
+    # a broken location.
+    default $2;
+
+    01 Jan;
+    02 Feb;
+    03 Mar;
+    04 Apr;
+    05 May;
+    06 Jun;
+    07 Jul;
+    08 Aug;
+    09 Sep;
+    10 Oct;
+    11 Nov;
+    12 Dec;
+}
diff --git a/provisioning/conf.d/common_expires_map.conf b/provisioning/conf.d/common_expires_map.conf
new file mode 100644 (file)
index 0000000..de18dc8
--- /dev/null
@@ -0,0 +1,14 @@
+# Shared across all sites on a box (nginx errors on a duplicate `map` name
+# within the same http{} context) -- included once, from nginx.conf's http{}
+# block, not from any individual site's config. Kept as an identical copy in
+# each blog's own provisioning/conf.d/ so each repo stays independently
+# rebuildable; only one of those copies is the one actually `include`d on a
+# given server.
+#
+# Forces HTML responses to always revalidate (since a post's URL stays the
+# same across edits/redeploys, so a cached page could otherwise go stale
+# silently) while leaving normal caching behavior for everything else.
+map $sent_http_content_type $expires {
+    default                    off;
+    text/html                  epoch;
+}
diff --git a/provisioning/conf.d/markdown_negotiation_map.conf b/provisioning/conf.d/markdown_negotiation_map.conf
new file mode 100644 (file)
index 0000000..70048f9
--- /dev/null
@@ -0,0 +1,40 @@
+# Supports the Markdown-alternative content negotiation in the "location
+# /blog/" block of nginx_siteconf: if a client's Accept header asks for
+# text/markdown (or text/plain) and a page has a sibling .md mirror (see
+# _prepare_markdown_mirrors/_write_markdown_mirrors in pelicanconf.py), serve
+# that instead of the compiled HTML. Prior art: gwern.net does the same
+# thing for the same reason (LLM-agent support) --
+# <https://github.com/gwern/gwern.net/commit/79ded21772a9aa338158c16a19dd4dad5a8f3d6b>.
+#
+# This is an aAL-specific concern, not a generally-shared one like
+# common_expires_map.conf, so map names are namespaced ($aal_...) rather
+# than generic.
+#
+# Included once from nginx.conf's http{} block (map directives can't live
+# inside a server{} block).
+
+# Article URLs are directories (ARTICLE_URL ends in "/" -- see
+# pelicanconf.py), but a page's markdown_url is its directory's *sibling*
+# with no trailing slash (dirname(save_as) + '.md'), so the trailing slash
+# has to come off before appending ".md". Static-asset URLs (no trailing
+# slash to begin with) pass through unchanged.
+map $uri $aal_uri_sans_trailing_slash {
+    "~^(?<base>.*)/$" $base;
+    default                $uri;
+}
+
+# gwern.net's version uses `if`, which requires unrolling since nginx
+# disallows nested `if`s inside a location. We can dodge `if` (and the
+# well-known "IfIsEvil" footguns that come with mixing it into
+# try_files-driven logic) entirely: fold "does the client want markdown" into
+# a string that's either ".md" or empty, and let try_files' own
+# first-candidate-that-exists-wins semantics (already relied on elsewhere in
+# nginx_siteconf) do the branching. When a client doesn't ask for markdown,
+# this suffix is empty and the resulting candidate is byte-for-byte identical
+# to the plain $uri candidate already tried today -- so behavior for
+# ordinary browser traffic is provably unchanged.
+map $http_accept $aal_wants_markdown_suffix {
+    default                 "";
+    "~*text/markdown"       ".md";
+    "~*text/plain"          ".md";
+}
diff --git a/provisioning/nginx_aal_month_map.conf b/provisioning/nginx_aal_month_map.conf
deleted file mode 100644 (file)
index 4320306..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-# Translates the old WordPress site's two-digit month URLs
-# (/blog/2011/12/some-post/) onto Pelican's %b abbreviation
-# (/blog/2011/Dec/some-post/), matching ARTICLE_URL / MONTH_ARCHIVE_SAVE_AS
-# in pelicanconf.py. Referenced from the "location ~ ^/blog/..." redirect
-# block in nginx_siteconf.
-#
-# This is an aAL-specific legacy-URL concern (WordPress's permalink
-# structure), not a generally-shared one like nginx_common_expires_map.conf,
-# so the map name is namespaced ($aal_month_abbrev) rather than generic --
-# no reason another blog sharing this server would need an identically-named
-# map, but no reason to risk a collision either.
-#
-# Included once from nginx.conf's http{} block (map directives can't live
-# inside a server{} block).
-#
-# Keyed on $2 (the location regex's second capture group in nginx_siteconf),
-# not a named capture -- conf.d/*.conf loads before sites-enabled/* in
-# nginx.conf, so at the point this map is parsed, nginx doesn't yet know
-# about a named capture a later location block would define. $1-$9 are
-# built-in nginx variables, always predeclared, so they don't have that
-# ordering problem.
-map $2 $aal_month_abbrev {
-    # Passes unrecognized input through unchanged, so a URL with a
-    # malformed month degrades to an ordinary 404 rather than a redirect to
-    # a broken location.
-    default $2;
-
-    01 Jan;
-    02 Feb;
-    03 Mar;
-    04 Apr;
-    05 May;
-    06 Jun;
-    07 Jul;
-    08 Aug;
-    09 Sep;
-    10 Oct;
-    11 Nov;
-    12 Dec;
-}
diff --git a/provisioning/nginx_common_expires_map.conf b/provisioning/nginx_common_expires_map.conf
deleted file mode 100644 (file)
index a0b2eca..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-# Shared across all sites on a box (nginx errors on a duplicate `map` name
-# within the same http{} context) -- included once, from nginx.conf's http{}
-# block, not from any individual site's config. Kept as an identical copy in
-# each blog's own provisioning/ so each repo stays independently rebuildable;
-# only one of those copies is the one actually `include`d on a given server.
-#
-# Forces HTML responses to always revalidate (since a post's URL stays the
-# same across edits/redeploys, so a cached page could otherwise go stale
-# silently) while leaving normal caching behavior for everything else.
-map $sent_http_content_type $expires {
-    default                    off;
-    text/html                  epoch;
-}
index 494c505448cd14745abf78aa1d5c7d951bf0de63..190ae54a6cc2bb7b041aaa6b665a2af638d3e42c 100644 (file)
@@ -1,5 +1,5 @@
-# $expires is defined by nginx_common_expires_map.conf, and $aal_month_abbrev
-# by nginx_aal_month_map.conf, both included once from nginx.conf's http{}
+# $expires is defined by conf.d/common_expires_map.conf, and $aal_month_abbrev
+# by conf.d/aal_month_map.conf, both included once from nginx.conf's http{}
 # block (not here -- see those files for why).
 #
 # All of the redirects below are 302 (not 301) for now, deliberately: we're
@@ -104,7 +104,40 @@ server {
         location /blog/ {
             alias /home/blogmistress/An_Algorithmic_Lucidity/output/;
             index index.html index.xml;
-            try_files $uri $uri/ =404;
+
+            # .md isn't in nginx's default mime.types, so it's currently
+            # served as application/octet-stream (forcing a download prompt
+            # instead of an inline view). Fix belongs in mime.types itself
+            # (one line, `text/markdown md;`, inside its existing `types {}`
+            # block) rather than a location-scoped default_type override:
+            # default_type is a last-resort fallback for the whole location,
+            # so overriding it here would silently relabel every OTHER
+            # currently-or-future unrecognized extension served from
+            # /blog/ (e.g. llms.txt, from _write_llms_txt in
+            # pelicanconf.py) as text/markdown too, not just .md files.
+            # mime.types is OS-managed, not part of this repo, so this edit
+            # has to happen directly on the server.
+
+            # See conf.d/markdown_negotiation_map.conf for
+            # $aal_uri_sans_trailing_slash and $aal_wants_markdown_suffix.
+            #
+            # This candidate MUST come before plain $uri, not after: for any
+            # article URL (always directory-shaped, trailing slash and all --
+            # see ARTICLE_URL in pelicanconf.py), $uri checks as an existing
+            # *directory* (try_files treats a trailing slash as "check
+            # directory existence") and that directory always exists, so
+            # $uri would win the match immediately, every time, if tried
+            # first -- and try_files stops at the first match, with no way
+            # to keep looking for something better. Putting the markdown
+            # candidate first is what gives it a chance to fire at all.
+            #
+            # When a client doesn't ask for markdown, this first candidate
+            # has no trailing slash, so it's checked as a *file* instead --
+            # which a directory URL never is, so it harmlessly falls through
+            # to the plain $uri/$uri/ pair below, unchanged from before this
+            # feature existed. (For non-directory URLs, e.g. static assets,
+            # it collapses to a literal duplicate of $uri -- also harmless.)
+            try_files $aal_uri_sans_trailing_slash$aal_wants_markdown_suffix $uri $uri/ =404;
         }
 
         location /blog/source {