From c78c0c9734c6e48fd86d692735b6d69ce34cea3e Mon Sep 17 00:00:00 2001 From: "Zack M. Davis" Date: Wed, 15 Jul 2026 19:06:43 -0700 Subject: [PATCH] provisioning --- provisioning/nginx_aal_month_map.conf | 40 ++++++++++ provisioning/nginx_common_expires_map.conf | 13 +++ provisioning/nginx_siteconf | 92 ++++++++++++++++++++++ provisioning/robots.txt | 3 + provisioning/root_index.html | 53 +++++++++++++ publishconf.py | 15 ++-- 6 files changed, 209 insertions(+), 7 deletions(-) create mode 100644 provisioning/nginx_aal_month_map.conf create mode 100644 provisioning/nginx_common_expires_map.conf create mode 100644 provisioning/nginx_siteconf create mode 100644 provisioning/robots.txt create mode 100644 provisioning/root_index.html diff --git a/provisioning/nginx_aal_month_map.conf b/provisioning/nginx_aal_month_map.conf new file mode 100644 index 0000000..4320306 --- /dev/null +++ b/provisioning/nginx_aal_month_map.conf @@ -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 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 new file mode 100644 index 0000000..a0b2eca --- /dev/null +++ b/provisioning/nginx_common_expires_map.conf @@ -0,0 +1,13 @@ +# 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; +} diff --git a/provisioning/nginx_siteconf b/provisioning/nginx_siteconf new file mode 100644 index 0000000..88ae4fc --- /dev/null +++ b/provisioning/nginx_siteconf @@ -0,0 +1,92 @@ +# $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{} +# block (not here -- see those files for why). + +server { + listen 80; + listen [::]:80; + + server_name zackmdavis.net www.zackmdavis.net; + + expires $expires; + + # The domain root is a small standalone landing page (plus docs/ and + # temporary/ carried over from the old NameCheap hosting) -- not part + # of the Pelican blog, which lives under /blog instead. + root /home/blogmistress/zackmdavis.net; + index index.html; + + location / { + try_files $uri $uri/ =404; + } + + location /docs { + autoindex on; + } + + location /temporary { + autoindex on; + } + + # Legacy WordPress URL compatibility, so old inbound/indexed links + # don't just 404 after the switch to Pelican. + + # feed/rss/ and feed/atom/ are real generated directories now (see + # FEED_ALL_RSS/FEED_ALL_ATOM in publishconf.py), each handled by the + # ordinary /blog/ location's index.xml fallback below -- no special + # casing needed for either. But the bare .../feed/ (WordPress's old + # single-format URL, still what existing subscribers have bookmarked) + # has nothing to fall back to now that it's just two subdirectories, + # so it needs an explicit default: RSS, matching what /feed/ used to + # mean. Covers both the site-wide and per-category feeds. + location ~ "^(.*/feed)/$" { + return 301 $1/rss/; + } + + # WordPress's permalinks were /blog/YYYY/MM/slug/ (two-digit month); + # Pelican's are /blog/YYYY/Mon/slug/ (see ARTICLE_URL in + # pelicanconf.py). A regex location takes precedence over the plain + # prefix location below regardless of ordering, so this only needs + # to exist, not to come first. + location ~ "^/blog/(\d{4})/(\d{2})/(.*)$" { + return 301 /blog/$1/$aal_month_abbrev/$3; + } + + # location /blog/ below requires the trailing slash to match (it's + # what makes the alias line up), so the bare /blog on its own would + # otherwise fall through to location / above and 404. + location = /blog { + return 301 /blog/; + } + + # The Pelican-generated blog itself. alias (not root) strips the + # /blog/ prefix so it maps onto the output directory's own top level, + # since Pelican has no idea it's being served from a subpath. + # + # index.xml as a second index fallback: feed directories (feed/, + # category/{slug}/feed/) contain only index.xml, no index.html, so + # this serves the feed directly at the bare directory URL -- + # matching WordPress's own /feed/ format, with no redirect needed -- + # while ordinary content directories are untouched since index.html + # always exists there and is tried first. + location /blog/ { + alias /home/blogmistress/An_Algorithmic_Lucidity/output/; + index index.html index.xml; + try_files $uri $uri/ =404; + } + + location /blog/source { + alias /usr/share/gitweb/; + add_header X-Robots-Tag "noindex"; + include fastcgi_params; + gzip off; + fastcgi_param SCRIPT_FILENAME /usr/share/gitweb/gitweb.cgi; + fastcgi_param GITWEB_CONFIG /etc/gitweb.conf; + fastcgi_pass unix:/run/fcgiwrap.socket; + } + + location /blog/static { # gitweb static files + alias /usr/share/gitweb/static/; + try_files $uri $uri/ =404; + } +} diff --git a/provisioning/robots.txt b/provisioning/robots.txt new file mode 100644 index 0000000..cb10b4b --- /dev/null +++ b/provisioning/robots.txt @@ -0,0 +1,3 @@ +User-Agent: * +Content-Signal: search=yes, ai-input=yes, ai-train=yes +Allow: / diff --git a/provisioning/root_index.html b/provisioning/root_index.html new file mode 100644 index 0000000..922af2a --- /dev/null +++ b/provisioning/root_index.html @@ -0,0 +1,53 @@ + + + +Zack M. Davis + + + + + + +
+

Zack M. Davis

+

my blog: An Algorithmic Lucidity

+ +

Elsewhere:
+GitHub
+

+ + + diff --git a/publishconf.py b/publishconf.py index 3704389..a6a1b34 100644 --- a/publishconf.py +++ b/publishconf.py @@ -20,13 +20,14 @@ from pelicanconf import * # things like previewing over plain HTTP before a certificate exists. SITEURL = '/blog' -# RSS (not Atom) to match the existing WordPress feed's format at -# zackmdavis.net/blog/feed/. The output path is feed/index.xml rather than -# a bare feed/ so it's a real static file; getting the URL down to exactly -# /feed/ (no filename) needs a webserver directory-index or redirect rule, -# which depends on whatever we end up hosting on. -FEED_ALL_RSS = 'feed/index.xml' -CATEGORY_FEED_RSS = 'category/{slug}/feed/index.xml' +# Both RSS and Atom, at parallel paths (.../feed/rss/ and .../feed/atom/). +# RSS keeps the WordPress-era /feed/ as its bare-directory default (an +# nginx redirect, see provisioning/nginx_siteconf) since that's what +# existing subscribers' bookmarks expect; Atom is new. +FEED_ALL_RSS = 'feed/rss/index.xml' +CATEGORY_FEED_RSS = 'category/{slug}/feed/rss/index.xml' +FEED_ALL_ATOM = 'feed/atom/index.xml' +CATEGORY_FEED_ATOM = 'category/{slug}/feed/atom/index.xml' # Feed readers fetch feed XML out of any page context, so its content # ideally wants absolute URLs -- but Pelican only uses FEED_DOMAIN for the -- 2.53.0