aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--content/articles/site-backend.md178
-rw-r--r--static/files/articles/site-backend/pablotron.org.conf.txt76
2 files changed, 254 insertions, 0 deletions
diff --git a/content/articles/site-backend.md b/content/articles/site-backend.md
new file mode 100644
index 0000000..6bfa592
--- /dev/null
+++ b/content/articles/site-backend.md
@@ -0,0 +1,178 @@
+---
+slug: "site-backend"
+title: "Site Backend"
+
+# date (optional for articles)
+date: "2023-09-08T05:07:47-04:00"
+
+# draft articles are not visible on live site
+draft: true
+
+# show on articles page
+show: true
+
+# uncomment to show table of contents
+toc: true
+---
+## Overview
+
+This site is statically generated by [Hugo][] and themed with a
+stripped-down version of [Bulma][]. Both have been heavily customized;
+see the [Configuration](#configuration) section for details.
+
+The goals of this setup are:
+
+- Size
+- Speed
+- Security
+- Mobile Support
+- Accessibility
+- Simplicity (for me)
+
+## History
+
+From 1998 to 2019 this site was generated by a custom [PHP][] backend,
+written by me. In 2019 I resurrected the site after a several year
+hiatus and migrated the site from the custom [PHP][] backend to
+[Jekyll][]. In 2021 I switched from [Jekyll][] to [Hugo][].
+
+## Content
+
+### HTML
+
+I create and edit site content with [vim][] in [Markdown][] format and
+preview the results locally with `hugo serve -D ...`. Articles and blog
+posts are saved as drafts and committed to the [Git][] repository so I
+can work on them as time permits.
+
+The content and site layout is designed with accessibility and mobile in
+mind. This means:
+
+- links, and table components have `title`, `aria-label` attributes
+- images have captions, fallback formats, `title` and `alt` attributes.
+- images scale gracefully to thumbnails on mobile
+- the site honors users' [color scheme preference][] and has a manual
+ theme override
+- The page menu bar collapes to a hamburger menu on mobile.
+
+### Images
+
+Images are created as follows:
+
+- Mathematical content is created using [Mathy][], saved as [SVG][],
+ and minified using [minify][].
+- Charts are created with [Matplotlib][], saved as [SVG][], and minified
+ using [minify][].
+- Lossless images (e.g. screenshots) are scaled and cropped with
+ [GraphicsMagick][] and served as a lossless [WebP][]
+ with a [PNG][] fallback. The fallback is compressed with
+ [pngquant][].
+- Lossy images are [GraphicsMagick][] and served as a lossy [WebP][]
+ with a [JPEG][] fallback.
+- Menubar icons are borrowed from [Bootstrap Icons][].
+- The animated site logo is generated by [this Ruby script][logo-script].
+
+### JavaScript
+
+There is almost no [JavaScript][], by design. The one script that is
+used is minimal, [deferred][], used for two things:
+
+1. to handle the [theme toggle][].
+2. to toggle the mobile site menu.
+
+## Deployment
+
+Once I am ready to apply any outstanding changes to the public web site,
+I push the outstanding commits to a remote [Git][] repository. This
+triggers a [`post-receive` hook][], which sends an authenticated `POST`
+request to a [web hook][] exposed on a TLS endpoint on the web server.
+
+The [web hook][] runs a [deployment script (`deploy.rb`)][] which does
+the following:
+
+1. Verifies the authenticated timestamp (to prevent replay attacks).
+2. Clones the upstream repository.
+3. Executes [Hugo][] (`hugo --minify -d ...`) to build the site minified
+ in a unique output directory.
+4. Updates the `htdocs` symlink for the public web site to point at
+ the output directory from the previous step.
+5. Removes any stale builds.
+
+## Configuration
+
+This section discusses the configuration for [Hugo][], [Bulma][] and
+[Apache][].
+
+### Hugo Configuration
+
+[Hugo][] is configured to use [Chroma syntax higlighting][] with inline
+styles disabled (e.g., `class` attributes only, no `style`) in order to
+support the restrictive `Content-Security-Policy` header (see "HTTP
+Headers").
+
+The formatted tables in the pages site are generated via [my
+`hugo-shortcode-table` shortcode][], because the native table generator
+for [Hugo][] uses inline styles.
+
+I have also written a couple of custom [shortcodes][] to generate
+`<picture>` and `<figure>` elements in order to support [progressive
+enhancement][].
+
+The generated [HTML][] has been modified to:
+
+- add support `go-import`
+- add a [Mastodon][] `<link rel='me' ...>` tag.
+- remove all unnecessary tags
+- to combine and [minify][] and [JavaScript][] and [CSS][] assets.
+- to add `integrity` attributes to `<link>` and `<script>` tags.
+
+### Bulma Configuration
+
+**TODO:**
+
+- bulma modified to remove all unnecessary components
+ - show `style.css`
+- added chroma styles
+- added dark mode
+
+### Apache Configuration
+
+**TODO:**
+
+- security headers (see next section)
+- `static/files/articles/site-backend/pablotron.org.conf.txt` (config w/ garbage removed)
+- mod deflate
+- mod rewrite for old links
+- aggressive caching
+- http2
+- letsencrypt
+- tls config (1.2 or newer, remove garbage algos)
+
+## HTTP Security Headers
+
+TODO
+
+## Validation
+
+I periodically verify the following manually:
+
+- Developer console: Page load time, cached and uncached page size.
+- [Lighthouse][]: Accessibility, desktop score, and mobile score.
+- security headers
+- tls configuration
+- manual verification in the desktop and mobile versions of chrome and
+ firefox
+
+## Other
+
+- content served minified, cached, and compressed.
+(more stuff from `TODO.md`)
+
+```apache
+# TODO: include annotated files/articles/site-backend/pablotron.org.conf.txt
+```
+
+[hugo]: https://gohugo.io/
+ "Hugo static site generator."
+[bulma]: https://bulma.io/
+ "Bulma minimal CSS framework."
diff --git a/static/files/articles/site-backend/pablotron.org.conf.txt b/static/files/articles/site-backend/pablotron.org.conf.txt
new file mode 100644
index 0000000..8934bad
--- /dev/null
+++ b/static/files/articles/site-backend/pablotron.org.conf.txt
@@ -0,0 +1,76 @@
+<VirtualHost *:80>
+ Use BASIC_SITE pablotron.org www-admin@pablotron.org
+ Use BASIC_LOGS pablotron.org
+ Use STRIP_WWW https://pablotron.org
+ Use MOD_DEFLATE
+
+ # unconditionally rewrite to https://pablotron.org
+ RewriteEngine On
+ RewriteRule ^/(.*)$ https://pablotron.org/$1 [R,L]
+</VirtualHost>
+
+<VirtualHost *:443>
+ Use BASIC_SITE pablotron.org www-admin@pablotron.org
+ Use BASIC_LOGS pablotron.org
+ Use STRIP_WWW https://pablotron.org
+ Use MOD_DEFLATE
+
+ SSLEngine on
+ SSLCertificateFile /etc/letsencrypt/live/pablotron.org/cert.pem
+ SSLCertificateKeyFile /etc/letsencrypt/live/pablotron.org/privkey.pem
+ SSLCertificateChainFile /etc/letsencrypt/live/pablotron.org/fullchain.pem
+
+ # redirect old rss feed to new one
+ RewriteCond %{QUERY_STRING} theme=rss
+ RewriteCond %{REQUEST_URI} ^/$
+ RewriteRule (.*) /index.xml [R=301,L]
+
+ # enable http2 (added 2022-01-29)
+ Protocols h2 http/1.1
+
+ # set security headers
+ # (added on 2021-10-17)
+ #
+ # refs:
+ # - https://web.dev/security-headers/#xfo
+ # - https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
+ # - https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
+ # - https://scotthelme.co.uk/a-new-security-header-referrer-policy/
+ # - https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy
+ # - https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
+ #
+ # permissions-policy docs (seems poorly thought out):
+ # * https://scotthelme.co.uk/goodbye-feature-policy-and-hello-permissions-policy/
+ # * feature list (for old feature-policy header, but a good reference): https://source.chromium.org/chromium/chromium/src/+/master:third_party/blink/renderer/platform/feature_policy/feature_policy.cc;drc=ab90b51c5b60de15054a32b0bd18e4839536a1c9;l=138
+ # https://github.com/w3c/webappsec-permissions-policy/blob/main/permissions-policy-explainer.md
+ #
+ Header append "Strict-Transport-Security" "max-age=31536000"
+ Header append "X-Frame-Options" "SAMEORIGIN"
+ Header append "X-Content-Type-Options" "nosniff"
+ Header append "Cross-Origin-Opener-Policy" "same-origin"
+ Header append "Cross-Origin-Resource-Policy" "same-origin"
+ Header append "Access-Control-Allow-Origin" "https://pablotron.org"
+ Header append "Referrer-Policy" "strict-origin-when-cross-origin"
+
+ # not sure about these yet
+ Header append "Permissions-Policy" "camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), midi=(), payment=(), usb=()"
+
+ # POST needed for /hooks
+ Header append "Access-Control-Allow-Methods" "POST, GET, HEAD, OPTIONS"
+
+ # 'unsafe-inline' is needed for goldmark table cell alignment
+ # Header append "Content-Security-Policy" "default-src 'self'; img-src 'self' https://pmdn.org; style-src 'self' 'unsafe-inline'"
+ # removed all tables w/ alignment, so i nuked unsafe-inline (2021-10-21)
+ Header append "Content-Security-Policy" "default-src 'self'; img-src 'self' https://pmdn.org"
+
+ # cache images, stylesheets, and javascript for 1 year
+ # (added 2022-01-29, i may regret this...)
+ <FilesMatch "\.(ico|jpg|jpeg|png|gif|webp|svg|js|json|css)$">
+ Header set Cache-Control "max-age=31536000, public"
+ </FilesMatch>
+
+ <Location /hooks/>
+ ProxyPass "http://localhost:9000/"
+ ProxyPassReverse "http://localhost:9000/"
+ </Location>
+</VirtualHost>